2 * @file sipe-cert-crypto-nss.c
6 * Copyright (C) 2011 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.
30 * Work around a compiler error in NSS 3.13.x. Let's hope they fix it for
31 * 3.14.x. See also: https://bugzilla.mozilla.org/show_bug.cgi?id=702090
34 #if (NSS_VMAJOR == 3) && (NSS_VMINOR == 13)
35 #define __GNUC_MINOR __GNUC_MINOR__
43 #include "sipe-backend.h"
44 #include "sipe-cert-crypto.h"
46 struct sipe_cert_crypto
{
47 SECKEYPrivateKey
*private;
48 SECKEYPublicKey
*public;
52 * This data structure is used in two different modes
54 * a) certificate generated by the server from our Certificate Request
56 * key_pair.private - reference to client private key, don't free!
57 * key_pair.public - reference to client public key, don't free!
58 * decoded - certificate as NSS data structure, must be freed
59 * raw - certificate as DER encoded binary, must be freed
60 * length - length of DER binary
62 * b) server certificate
64 * key_pair.private - NULL
65 * key_pair.public - reference to server public key, must be freed!
66 * decoded - certificate as NSS data structure, must be freed
68 * length - modulus length of server public key
70 struct certificate_nss
{
71 struct sipe_cert_crypto key_pair
;
72 CERTCertificate
*decoded
;
77 struct sipe_cert_crypto
*sipe_cert_crypto_init(void)
79 PK11SlotInfo
*slot
= PK11_GetInternalKeySlot();
82 PK11RSAGenParams rsaParams
;
83 struct sipe_cert_crypto
*ssc
= g_new0(struct sipe_cert_crypto
, 1);
85 /* RSA parameters - should those be configurable? */
86 rsaParams
.keySizeInBits
= 2048;
89 SIPE_DEBUG_INFO_NOFORMAT("sipe_cert_crypto_init: generate key pair, this might take a while...");
90 ssc
->private = PK11_GenerateKeyPair(slot
,
91 CKM_RSA_PKCS_KEY_PAIR_GEN
,
94 PR_FALSE
, /* not permanent */
95 PR_TRUE
, /* sensitive */
98 SIPE_DEBUG_INFO_NOFORMAT("sipe_cert_crypto_init: key pair generated");
103 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_init: key generation failed");
111 void sipe_cert_crypto_free(struct sipe_cert_crypto
*ssc
)
115 SECKEY_DestroyPublicKey(ssc
->public);
117 SECKEY_DestroyPrivateKey(ssc
->private);
122 static gchar
*sign_certreq(CERTCertificateRequest
*certreq
,
123 SECKEYPrivateKey
*private)
125 PRArenaPool
*arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
126 gchar
*base64
= NULL
;
129 SECItem
*encoding
= SEC_ASN1EncodeItem(arena
,
132 SEC_ASN1_GET(CERT_CertificateRequestTemplate
));
135 SECOidTag signtag
= SEC_GetSignatureAlgorithmOidTag(private->keyType
,
141 if (!SEC_DerSignData(arena
,
148 SIPE_DEBUG_INFO_NOFORMAT("sign_certreq: request signed successfully");
149 base64
= g_base64_encode(raw
.data
, raw
.len
);
152 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: signing failed");
155 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: can't find signature algorithm");
158 /* all memory allocated from "arena"
159 SECITEM_FreeItem(encoding, PR_TRUE); */
161 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: can't ASN.1 encode certreq");
164 PORT_FreeArena(arena
, PR_TRUE
);
166 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: can't allocate memory");
172 gchar
*sipe_cert_crypto_request(struct sipe_cert_crypto
*ssc
,
173 const gchar
*subject
)
175 gchar
*base64
= NULL
;
178 if (!ssc
|| !subject
)
181 pkd
= SECKEY_EncodeDERSubjectPublicKeyInfo(ssc
->public);
183 CERTSubjectPublicKeyInfo
*spki
= SECKEY_DecodeDERSubjectPublicKeyInfo(pkd
);
186 gchar
*cn
= g_strdup_printf("CN=%s", subject
);
187 CERTName
*name
= CERT_AsciiToName(cn
);
191 CERTCertificateRequest
*certreq
= CERT_CreateCertificateRequest(name
,
196 base64
= sign_certreq(certreq
, ssc
->private);
197 CERT_DestroyCertificateRequest(certreq
);
199 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: certreq creation failed");
202 CERT_DestroyName(name
);
204 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: subject name creation failed");
207 SECKEY_DestroySubjectPublicKeyInfo(spki
);
209 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: DER decode public key info failed");
212 SECITEM_FreeItem(pkd
, PR_TRUE
);
214 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: DER encode failed");
220 void sipe_cert_crypto_destroy(gpointer certificate
)
222 struct certificate_nss
*cn
= certificate
;
225 /* imported server certificate - mode (b) */
226 if (!cn
->raw
&& cn
->key_pair
.public)
227 SECKEY_DestroyPublicKey(cn
->key_pair
.public);
229 CERT_DestroyCertificate(cn
->decoded
);
235 /* generates certificate_nss in mode (a) */
236 gpointer
sipe_cert_crypto_decode(struct sipe_cert_crypto
*ssc
,
239 struct certificate_nss
*cn
= g_new0(struct certificate_nss
, 1);
241 cn
->raw
= g_base64_decode(base64
, &cn
->length
);
242 cn
->decoded
= CERT_DecodeCertFromPackage((char *) cn
->raw
, cn
->length
);
245 sipe_cert_crypto_destroy(cn
);
254 /* generates certificate_nss in mode (b) */
255 gpointer
sipe_cert_crypto_import(const guchar
*raw
,
258 struct certificate_nss
*cn
= g_new0(struct certificate_nss
, 1);
260 /* cn->raw not needed as this is a server certificate */
261 cn
->decoded
= CERT_DecodeCertFromPackage((char *) raw
, length
);
264 sipe_cert_crypto_destroy(cn
);
268 cn
->key_pair
.public = CERT_ExtractPublicKey(cn
->decoded
);
270 if (!cn
->key_pair
.public) {
271 sipe_cert_crypto_destroy(cn
);
275 cn
->length
= SECKEY_PublicKeyStrength(cn
->key_pair
.public);
280 gboolean
sipe_cert_crypto_valid(gpointer certificate
,
283 struct certificate_nss
*cn
= certificate
;
284 SECCertTimeValidity validity
;
289 validity
= CERT_CheckCertValidTimes(cn
->decoded
,
290 /* PRTime unit is microseconds */
291 PR_Now() + offset
* PR_USEC_PER_SEC
,
294 return((validity
== secCertTimeValid
) ||
296 * From certt.h: "validity could not be decoded from the
297 * cert, most likely because it was NULL"
299 * Let's assume if the server sends us such a certificate
300 * that it must be valid then...
302 (validity
== secCertTimeUndetermined
));
305 gsize
sipe_cert_crypto_raw_length(gpointer certificate
)
307 return(((struct certificate_nss
*) certificate
)->length
);
310 const guchar
*sipe_cert_crypto_raw(gpointer certificate
)
312 return(((struct certificate_nss
*) certificate
)->raw
);
315 gpointer
sipe_cert_crypto_public_key(gpointer certificate
)
317 return(((struct certificate_nss
*) certificate
)->key_pair
.public);
320 gsize
sipe_cert_crypto_modulus_length(gpointer certificate
)
322 return(((struct certificate_nss
*) certificate
)->length
);
325 gpointer
sipe_cert_crypto_private_key(gpointer certificate
)
327 return(((struct certificate_nss
*) certificate
)->key_pair
.private);