nss: add RSA crypto functions
[siplcs.git] / src / core / sipe-cert-crypto-nss.c
blobde16093b5f2bd6288d678c5e52ee4f3a559cae07
1 /**
2 * @file sipe-cert-crypto-nss.c
4 * pidgin-sipe
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
23 /**
24 * Certificate routines implementation based on NSS.
27 #include <glib.h>
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
33 #include "nss.h"
34 #if (NSS_VMAJOR == 3) && (NSS_VMINOR == 13)
35 #define __GNUC_MINOR __GNUC_MINOR__
36 #endif
38 #include "cert.h"
39 #include "cryptohi.h"
40 #include "keyhi.h"
41 #include "pk11pub.h"
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
67 * raw - NULL
68 * length - modulus length of server public key
70 struct certificate_nss {
71 struct sipe_cert_crypto key_pair;
72 CERTCertificate *decoded;
73 guchar *raw;
74 gsize length;
77 struct sipe_cert_crypto *sipe_cert_crypto_init(void)
79 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
81 if (slot) {
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;
87 rsaParams.pe = 65537;
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,
92 &rsaParams,
93 &ssc->public,
94 PR_FALSE, /* not permanent */
95 PR_TRUE, /* sensitive */
96 NULL);
97 if (ssc->private) {
98 SIPE_DEBUG_INFO_NOFORMAT("sipe_cert_crypto_init: key pair generated");
99 PK11_FreeSlot(slot);
100 return(ssc);
103 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_init: key generation failed");
104 g_free(ssc);
105 PK11_FreeSlot(slot);
108 return(NULL);
111 void sipe_cert_crypto_free(struct sipe_cert_crypto *ssc)
113 if (ssc) {
114 if (ssc->public)
115 SECKEY_DestroyPublicKey(ssc->public);
116 if (ssc->private)
117 SECKEY_DestroyPrivateKey(ssc->private);
118 g_free(ssc);
122 static gchar *sign_certreq(CERTCertificateRequest *certreq,
123 SECKEYPrivateKey *private)
125 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
126 gchar *base64 = NULL;
128 if (arena) {
129 SECItem *encoding = SEC_ASN1EncodeItem(arena,
130 NULL,
131 certreq,
132 SEC_ASN1_GET(CERT_CertificateRequestTemplate));
134 if (encoding) {
135 SECOidTag signtag = SEC_GetSignatureAlgorithmOidTag(private->keyType,
136 SEC_OID_UNKNOWN);
138 if (signtag) {
139 SECItem raw;
141 if (!SEC_DerSignData(arena,
142 &raw,
143 encoding->data,
144 encoding->len,
145 private,
146 signtag)) {
148 SIPE_DEBUG_INFO_NOFORMAT("sign_certreq: request signed successfully");
149 base64 = g_base64_encode(raw.data, raw.len);
151 } else {
152 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: signing failed");
154 } else {
155 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: can't find signature algorithm");
158 /* all memory allocated from "arena"
159 SECITEM_FreeItem(encoding, PR_TRUE); */
160 } else {
161 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: can't ASN.1 encode certreq");
164 PORT_FreeArena(arena, PR_TRUE);
165 } else {
166 SIPE_DEBUG_ERROR_NOFORMAT("sign_certreq: can't allocate memory");
169 return(base64);
172 gchar *sipe_cert_crypto_request(struct sipe_cert_crypto *ssc,
173 const gchar *subject)
175 gchar *base64 = NULL;
176 SECItem *pkd;
178 if (!ssc || !subject)
179 return(NULL);
181 pkd = SECKEY_EncodeDERSubjectPublicKeyInfo(ssc->public);
182 if (pkd) {
183 CERTSubjectPublicKeyInfo *spki = SECKEY_DecodeDERSubjectPublicKeyInfo(pkd);
185 if (spki) {
186 gchar *cn = g_strdup_printf("CN=%s", subject);
187 CERTName *name = CERT_AsciiToName(cn);
188 g_free(cn);
190 if (name) {
191 CERTCertificateRequest *certreq = CERT_CreateCertificateRequest(name,
192 spki,
193 NULL);
195 if (certreq) {
196 base64 = sign_certreq(certreq, ssc->private);
197 CERT_DestroyCertificateRequest(certreq);
198 } else {
199 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: certreq creation failed");
202 CERT_DestroyName(name);
203 } else {
204 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: subject name creation failed");
207 SECKEY_DestroySubjectPublicKeyInfo(spki);
208 } else {
209 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: DER decode public key info failed");
212 SECITEM_FreeItem(pkd, PR_TRUE);
213 } else {
214 SIPE_DEBUG_ERROR_NOFORMAT("sipe_cert_crypto_create: DER encode failed");
217 return(base64);
220 void sipe_cert_crypto_destroy(gpointer certificate)
222 struct certificate_nss *cn = certificate;
224 if (cn) {
225 /* imported server certificate - mode (b) */
226 if (!cn->raw && cn->key_pair.public)
227 SECKEY_DestroyPublicKey(cn->key_pair.public);
228 if (cn->decoded)
229 CERT_DestroyCertificate(cn->decoded);
230 g_free(cn->raw);
231 g_free(cn);
235 /* generates certificate_nss in mode (a) */
236 gpointer sipe_cert_crypto_decode(struct sipe_cert_crypto *ssc,
237 const gchar *base64)
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);
244 if (!cn->decoded) {
245 sipe_cert_crypto_destroy(cn);
246 return(NULL);
249 cn->key_pair = *ssc;
251 return(cn);
254 /* generates certificate_nss in mode (b) */
255 gpointer sipe_cert_crypto_import(const guchar *raw,
256 gsize length)
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);
263 if (!cn->decoded) {
264 sipe_cert_crypto_destroy(cn);
265 return(NULL);
268 cn->key_pair.public = CERT_ExtractPublicKey(cn->decoded);
270 if (!cn->key_pair.public) {
271 sipe_cert_crypto_destroy(cn);
272 return(NULL);
275 cn->length = SECKEY_PublicKeyStrength(cn->key_pair.public);
277 return(cn);
280 gboolean sipe_cert_crypto_valid(gpointer certificate,
281 guint offset)
283 struct certificate_nss *cn = certificate;
284 SECCertTimeValidity validity;
286 if (!cn)
287 return(FALSE);
289 validity = CERT_CheckCertValidTimes(cn->decoded,
290 /* PRTime unit is microseconds */
291 PR_Now() + offset * PR_USEC_PER_SEC,
292 PR_FALSE);
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);
331 Local Variables:
332 mode: c
333 c-file-style: "bsd"
334 indent-tabs-mode: t
335 tab-width: 8
336 End: