2 * @file sipe-cert-crypto-nss.c
6 * Copyright (C) 2011-2012 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Certificate routines implementation based on NSS.
38 * Work around a compiler error in NSS 3.13.x. Let's hope they fix it for
39 * 3.14.x. See also: https://bugzilla.mozilla.org/show_bug.cgi?id=702090
42 #if (NSS_VMAJOR == 3) && (NSS_VMINOR == 13)
43 #define __GNUC_MINOR __GNUC_MINOR__
51 #include "sipe-backend.h"
52 #include "sipe-cert-crypto.h"
54 struct sipe_cert_crypto
{
55 SECKEYPrivateKey
*private;
56 SECKEYPublicKey
*public;
60 * This data structure is used in two different modes
62 * a) certificate generated by the server from our Certificate Request
64 * key_pair.private - reference to client private key, don't free!
65 * key_pair.public - reference to client public key, don't free!
66 * decoded - certificate as NSS data structure, must be freed
67 * raw - certificate as DER encoded binary, must be freed
68 * length - length of DER binary
70 * b) server certificate
72 * key_pair.private - NULL
73 * key_pair.public - reference to server public key, must be freed!
74 * decoded - certificate as NSS data structure, must be freed
76 * length - modulus length of server public key
78 struct certificate_nss
{
79 struct sipe_cert_crypto key_pair
;
80 CERTCertificate
*decoded
;
85 struct sipe_cert_crypto
*sipe_cert_crypto_init(void)
87 PK11SlotInfo
*slot
= PK11_GetInternalKeySlot();
90 PK11RSAGenParams rsaParams
;
91 struct sipe_cert_crypto
*scc
= g_new0(struct sipe_cert_crypto
, 1);
93 /* RSA parameters - should those be configurable? */
96 * valgrind makes key pair generation extremely slow. At least
97 * on my system it takes longer for the default key size than
98 * the SIP server timeout and our next message will fail with
100 * Read error: Connection reset by peer (104)
102 * Let's reduce the key size when we detect valgrind.
104 if (RUNNING_ON_VALGRIND
) {
105 rsaParams
.keySizeInBits
= 1024;
106 SIPE_DEBUG_INFO("sipe_cert_crypto_init: running on valgrind, reducing RSA key size to %d bits",
107 rsaParams
.keySizeInBits
);
110 rsaParams
.keySizeInBits
= 2048;
111 rsaParams
.pe
= 65537;
113 SIPE_DEBUG_INFO_NOFORMAT("sipe_cert_crypto_init: generate key pair, this might take a while...");
114 scc
->private = PK11_GenerateKeyPair(slot
,
115 CKM_RSA_PKCS_KEY_PAIR_GEN
,
118 PR_FALSE
, /* not permanent */
119 PR_TRUE
, /* sensitive */
122 SIPE_DEBUG_INFO_NOFORMAT("sipe_cert_crypto_init: key pair generated");
127 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_init: key generation failed");
135 void sipe_cert_crypto_free(struct sipe_cert_crypto
*scc
)
139 SECKEY_DestroyPublicKey(scc
->public);
141 SECKEY_DestroyPrivateKey(scc
->private);
146 static gchar
*sign_cert_or_certreq(CERTCertificate
*cert
,
147 CERTCertificateRequest
*certreq
,
148 SECKEYPrivateKey
*private)
150 PRArenaPool
*arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
151 gchar
*base64
= NULL
;
154 SECItem
*encoding
= SEC_ASN1EncodeItem(arena
,
160 SEC_ASN1_GET(CERT_CertificateTemplate
) :
161 SEC_ASN1_GET(CERT_CertificateRequestTemplate
));
164 SECOidTag signtag
= SEC_GetSignatureAlgorithmOidTag(private->keyType
,
167 if (signtag
!= SEC_OID_UNKNOWN
) {
170 if (!SEC_DerSignData(arena
,
177 SIPE_DEBUG_INFO_NOFORMAT("sign_cert_or_certreq: successfully signed");
178 base64
= g_base64_encode(raw
.data
, raw
.len
);
181 SIPE_DEBUG_ERROR_NOFORMAT("sign_cert_or_certreq: signing failed");
184 SIPE_DEBUG_ERROR_NOFORMAT("sign_cert_or_certreq: can't find signature algorithm");
187 /* all memory allocated from "arena"
188 SECITEM_FreeItem(encoding, PR_TRUE); */
190 SIPE_DEBUG_ERROR_NOFORMAT("sign_cert_or_certreq: can't ASN.1 encode data");
193 PORT_FreeArena(arena
, PR_TRUE
);
195 SIPE_DEBUG_ERROR_NOFORMAT("sign_cert_or_certreq: can't allocate memory");
201 static CERTCertificateRequest
*generate_request(struct sipe_cert_crypto
*scc
,
202 const gchar
*subject
)
205 CERTCertificateRequest
*certreq
= NULL
;
207 if (!scc
|| !subject
)
210 pkd
= SECKEY_EncodeDERSubjectPublicKeyInfo(scc
->public);
212 CERTSubjectPublicKeyInfo
*spki
= SECKEY_DecodeDERSubjectPublicKeyInfo(pkd
);
215 gchar
*cn
= g_strdup_printf("CN=%s", subject
);
216 CERTName
*name
= CERT_AsciiToName(cn
);
220 certreq
= CERT_CreateCertificateRequest(name
,
224 SIPE_DEBUG_ERROR_NOFORMAT("generate_request: certreq creation failed");
227 CERT_DestroyName(name
);
229 SIPE_DEBUG_ERROR_NOFORMAT("generate_request: subject name creation failed");
232 SECKEY_DestroySubjectPublicKeyInfo(spki
);
234 SIPE_DEBUG_ERROR_NOFORMAT("generate_request: DER decode public key info failed");
237 SECITEM_FreeItem(pkd
, PR_TRUE
);
239 SIPE_DEBUG_ERROR_NOFORMAT("generate_request: DER encode failed");
245 gchar
*sipe_cert_crypto_request(struct sipe_cert_crypto
*scc
,
246 const gchar
*subject
)
248 gchar
*base64
= NULL
;
249 CERTCertificateRequest
*certreq
= generate_request(scc
, subject
);
252 base64
= sign_cert_or_certreq(NULL
, certreq
, scc
->private);
253 CERT_DestroyCertificateRequest(certreq
);
259 void sipe_cert_crypto_destroy(gpointer certificate
)
261 struct certificate_nss
*cn
= certificate
;
264 /* imported server certificate - mode (b) */
265 if (!cn
->raw
&& cn
->key_pair
.public)
266 SECKEY_DestroyPublicKey(cn
->key_pair
.public);
268 CERT_DestroyCertificate(cn
->decoded
);
274 /* generates certificate_nss in mode (a) */
275 gpointer
sipe_cert_crypto_decode(struct sipe_cert_crypto
*scc
,
278 struct certificate_nss
*cn
= g_new0(struct certificate_nss
, 1);
280 cn
->raw
= g_base64_decode(base64
, &cn
->length
);
281 cn
->decoded
= CERT_DecodeCertFromPackage((char *) cn
->raw
, cn
->length
);
284 sipe_cert_crypto_destroy(cn
);
293 /* generates certificate_nss in mode (b) */
294 gpointer
sipe_cert_crypto_import(const guchar
*raw
,
297 struct certificate_nss
*cn
= g_new0(struct certificate_nss
, 1);
299 /* cn->raw not needed as this is a server certificate */
300 cn
->decoded
= CERT_DecodeCertFromPackage((char *) raw
, length
);
303 sipe_cert_crypto_destroy(cn
);
307 cn
->key_pair
.public = CERT_ExtractPublicKey(cn
->decoded
);
309 if (!cn
->key_pair
.public) {
310 sipe_cert_crypto_destroy(cn
);
314 cn
->length
= SECKEY_PublicKeyStrength(cn
->key_pair
.public);
319 gboolean
sipe_cert_crypto_valid(gpointer certificate
,
322 struct certificate_nss
*cn
= certificate
;
323 SECCertTimeValidity validity
;
328 validity
= CERT_CheckCertValidTimes(cn
->decoded
,
329 /* PRTime unit is microseconds */
330 PR_Now() + offset
* PR_USEC_PER_SEC
,
333 return((validity
== secCertTimeValid
) ||
335 * From certt.h: "validity could not be decoded from the
336 * cert, most likely because it was NULL"
338 * Let's assume if the server sends us such a certificate
339 * that it must be valid then...
341 (validity
== secCertTimeUndetermined
));
344 guint
sipe_cert_crypto_expires(gpointer certificate
)
346 struct certificate_nss
*cn
= certificate
;
347 PRTime now
, notAfter
;
350 (CERT_GetCertTimes(cn
->decoded
,
351 &now
, /* can't be NULL */
352 ¬After
) != SECSuccess
))
360 /* PRTime unit is microseconds */
361 return((notAfter
- now
) / PR_USEC_PER_SEC
);
364 gsize
sipe_cert_crypto_raw_length(gpointer certificate
)
366 return(((struct certificate_nss
*) certificate
)->length
);
369 const guchar
*sipe_cert_crypto_raw(gpointer certificate
)
371 return(((struct certificate_nss
*) certificate
)->raw
);
374 gpointer
sipe_cert_crypto_public_key(gpointer certificate
)
376 return(((struct certificate_nss
*) certificate
)->key_pair
.public);
379 gsize
sipe_cert_crypto_modulus_length(gpointer certificate
)
381 return(((struct certificate_nss
*) certificate
)->length
);
384 gpointer
sipe_cert_crypto_private_key(gpointer certificate
)
386 return(((struct certificate_nss
*) certificate
)->key_pair
.private);
389 /* Create test certificate for internal key pair (ONLY USE FOR TEST CODE!!!) */
390 gpointer
sipe_cert_crypto_test_certificate(struct sipe_cert_crypto
*scc
)
392 CERTCertificateRequest
*certreq
= generate_request(scc
, "test@test.com");
393 struct certificate_nss
*cn
= NULL
;
397 CERTName
*issuer
= CERT_AsciiToName("CN=test@test.com");
400 /* we really don't need this certificate for long... */
401 CERTValidity
*validity
= CERT_CreateValidity(PR_Now(),
402 PR_Now() + 600 * PR_USEC_PER_SEC
);
405 CERTCertificate
*certificate
= CERT_CreateCertificate(1,
411 SECOidTag signtag
= SEC_GetSignatureAlgorithmOidTag(scc
->private->keyType
,
414 if ((signtag
!= SEC_OID_UNKNOWN
) &&
415 (SECOID_SetAlgorithmID(certificate
->arena
,
416 &certificate
->signature
,
417 signtag
, 0) == SECSuccess
)) {
418 gchar
*base64
= sign_cert_or_certreq(certificate
,
423 cn
= sipe_cert_crypto_decode(scc
,
426 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: certificate decode failed");
431 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: certificate signing failed");
434 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: setting certificate signature algorithm ID failed");
437 CERT_DestroyCertificate(certificate
);
439 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: certificate creation failed");
442 CERT_DestroyValidity(validity
);
444 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: validity creation failed");
447 CERT_DestroyName(issuer
);
449 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_test_certificate: issuer name creation failed");
452 CERT_DestroyCertificateRequest(certreq
);