1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * Certificate handling code
7 */
8
9 #include "seccomon.h"
10 #include "secder.h"
11 #include "nssilock.h"
12 #include "lowkeyi.h"
13 #include "secasn1.h"
14 #include "secoid.h"
15 #include "secerr.h"
16 #include "pcert.h"
17
18 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
19
20 static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = {
21 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) },
22 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
23 offsetof(NSSLOWCERTSubjectPublicKeyInfo, algorithm),
24 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
25 { SEC_ASN1_BIT_STRING,
26 offsetof(NSSLOWCERTSubjectPublicKeyInfo, subjectPublicKey) },
27 { 0 }
28 };
29
30 static const SEC_ASN1Template nsslowcert_RSAPublicKeyTemplate[] = {
31 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) },
32 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.modulus) },
33 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.publicExponent) },
34 { 0 }
35 };
36 static const SEC_ASN1Template nsslowcert_DSAPublicKeyTemplate[] = {
37 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.dsa.publicValue) },
38 { 0 }
39 };
40 static const SEC_ASN1Template nsslowcert_DHPublicKeyTemplate[] = {
41 { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.dh.publicValue) },
42 { 0 }
43 };
44
45 /*
46 * See bugzilla bug 125359
47 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
48 * all of the templates above that en/decode into integers must be converted
49 * from ASN.1's signed integer type. This is done by marking either the
50 * source or destination (encoding or decoding, respectively) type as
51 * siUnsignedInteger.
52 */
53
54 static void
prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey * pubk)55 prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
56 {
57 pubk->u.rsa.modulus.type = siUnsignedInteger;
58 pubk->u.rsa.publicExponent.type = siUnsignedInteger;
59 }
60
61 static void
prepare_low_dsa_pub_key_for_asn1(NSSLOWKEYPublicKey * pubk)62 prepare_low_dsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
63 {
64 pubk->u.dsa.publicValue.type = siUnsignedInteger;
65 pubk->u.dsa.params.prime.type = siUnsignedInteger;
66 pubk->u.dsa.params.subPrime.type = siUnsignedInteger;
67 pubk->u.dsa.params.base.type = siUnsignedInteger;
68 }
69
70 static void
prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey * pubk)71 prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk)
72 {
73 pubk->u.dh.prime.type = siUnsignedInteger;
74 pubk->u.dh.base.type = siUnsignedInteger;
75 pubk->u.dh.publicValue.type = siUnsignedInteger;
76 }
77
78 /*
79 * simple cert decoder to avoid the cost of asn1 engine
80 */
81 static unsigned char *
nsslowcert_dataStart(unsigned char * buf,unsigned int length,unsigned int * data_length,PRBool includeTag,unsigned char * rettag)82 nsslowcert_dataStart(unsigned char *buf, unsigned int length,
83 unsigned int *data_length, PRBool includeTag,
84 unsigned char *rettag)
85 {
86 unsigned char tag;
87 unsigned int used_length = 0;
88
89 /* need at least a tag and a 1 byte length */
90 if (length < 2) {
91 return NULL;
92 }
93
94 tag = buf[used_length++];
95
96 if (rettag) {
97 *rettag = tag;
98 }
99
100 /* blow out when we come to the end */
101 if (tag == 0) {
102 return NULL;
103 }
104
105 *data_length = buf[used_length++];
106
107 if (*data_length & 0x80) {
108 int len_count = *data_length & 0x7f;
109
110 if (len_count + used_length > length) {
111 return NULL;
112 }
113
114 *data_length = 0;
115
116 while (len_count-- > 0) {
117 *data_length = (*data_length << 8) | buf[used_length++];
118 }
119 }
120
121 if (*data_length > (length - used_length)) {
122 *data_length = length - used_length;
123 return NULL;
124 }
125 if (includeTag)
126 *data_length += used_length;
127
128 return (buf + (includeTag ? 0 : used_length));
129 }
130
131 static void
SetTimeType(SECItem * item,unsigned char tagtype)132 SetTimeType(SECItem *item, unsigned char tagtype)
133 {
134 switch (tagtype) {
135 case SEC_ASN1_UTC_TIME:
136 item->type = siUTCTime;
137 break;
138
139 case SEC_ASN1_GENERALIZED_TIME:
140 item->type = siGeneralizedTime;
141 break;
142
143 default:
144 PORT_Assert(0);
145 break;
146 }
147 }
148
149 static int
nsslowcert_GetValidityFields(unsigned char * buf,int buf_length,SECItem * notBefore,SECItem * notAfter)150 nsslowcert_GetValidityFields(unsigned char *buf, int buf_length,
151 SECItem *notBefore, SECItem *notAfter)
152 {
153 unsigned char tagtype;
154 notBefore->data = nsslowcert_dataStart(buf, buf_length,
155 ¬Before->len, PR_FALSE, &tagtype);
156 if (notBefore->data == NULL)
157 return SECFailure;
158 SetTimeType(notBefore, tagtype);
159 buf_length -= (notBefore->data - buf) + notBefore->len;
160 buf = notBefore->data + notBefore->len;
161 notAfter->data = nsslowcert_dataStart(buf, buf_length,
162 ¬After->len, PR_FALSE, &tagtype);
163 if (notAfter->data == NULL)
164 return SECFailure;
165 SetTimeType(notAfter, tagtype);
166 return SECSuccess;
167 }
168
169 static int
nsslowcert_GetCertFields(unsigned char * cert,int cert_length,SECItem * issuer,SECItem * serial,SECItem * derSN,SECItem * subject,SECItem * valid,SECItem * subjkey,SECItem * extensions)170 nsslowcert_GetCertFields(unsigned char *cert, int cert_length,
171 SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject,
172 SECItem *valid, SECItem *subjkey, SECItem *extensions)
173 {
174 unsigned char *buf;
175 unsigned int buf_length;
176 unsigned char *dummy;
177 unsigned int dummylen;
178
179 /* get past the signature wrap */
180 buf = nsslowcert_dataStart(cert, cert_length, &buf_length, PR_FALSE, NULL);
181 if (buf == NULL)
182 return SECFailure;
183 /* get into the raw cert data */
184 buf = nsslowcert_dataStart(buf, buf_length, &buf_length, PR_FALSE, NULL);
185 if (buf == NULL)
186 return SECFailure;
187 /* skip past any optional version number */
188 if ((buf[0] & 0xa0) == 0xa0) {
189 dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
190 if (dummy == NULL)
191 return SECFailure;
192 buf_length -= (dummy - buf) + dummylen;
193 buf = dummy + dummylen;
194 }
195 /* serial number */
196 if (derSN) {
197 derSN->data = nsslowcert_dataStart(buf, buf_length, &derSN->len, PR_TRUE, NULL);
198 /* derSN->data doesn't need to be checked because if it fails so will
199 * serial->data below. The only difference between the two calls is
200 * whether or not the tags are included in the returned buffer */
201 }
202 serial->data = nsslowcert_dataStart(buf, buf_length, &serial->len, PR_FALSE, NULL);
203 if (serial->data == NULL)
204 return SECFailure;
205 buf_length -= (serial->data - buf) + serial->len;
206 buf = serial->data + serial->len;
207 /* skip the OID */
208 dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
209 if (dummy == NULL)
210 return SECFailure;
211 buf_length -= (dummy - buf) + dummylen;
212 buf = dummy + dummylen;
213 /* issuer */
214 issuer->data = nsslowcert_dataStart(buf, buf_length, &issuer->len, PR_TRUE, NULL);
215 if (issuer->data == NULL)
216 return SECFailure;
217 buf_length -= (issuer->data - buf) + issuer->len;
218 buf = issuer->data + issuer->len;
219
220 /* only wanted issuer/SN */
221 if (valid == NULL) {
222 return SECSuccess;
223 }
224 /* validity */
225 valid->data = nsslowcert_dataStart(buf, buf_length, &valid->len, PR_FALSE, NULL);
226 if (valid->data == NULL)
227 return SECFailure;
228 buf_length -= (valid->data - buf) + valid->len;
229 buf = valid->data + valid->len;
230 /*subject */
231 subject->data = nsslowcert_dataStart(buf, buf_length, &subject->len, PR_TRUE, NULL);
232 if (subject->data == NULL)
233 return SECFailure;
234 buf_length -= (subject->data - buf) + subject->len;
235 buf = subject->data + subject->len;
236 /* subject key info */
237 subjkey->data = nsslowcert_dataStart(buf, buf_length, &subjkey->len, PR_TRUE, NULL);
238 if (subjkey->data == NULL)
239 return SECFailure;
240 buf_length -= (subjkey->data - buf) + subjkey->len;
241 buf = subjkey->data + subjkey->len;
242
243 extensions->data = NULL;
244 extensions->len = 0;
245 while (buf_length > 0) {
246 /* EXTENSIONS */
247 if (buf[0] == 0xa3) {
248 extensions->data = nsslowcert_dataStart(buf, buf_length,
249 &extensions->len, PR_FALSE, NULL);
250 /* if the DER is bad, we should fail. Previously we accepted
251 * bad DER here and treated the extension as missin */
252 if (extensions->data == NULL ||
253 (extensions->data - buf) + extensions->len != buf_length)
254 return SECFailure;
255 buf = extensions->data;
256 buf_length = extensions->len;
257 /* now parse the SEQUENCE holding the extensions. */
258 dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
259 if (dummy == NULL ||
260 (dummy - buf) + dummylen != buf_length)
261 return SECFailure;
262 buf_length -= (dummy - buf);
263 buf = dummy;
264 /* Now parse the extensions inside this sequence */
265 }
266 dummy = nsslowcert_dataStart(buf, buf_length, &dummylen, PR_FALSE, NULL);
267 if (dummy == NULL)
268 return SECFailure;
269 buf_length -= (dummy - buf) + dummylen;
270 buf = dummy + dummylen;
271 }
272 return SECSuccess;
273 }
274
275 static SECStatus
nsslowcert_GetCertTimes(NSSLOWCERTCertificate * c,PRTime * notBefore,PRTime * notAfter)276 nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
277 {
278 int rv;
279 NSSLOWCERTValidity validity;
280
281 rv = nsslowcert_GetValidityFields(c->validity.data, c->validity.len,
282 &validity.notBefore, &validity.notAfter);
283 if (rv != SECSuccess) {
284 return rv;
285 }
286
287 /* convert DER not-before time */
288 rv = DER_DecodeTimeChoice(notBefore, &validity.notBefore);
289 if (rv) {
290 return (SECFailure);
291 }
292
293 /* convert DER not-after time */
294 rv = DER_DecodeTimeChoice(notAfter, &validity.notAfter);
295 if (rv) {
296 return (SECFailure);
297 }
298
299 return (SECSuccess);
300 }
301
302 /*
303 * is certa newer than certb? If one is expired, pick the other one.
304 */
305 PRBool
nsslowcert_IsNewer(NSSLOWCERTCertificate * certa,NSSLOWCERTCertificate * certb)306 nsslowcert_IsNewer(NSSLOWCERTCertificate *certa, NSSLOWCERTCertificate *certb)
307 {
308 PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
309 SECStatus rv;
310 PRBool newerbefore, newerafter;
311
312 rv = nsslowcert_GetCertTimes(certa, ¬BeforeA, ¬AfterA);
313 if (rv != SECSuccess) {
314 return (PR_FALSE);
315 }
316
317 rv = nsslowcert_GetCertTimes(certb, ¬BeforeB, ¬AfterB);
318 if (rv != SECSuccess) {
319 return (PR_TRUE);
320 }
321
322 newerbefore = PR_FALSE;
323 if (LL_CMP(notBeforeA, >, notBeforeB)) {
324 newerbefore = PR_TRUE;
325 }
326
327 newerafter = PR_FALSE;
328 if (LL_CMP(notAfterA, >, notAfterB)) {
329 newerafter = PR_TRUE;
330 }
331
332 if (newerbefore && newerafter) {
333 return (PR_TRUE);
334 }
335
336 if ((!newerbefore) && (!newerafter)) {
337 return (PR_FALSE);
338 }
339
340 /* get current time */
341 now = PR_Now();
342
343 if (newerbefore) {
344 /* cert A was issued after cert B, but expires sooner */
345 /* if A is expired, then pick B */
346 if (LL_CMP(notAfterA, <, now)) {
347 return (PR_FALSE);
348 }
349 return (PR_TRUE);
350 } else {
351 /* cert B was issued after cert A, but expires sooner */
352 /* if B is expired, then pick A */
353 if (LL_CMP(notAfterB, <, now)) {
354 return (PR_TRUE);
355 }
356 return (PR_FALSE);
357 }
358 }
359
360 #define SOFT_DEFAULT_CHUNKSIZE 2048
361
362 static SECStatus
nsslowcert_KeyFromIssuerAndSN(PLArenaPool * arena,SECItem * issuer,SECItem * sn,SECItem * key)363 nsslowcert_KeyFromIssuerAndSN(PLArenaPool *arena,
364 SECItem *issuer, SECItem *sn, SECItem *key)
365 {
366 unsigned int len = sn->len + issuer->len;
367
368 if (!arena) {
369 PORT_SetError(SEC_ERROR_INVALID_ARGS);
370 goto loser;
371 }
372 if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) {
373 PORT_SetError(SEC_ERROR_INPUT_LEN);
374 goto loser;
375 }
376 key->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
377 if (!key->data) {
378 goto loser;
379 }
380
381 key->len = len;
382 /* copy the serialNumber */
383 PORT_Memcpy(key->data, sn->data, sn->len);
384
385 /* copy the issuer */
386 PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
387
388 return (SECSuccess);
389
390 loser:
391 return (SECFailure);
392 }
393
394 static SECStatus
nsslowcert_KeyFromIssuerAndSNStatic(unsigned char * space,int spaceLen,SECItem * issuer,SECItem * sn,SECItem * key)395 nsslowcert_KeyFromIssuerAndSNStatic(unsigned char *space,
396 int spaceLen, SECItem *issuer, SECItem *sn, SECItem *key)
397 {
398 unsigned int len = sn->len + issuer->len;
399
400 key->data = pkcs11_allocStaticData(len, space, spaceLen);
401 if (!key->data) {
402 goto loser;
403 }
404
405 key->len = len;
406 /* copy the serialNumber */
407 PORT_Memcpy(key->data, sn->data, sn->len);
408
409 /* copy the issuer */
410 PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
411
412 return (SECSuccess);
413
414 loser:
415 return (SECFailure);
416 }
417
418 static char *
nsslowcert_EmailName(SECItem * derDN,char * space,unsigned int len)419 nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len)
420 {
421 unsigned char *buf;
422 unsigned int buf_length;
423
424 /* unwrap outer sequence */
425 buf = nsslowcert_dataStart(derDN->data, derDN->len, &buf_length, PR_FALSE, NULL);
426 if (buf == NULL)
427 return NULL;
428
429 /* Walk each RDN */
430 while (buf_length > 0) {
431 unsigned char *rdn;
432 unsigned int rdn_length;
433
434 /* grab next rdn */
435 rdn = nsslowcert_dataStart(buf, buf_length, &rdn_length, PR_FALSE, NULL);
436 if (rdn == NULL) {
437 return NULL;
438 }
439 buf_length -= (rdn - buf) + rdn_length;
440 buf = rdn + rdn_length;
441
442 while (rdn_length > 0) {
443 unsigned char *ava;
444 unsigned int ava_length;
445 unsigned char *oid;
446 unsigned int oid_length;
447 unsigned char *name;
448 unsigned int name_length;
449 SECItem oidItem;
450 SECOidTag type;
451
452 /* unwrap the ava */
453 ava = nsslowcert_dataStart(rdn, rdn_length, &ava_length, PR_FALSE,
454 NULL);
455 if (ava == NULL)
456 return NULL;
457 rdn_length -= (ava - rdn) + ava_length;
458 rdn = ava + ava_length;
459
460 oid = nsslowcert_dataStart(ava, ava_length, &oid_length, PR_FALSE,
461 NULL);
462 if (oid == NULL) {
463 return NULL;
464 }
465 ava_length -= (oid - ava) + oid_length;
466 ava = oid + oid_length;
467
468 name = nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE,
469 NULL);
470 if (name == NULL) {
471 return NULL;
472 }
473 ava_length -= (name - ava) + name_length;
474 ava = name + name_length;
475
476 oidItem.data = oid;
477 oidItem.len = oid_length;
478 type = SECOID_FindOIDTag(&oidItem);
479 if ((type == SEC_OID_PKCS9_EMAIL_ADDRESS) ||
480 (type == SEC_OID_RFC1274_MAIL)) {
481 /* Email is supposed to be IA5String, so no
482 * translation necessary */
483 char *emailAddr;
484 emailAddr = (char *)pkcs11_copyStaticData(name, name_length + 1,
485 (unsigned char *)space, len);
486 if (emailAddr) {
487 emailAddr[name_length] = 0;
488 }
489 return emailAddr;
490 }
491 }
492 }
493 return NULL;
494 }
495
496 static char *
nsslowcert_EmailAltName(NSSLOWCERTCertificate * cert,char * space,unsigned int len)497 nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space,
498 unsigned int len)
499 {
500 unsigned char *exts;
501 unsigned int exts_length;
502
503 /* unwrap the sequence */
504 exts = nsslowcert_dataStart(cert->extensions.data, cert->extensions.len,
505 &exts_length, PR_FALSE, NULL);
506 /* loop through extension */
507 while (exts && exts_length > 0) {
508 unsigned char *ext;
509 unsigned int ext_length;
510 unsigned char *oid;
511 unsigned int oid_length;
512 unsigned char *nameList;
513 unsigned int nameList_length;
514 SECItem oidItem;
515 SECOidTag type;
516
517 ext = nsslowcert_dataStart(exts, exts_length, &ext_length,
518 PR_FALSE, NULL);
519 if (ext == NULL) {
520 break;
521 }
522 exts_length -= (ext - exts) + ext_length;
523 exts = ext + ext_length;
524
525 oid = nsslowcert_dataStart(ext, ext_length, &oid_length, PR_FALSE, NULL);
526 if (oid == NULL) {
527 break;
528 }
529 ext_length -= (oid - ext) + oid_length;
530 ext = oid + oid_length;
531 oidItem.data = oid;
532 oidItem.len = oid_length;
533 type = SECOID_FindOIDTag(&oidItem);
534
535 /* get Alt Extension */
536 if (type != SEC_OID_X509_SUBJECT_ALT_NAME) {
537 continue;
538 }
539
540 /* skip passed the critical flag */
541 if (ext[0] == 0x01) { /* BOOLEAN */
542 unsigned char *dummy;
543 unsigned int dummy_length;
544 dummy = nsslowcert_dataStart(ext, ext_length, &dummy_length,
545 PR_FALSE, NULL);
546 if (dummy == NULL) {
547 break;
548 }
549 ext_length -= (dummy - ext) + dummy_length;
550 ext = dummy + dummy_length;
551 }
552
553 /* unwrap the name list */
554 nameList = nsslowcert_dataStart(ext, ext_length, &nameList_length,
555 PR_FALSE, NULL);
556 if (nameList == NULL) {
557 break;
558 }
559 ext_length -= (nameList - ext) + nameList_length;
560 ext = nameList + nameList_length;
561 nameList = nsslowcert_dataStart(nameList, nameList_length,
562 &nameList_length, PR_FALSE, NULL);
563 /* loop through the name list */
564 while (nameList && nameList_length > 0) {
565 unsigned char *thisName;
566 unsigned int thisName_length;
567
568 thisName = nsslowcert_dataStart(nameList, nameList_length,
569 &thisName_length, PR_FALSE, NULL);
570 if (thisName == NULL) {
571 break;
572 }
573 if (nameList[0] == 0xa2) { /* DNS Name */
574 SECItem dn;
575 char *emailAddr;
576
577 dn.data = thisName;
578 dn.len = thisName_length;
579 emailAddr = nsslowcert_EmailName(&dn, space, len);
580 if (emailAddr) {
581 return emailAddr;
582 }
583 }
584 if (nameList[0] == 0x81) { /* RFC 822name */
585 char *emailAddr;
586 emailAddr = (char *)pkcs11_copyStaticData(thisName,
587 thisName_length + 1, (unsigned char *)space, len);
588 if (emailAddr) {
589 emailAddr[thisName_length] = 0;
590 }
591 return emailAddr;
592 }
593 nameList_length -= (thisName - nameList) + thisName_length;
594 nameList = thisName + thisName_length;
595 }
596 break;
597 }
598 return NULL;
599 }
600
601 static char *
nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate * cert)602 nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert)
603 {
604 char *emailAddr = NULL;
605 char *str;
606
607 emailAddr = nsslowcert_EmailName(&cert->derSubject, cert->emailAddrSpace,
608 sizeof(cert->emailAddrSpace));
609 /* couldn't find the email address in the DN, check the subject Alt name */
610 if (!emailAddr && cert->extensions.data) {
611 emailAddr = nsslowcert_EmailAltName(cert, cert->emailAddrSpace,
612 sizeof(cert->emailAddrSpace));
613 }
614
615 /* make it lower case */
616 str = emailAddr;
617 while (str && *str) {
618 *str = tolower(*str);
619 str++;
620 }
621 return emailAddr;
622 }
623
624 /*
625 * take a DER certificate and decode it into a certificate structure
626 */
627 NSSLOWCERTCertificate *
nsslowcert_DecodeDERCertificate(SECItem * derSignedCert,char * nickname)628 nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname)
629 {
630 NSSLOWCERTCertificate *cert;
631 int rv;
632
633 /* allocate the certificate structure */
634 cert = nsslowcert_CreateCert();
635
636 if (!cert) {
637 goto loser;
638 }
639
640 /* point to passed in DER data */
641 cert->derCert = *derSignedCert;
642 cert->nickname = NULL;
643 cert->certKey.data = NULL;
644 cert->referenceCount = 1;
645
646 /* decode the certificate info */
647 rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len,
648 &cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject,
649 &cert->validity, &cert->derSubjKeyInfo, &cert->extensions);
650
651 if (rv != SECSuccess) {
652 goto loser;
653 }
654
655 /* cert->subjectKeyID; x509v3 subject key identifier */
656 cert->subjectKeyID.data = NULL;
657 cert->subjectKeyID.len = 0;
658 cert->dbEntry = NULL;
659 cert->trust = NULL;
660 cert->dbhandle = NULL;
661
662 /* generate and save the database key for the cert */
663 rv = nsslowcert_KeyFromIssuerAndSNStatic(cert->certKeySpace,
664 sizeof(cert->certKeySpace), &cert->derIssuer,
665 &cert->serialNumber, &cert->certKey);
666 if (rv) {
667 goto loser;
668 }
669
670 /* set the nickname */
671 if (nickname == NULL) {
672 cert->nickname = NULL;
673 } else {
674 /* copy and install the nickname */
675 cert->nickname = pkcs11_copyNickname(nickname, cert->nicknameSpace,
676 sizeof(cert->nicknameSpace));
677 }
678
679 #ifdef FIXME
680 /* initialize the subjectKeyID */
681 rv = cert_GetKeyID(cert);
682 if (rv != SECSuccess) {
683 goto loser;
684 }
685 #endif
686
687 /* set the email address */
688 cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert);
689
690 cert->referenceCount = 1;
691
692 return (cert);
693
694 loser:
695 if (cert) {
696 nsslowcert_DestroyCertificate(cert);
697 }
698
699 return (0);
700 }
701
702 char *
nsslowcert_FixupEmailAddr(char * emailAddr)703 nsslowcert_FixupEmailAddr(char *emailAddr)
704 {
705 char *retaddr;
706 char *str;
707
708 if (emailAddr == NULL) {
709 return (NULL);
710 }
711
712 /* copy the string */
713 str = retaddr = PORT_Strdup(emailAddr);
714 if (str == NULL) {
715 return (NULL);
716 }
717
718 /* make it lower case */
719 while (*str) {
720 *str = tolower(*str);
721 str++;
722 }
723
724 return (retaddr);
725 }
726
727 /*
728 * Generate a database key, based on serial number and issuer, from a
729 * DER certificate.
730 */
731 SECStatus
nsslowcert_KeyFromDERCert(PLArenaPool * arena,SECItem * derCert,SECItem * key)732 nsslowcert_KeyFromDERCert(PLArenaPool *arena, SECItem *derCert, SECItem *key)
733 {
734 int rv;
735 NSSLOWCERTCertKey certkey;
736
737 PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey));
738
739 rv = nsslowcert_GetCertFields(derCert->data, derCert->len,
740 &certkey.derIssuer, &certkey.serialNumber, NULL, NULL,
741 NULL, NULL, NULL);
742
743 if (rv) {
744 goto loser;
745 }
746
747 return (nsslowcert_KeyFromIssuerAndSN(arena, &certkey.derIssuer,
748 &certkey.serialNumber, key));
749 loser:
750 return (SECFailure);
751 }
752
753 NSSLOWKEYPublicKey *
nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate * cert)754 nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *cert)
755 {
756 NSSLOWCERTSubjectPublicKeyInfo spki;
757 NSSLOWKEYPublicKey *pubk;
758 SECItem os;
759 SECStatus rv;
760 PLArenaPool *arena;
761 SECOidTag tag;
762 SECItem newDerSubjKeyInfo;
763
764 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
765 if (arena == NULL)
766 return NULL;
767
768 pubk = (NSSLOWKEYPublicKey *)
769 PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPublicKey));
770 if (pubk == NULL) {
771 PORT_FreeArena(arena, PR_FALSE);
772 return NULL;
773 }
774
775 pubk->arena = arena;
776 PORT_Memset(&spki, 0, sizeof(spki));
777
778 /* copy the DER into the arena, since Quick DER returns data that points
779 into the DER input, which may get freed by the caller */
780 rv = SECITEM_CopyItem(arena, &newDerSubjKeyInfo, &cert->derSubjKeyInfo);
781 if (rv != SECSuccess) {
782 PORT_FreeArena(arena, PR_FALSE);
783 return NULL;
784 }
785
786 /* we haven't bothered decoding the spki struct yet, do it now */
787 rv = SEC_QuickDERDecodeItem(arena, &spki,
788 nsslowcert_SubjectPublicKeyInfoTemplate, &newDerSubjKeyInfo);
789 if (rv != SECSuccess) {
790 PORT_FreeArena(arena, PR_FALSE);
791 return NULL;
792 }
793
794 /* Convert bit string length from bits to bytes */
795 os = spki.subjectPublicKey;
796 DER_ConvertBitString(&os);
797
798 tag = SECOID_GetAlgorithmTag(&spki.algorithm);
799 switch (tag) {
800 case SEC_OID_X500_RSA_ENCRYPTION:
801 case SEC_OID_PKCS1_RSA_ENCRYPTION:
802 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
803 pubk->keyType = NSSLOWKEYRSAKey;
804 prepare_low_rsa_pub_key_for_asn1(pubk);
805 rv = SEC_QuickDERDecodeItem(arena, pubk,
806 nsslowcert_RSAPublicKeyTemplate, &os);
807 if (rv == SECSuccess)
808 return pubk;
809 break;
810 case SEC_OID_ANSIX9_DSA_SIGNATURE:
811 pubk->keyType = NSSLOWKEYDSAKey;
812 prepare_low_dsa_pub_key_for_asn1(pubk);
813 rv = SEC_QuickDERDecodeItem(arena, pubk,
814 nsslowcert_DSAPublicKeyTemplate, &os);
815 if (rv == SECSuccess)
816 return pubk;
817 break;
818 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
819 pubk->keyType = NSSLOWKEYDHKey;
820 prepare_low_dh_pub_key_for_asn1(pubk);
821 rv = SEC_QuickDERDecodeItem(arena, pubk,
822 nsslowcert_DHPublicKeyTemplate, &os);
823 if (rv == SECSuccess)
824 return pubk;
825 break;
826 case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
827 pubk->keyType = NSSLOWKEYECKey;
828 /* Since PKCS#11 directly takes the DER encoding of EC params
829 * and public value, we don't need any decoding here.
830 */
831 rv = SECITEM_CopyItem(arena, &pubk->u.ec.ecParams.DEREncoding,
832 &spki.algorithm.parameters);
833 if (rv != SECSuccess)
834 break;
835
836 /* Fill out the rest of the ecParams structure
837 * based on the encoded params
838 */
839 if (LGEC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding,
840 &pubk->u.ec.ecParams) != SECSuccess)
841 break;
842
843 rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &os);
844 if (rv == SECSuccess)
845 return pubk;
846 break;
847 default:
848 rv = SECFailure;
849 break;
850 }
851
852 lg_nsslowkey_DestroyPublicKey(pubk);
853 return NULL;
854 }
855