security/nss/lib/softoken/legacydb/lowcert.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 /*
     6  * Certificate handling code
     7  */
     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"
    18 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    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 };
    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 };
    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  */
    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 }
    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 }
    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 }
    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;
    88     /* need at least a tag and a 1 byte length */
    89     if (length < 2) {
    90 	return NULL;
    91     }
    93     tag = buf[used_length++];
    95     if (rettag) {
    96         *rettag = tag;
    97     }
    99     /* blow out when we come to the end */
   100     if (tag == 0) {
   101 	return NULL;
   102     }
   104     *data_length = buf[used_length++];
   106     if (*data_length&0x80) {
   107 	int  len_count = *data_length & 0x7f;
   109 	if (len_count+used_length > length) {
   110 	   return NULL;
   111 	}
   113 	*data_length = 0;
   115 	while (len_count-- > 0) {
   116 	    *data_length = (*data_length << 8) | buf[used_length++];
   117 	} 
   118     }
   120     if (*data_length > (length-used_length) ) {
   121 	*data_length = length-used_length;
   122 	return NULL;
   123     }
   124     if (includeTag) *data_length += used_length;
   126     return (buf + (includeTag ? 0 : used_length));	
   127 }
   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;
   136         case SEC_ASN1_GENERALIZED_TIME:
   137             item->type = siGeneralizedTime;
   138             break;
   140         default:
   141             PORT_Assert(0);
   142             break;
   143     }
   144 }
   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 }
   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;
   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;
   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;
   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 }
   260 static SECStatus
   261 nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
   262 {
   263     int rv;
   264     NSSLOWCERTValidity validity;
   266     rv = nsslowcert_GetValidityFields(c->validity.data,c->validity.len,
   267 				&validity.notBefore,&validity.notAfter);
   268     if (rv != SECSuccess) {
   269 	return rv;
   270     }
   272     /* convert DER not-before time */
   273     rv = DER_DecodeTimeChoice(notBefore, &validity.notBefore);
   274     if (rv) {
   275         return(SECFailure);
   276     }
   278     /* convert DER not-after time */
   279     rv = DER_DecodeTimeChoice(notAfter, &validity.notAfter);
   280     if (rv) {
   281         return(SECFailure);
   282     }
   284     return(SECSuccess);
   285 }
   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;
   297     rv = nsslowcert_GetCertTimes(certa, &notBeforeA, &notAfterA);
   298     if ( rv != SECSuccess ) {
   299 	return(PR_FALSE);
   300     }
   302     rv = nsslowcert_GetCertTimes(certb, &notBeforeB, &notAfterB);
   303     if ( rv != SECSuccess ) {
   304 	return(PR_TRUE);
   305     }
   307     newerbefore = PR_FALSE;
   308     if ( LL_CMP(notBeforeA, >, notBeforeB) ) {
   309 	newerbefore = PR_TRUE;
   310     }
   312     newerafter = PR_FALSE;
   313     if ( LL_CMP(notAfterA, >, notAfterB) ) {
   314 	newerafter = PR_TRUE;
   315     }
   317     if ( newerbefore && newerafter ) {
   318 	return(PR_TRUE);
   319     }
   321     if ( ( !newerbefore ) && ( !newerafter ) ) {
   322 	return(PR_FALSE);
   323     }
   325     /* get current time */
   326     now = PR_Now();
   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 }
   345 #define SOFT_DEFAULT_CHUNKSIZE 2048
   347 static SECStatus
   348 nsslowcert_KeyFromIssuerAndSN(PLArenaPool *arena,
   349 			      SECItem *issuer, SECItem *sn, SECItem *key)
   350 {
   351     unsigned int len = sn->len + issuer->len;
   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     }
   366     key->len = len;
   367     /* copy the serialNumber */
   368     PORT_Memcpy(key->data, sn->data, sn->len);
   370     /* copy the issuer */
   371     PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
   373     return(SECSuccess);
   375 loser:
   376     return(SECFailure);
   377 }
   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;
   385     key->data = pkcs11_allocStaticData(len, space, spaceLen);
   386     if ( !key->data ) {
   387 	goto loser;
   388     }
   390     key->len = len;
   391     /* copy the serialNumber */
   392     PORT_Memcpy(key->data, sn->data, sn->len);
   394     /* copy the issuer */
   395     PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
   397     return(SECSuccess);
   399 loser:
   400     return(SECFailure);
   401 }
   404 static char *
   405 nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len)
   406 {
   407     unsigned char *buf;
   408     unsigned int buf_length;
   410     /* unwrap outer sequence */
   411     buf=nsslowcert_dataStart(derDN->data,derDN->len,&buf_length,PR_FALSE,NULL);
   412     if (buf == NULL) return NULL;
   414     /* Walk each RDN */
   415     while (buf_length > 0) {
   416 	unsigned char *rdn;
   417 	unsigned int rdn_length;
   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;
   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;
   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;
   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;
   448 	    name=nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE, 
   449 					NULL);
   450 	    if (oid == NULL) { return NULL; }
   451 	    ava_length -= (name-ava)+name_length;
   452 	    ava = name+name_length;
   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 }
   474 static char *
   475 nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space, 
   476 			unsigned int len)
   477 {
   478     unsigned char *exts;
   479     unsigned int exts_length;
   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;
   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;
   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);
   509 	/* get Alt Extension */
   510 	if (type != SEC_OID_X509_SUBJECT_ALT_NAME) {
   511 		continue;
   512 	}
   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 	}
   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;
   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;
   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 }
   570 static char *
   571 nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert)
   572 {
   573     char *emailAddr = NULL;
   574     char *str;
   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     }
   585     /* make it lower case */
   586     str = emailAddr;
   587     while ( str && *str ) {
   588 	*str = tolower( *str );
   589 	str++;
   590     }
   591     return emailAddr;
   593 }
   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;
   604     /* allocate the certificate structure */
   605     cert = nsslowcert_CreateCert();
   607     if ( !cert ) {
   608 	goto loser;
   609     }
   611 	/* point to passed in DER data */
   612     cert->derCert = *derSignedCert;
   613     cert->nickname = NULL;
   614     cert->certKey.data = NULL;
   615     cert->referenceCount = 1;
   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);
   622     if (rv != SECSuccess) {
   623 	goto loser;
   624     }
   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;
   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     }
   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     }
   650 #ifdef FIXME
   651     /* initialize the subjectKeyID */
   652     rv = cert_GetKeyID(cert);
   653     if ( rv != SECSuccess ) {
   654 	goto loser;
   655     }
   656 #endif
   658     /* set the email address */
   659     cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert);
   662     cert->referenceCount = 1;
   664     return(cert);
   666 loser:
   667     if (cert) {
   668 	nsslowcert_DestroyCertificate(cert);
   669     }
   671     return(0);
   672 }
   674 char *
   675 nsslowcert_FixupEmailAddr(char *emailAddr)
   676 {
   677     char *retaddr;
   678     char *str;
   680     if ( emailAddr == NULL ) {
   681 	return(NULL);
   682     }
   684     /* copy the string */
   685     str = retaddr = PORT_Strdup(emailAddr);
   686     if ( str == NULL ) {
   687 	return(NULL);
   688     }
   690     /* make it lower case */
   691     while ( *str ) {
   692 	*str = tolower( *str );
   693 	str++;
   694     }
   696     return(retaddr);
   697 }
   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;
   710     PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey));    
   712     rv = nsslowcert_GetCertFields(derCert->data, derCert->len,
   713 	&certkey.derIssuer, &certkey.serialNumber, NULL, NULL, 
   714 	NULL, NULL, NULL);
   716     if ( rv ) {
   717 	goto loser;
   718     }
   720     return(nsslowcert_KeyFromIssuerAndSN(arena, &certkey.derIssuer,
   721 				   &certkey.serialNumber, key));
   722 loser:
   723     return(SECFailure);
   724 }
   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;
   737     arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
   738     if (arena == NULL)
   739         return NULL;
   741     pubk = (NSSLOWKEYPublicKey *) 
   742 		PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPublicKey));
   743     if (pubk == NULL) {
   744         PORT_FreeArena (arena, PR_FALSE);
   745         return NULL;
   746     }
   748     pubk->arena = arena;
   749     PORT_Memset(&spki,0,sizeof(spki));
   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     }
   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     }
   767     /* Convert bit string length from bits to bytes */
   768     os = spki.subjectPublicKey;
   769     DER_ConvertBitString (&os);
   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;	
   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;
   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     }
   823     lg_nsslowkey_DestroyPublicKey (pubk);
   824     return NULL;
   825 }

mercurial