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