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                                            &notBefore->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                                           &notAfter->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, &notBeforeA, &notAfterA);
313     if (rv != SECSuccess) {
314         return (PR_FALSE);
315     }
316 
317     rv = nsslowcert_GetCertTimes(certb, &notBeforeB, &notAfterB);
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