1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/legacydb/lowcert.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,826 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Certificate handling code 1.10 + */ 1.11 + 1.12 +#include "seccomon.h" 1.13 +#include "secder.h" 1.14 +#include "nssilock.h" 1.15 +#include "lowkeyi.h" 1.16 +#include "secasn1.h" 1.17 +#include "secoid.h" 1.18 +#include "secerr.h" 1.19 +#include "pcert.h" 1.20 + 1.21 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 1.22 + 1.23 +static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = { 1.24 + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) }, 1.25 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1.26 + offsetof(NSSLOWCERTSubjectPublicKeyInfo,algorithm), 1.27 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.28 + { SEC_ASN1_BIT_STRING, 1.29 + offsetof(NSSLOWCERTSubjectPublicKeyInfo,subjectPublicKey), }, 1.30 + { 0, } 1.31 +}; 1.32 + 1.33 +static const SEC_ASN1Template nsslowcert_RSAPublicKeyTemplate[] = { 1.34 + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) }, 1.35 + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.modulus), }, 1.36 + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.rsa.publicExponent), }, 1.37 + { 0, } 1.38 +}; 1.39 +static const SEC_ASN1Template nsslowcert_DSAPublicKeyTemplate[] = { 1.40 + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dsa.publicValue), }, 1.41 + { 0, } 1.42 +}; 1.43 +static const SEC_ASN1Template nsslowcert_DHPublicKeyTemplate[] = { 1.44 + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey,u.dh.publicValue), }, 1.45 + { 0, } 1.46 +}; 1.47 + 1.48 +/* 1.49 + * See bugzilla bug 125359 1.50 + * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, 1.51 + * all of the templates above that en/decode into integers must be converted 1.52 + * from ASN.1's signed integer type. This is done by marking either the 1.53 + * source or destination (encoding or decoding, respectively) type as 1.54 + * siUnsignedInteger. 1.55 + */ 1.56 + 1.57 +static void 1.58 +prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk) 1.59 +{ 1.60 + pubk->u.rsa.modulus.type = siUnsignedInteger; 1.61 + pubk->u.rsa.publicExponent.type = siUnsignedInteger; 1.62 +} 1.63 + 1.64 +static void 1.65 +prepare_low_dsa_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk) 1.66 +{ 1.67 + pubk->u.dsa.publicValue.type = siUnsignedInteger; 1.68 + pubk->u.dsa.params.prime.type = siUnsignedInteger; 1.69 + pubk->u.dsa.params.subPrime.type = siUnsignedInteger; 1.70 + pubk->u.dsa.params.base.type = siUnsignedInteger; 1.71 +} 1.72 + 1.73 +static void 1.74 +prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk) 1.75 +{ 1.76 + pubk->u.dh.prime.type = siUnsignedInteger; 1.77 + pubk->u.dh.base.type = siUnsignedInteger; 1.78 + pubk->u.dh.publicValue.type = siUnsignedInteger; 1.79 +} 1.80 + 1.81 +/* 1.82 + * simple cert decoder to avoid the cost of asn1 engine 1.83 + */ 1.84 +static unsigned char * 1.85 +nsslowcert_dataStart(unsigned char *buf, unsigned int length, 1.86 + unsigned int *data_length, PRBool includeTag, 1.87 + unsigned char* rettag) { 1.88 + unsigned char tag; 1.89 + unsigned int used_length= 0; 1.90 + 1.91 + /* need at least a tag and a 1 byte length */ 1.92 + if (length < 2) { 1.93 + return NULL; 1.94 + } 1.95 + 1.96 + tag = buf[used_length++]; 1.97 + 1.98 + if (rettag) { 1.99 + *rettag = tag; 1.100 + } 1.101 + 1.102 + /* blow out when we come to the end */ 1.103 + if (tag == 0) { 1.104 + return NULL; 1.105 + } 1.106 + 1.107 + *data_length = buf[used_length++]; 1.108 + 1.109 + if (*data_length&0x80) { 1.110 + int len_count = *data_length & 0x7f; 1.111 + 1.112 + if (len_count+used_length > length) { 1.113 + return NULL; 1.114 + } 1.115 + 1.116 + *data_length = 0; 1.117 + 1.118 + while (len_count-- > 0) { 1.119 + *data_length = (*data_length << 8) | buf[used_length++]; 1.120 + } 1.121 + } 1.122 + 1.123 + if (*data_length > (length-used_length) ) { 1.124 + *data_length = length-used_length; 1.125 + return NULL; 1.126 + } 1.127 + if (includeTag) *data_length += used_length; 1.128 + 1.129 + return (buf + (includeTag ? 0 : used_length)); 1.130 +} 1.131 + 1.132 +static void SetTimeType(SECItem* item, unsigned char tagtype) 1.133 +{ 1.134 + switch (tagtype) { 1.135 + case SEC_ASN1_UTC_TIME: 1.136 + item->type = siUTCTime; 1.137 + break; 1.138 + 1.139 + case SEC_ASN1_GENERALIZED_TIME: 1.140 + item->type = siGeneralizedTime; 1.141 + break; 1.142 + 1.143 + default: 1.144 + PORT_Assert(0); 1.145 + break; 1.146 + } 1.147 +} 1.148 + 1.149 +static int 1.150 +nsslowcert_GetValidityFields(unsigned char *buf,int buf_length, 1.151 + SECItem *notBefore, SECItem *notAfter) 1.152 +{ 1.153 + unsigned char tagtype; 1.154 + notBefore->data = nsslowcert_dataStart(buf,buf_length, 1.155 + ¬Before->len,PR_FALSE, &tagtype); 1.156 + if (notBefore->data == NULL) return SECFailure; 1.157 + SetTimeType(notBefore, tagtype); 1.158 + buf_length -= (notBefore->data-buf) + notBefore->len; 1.159 + buf = notBefore->data + notBefore->len; 1.160 + notAfter->data = nsslowcert_dataStart(buf,buf_length, 1.161 + ¬After->len,PR_FALSE, &tagtype); 1.162 + if (notAfter->data == NULL) return SECFailure; 1.163 + SetTimeType(notAfter, tagtype); 1.164 + return SECSuccess; 1.165 +} 1.166 + 1.167 +static int 1.168 +nsslowcert_GetCertFields(unsigned char *cert,int cert_length, 1.169 + SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject, 1.170 + SECItem *valid, SECItem *subjkey, SECItem *extensions) 1.171 +{ 1.172 + unsigned char *buf; 1.173 + unsigned int buf_length; 1.174 + unsigned char *dummy; 1.175 + unsigned int dummylen; 1.176 + 1.177 + /* get past the signature wrap */ 1.178 + buf = nsslowcert_dataStart(cert,cert_length,&buf_length,PR_FALSE, NULL); 1.179 + if (buf == NULL) return SECFailure; 1.180 + /* get into the raw cert data */ 1.181 + buf = nsslowcert_dataStart(buf,buf_length,&buf_length,PR_FALSE, NULL); 1.182 + if (buf == NULL) return SECFailure; 1.183 + /* skip past any optional version number */ 1.184 + if ((buf[0] & 0xa0) == 0xa0) { 1.185 + dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL); 1.186 + if (dummy == NULL) return SECFailure; 1.187 + buf_length -= (dummy-buf) + dummylen; 1.188 + buf = dummy + dummylen; 1.189 + } 1.190 + /* serial number */ 1.191 + if (derSN) { 1.192 + derSN->data=nsslowcert_dataStart(buf,buf_length,&derSN->len,PR_TRUE, NULL); 1.193 + /* derSN->data doesn't need to be checked because if it fails so will 1.194 + * serial->data below. The only difference between the two calls is 1.195 + * whether or not the tags are included in the returned buffer */ 1.196 + } 1.197 + serial->data = nsslowcert_dataStart(buf,buf_length,&serial->len,PR_FALSE, NULL); 1.198 + if (serial->data == NULL) return SECFailure; 1.199 + buf_length -= (serial->data-buf) + serial->len; 1.200 + buf = serial->data + serial->len; 1.201 + /* skip the OID */ 1.202 + dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE, NULL); 1.203 + if (dummy == NULL) return SECFailure; 1.204 + buf_length -= (dummy-buf) + dummylen; 1.205 + buf = dummy + dummylen; 1.206 + /* issuer */ 1.207 + issuer->data = nsslowcert_dataStart(buf,buf_length,&issuer->len,PR_TRUE, NULL); 1.208 + if (issuer->data == NULL) return SECFailure; 1.209 + buf_length -= (issuer->data-buf) + issuer->len; 1.210 + buf = issuer->data + issuer->len; 1.211 + 1.212 + /* only wanted issuer/SN */ 1.213 + if (valid == NULL) { 1.214 + return SECSuccess; 1.215 + } 1.216 + /* validity */ 1.217 + valid->data = nsslowcert_dataStart(buf,buf_length,&valid->len,PR_FALSE, NULL); 1.218 + if (valid->data == NULL) return SECFailure; 1.219 + buf_length -= (valid->data-buf) + valid->len; 1.220 + buf = valid->data + valid->len; 1.221 + /*subject */ 1.222 + subject->data=nsslowcert_dataStart(buf,buf_length,&subject->len,PR_TRUE, NULL); 1.223 + if (subject->data == NULL) return SECFailure; 1.224 + buf_length -= (subject->data-buf) + subject->len; 1.225 + buf = subject->data + subject->len; 1.226 + /* subject key info */ 1.227 + subjkey->data=nsslowcert_dataStart(buf,buf_length,&subjkey->len,PR_TRUE, NULL); 1.228 + if (subjkey->data == NULL) return SECFailure; 1.229 + buf_length -= (subjkey->data-buf) + subjkey->len; 1.230 + buf = subjkey->data + subjkey->len; 1.231 + 1.232 + extensions->data = NULL; 1.233 + extensions->len = 0; 1.234 + while (buf_length > 0) { 1.235 + /* EXTENSIONS */ 1.236 + if (buf[0] == 0xa3) { 1.237 + extensions->data = nsslowcert_dataStart(buf,buf_length, 1.238 + &extensions->len, PR_FALSE, NULL); 1.239 + /* if the DER is bad, we should fail. Previously we accepted 1.240 + * bad DER here and treated the extension as missin */ 1.241 + if (extensions->data == NULL || 1.242 + (extensions->data - buf) + extensions->len != buf_length) 1.243 + return SECFailure; 1.244 + buf = extensions->data; 1.245 + buf_length = extensions->len; 1.246 + /* now parse the SEQUENCE holding the extensions. */ 1.247 + dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL); 1.248 + if (dummy == NULL || 1.249 + (dummy - buf) + dummylen != buf_length) 1.250 + return SECFailure; 1.251 + buf_length -= (dummy - buf); 1.252 + buf = dummy; 1.253 + /* Now parse the extensions inside this sequence */ 1.254 + } 1.255 + dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL); 1.256 + if (dummy == NULL) return SECFailure; 1.257 + buf_length -= (dummy - buf) + dummylen; 1.258 + buf = dummy + dummylen; 1.259 + } 1.260 + return SECSuccess; 1.261 +} 1.262 + 1.263 +static SECStatus 1.264 +nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter) 1.265 +{ 1.266 + int rv; 1.267 + NSSLOWCERTValidity validity; 1.268 + 1.269 + rv = nsslowcert_GetValidityFields(c->validity.data,c->validity.len, 1.270 + &validity.notBefore,&validity.notAfter); 1.271 + if (rv != SECSuccess) { 1.272 + return rv; 1.273 + } 1.274 + 1.275 + /* convert DER not-before time */ 1.276 + rv = DER_DecodeTimeChoice(notBefore, &validity.notBefore); 1.277 + if (rv) { 1.278 + return(SECFailure); 1.279 + } 1.280 + 1.281 + /* convert DER not-after time */ 1.282 + rv = DER_DecodeTimeChoice(notAfter, &validity.notAfter); 1.283 + if (rv) { 1.284 + return(SECFailure); 1.285 + } 1.286 + 1.287 + return(SECSuccess); 1.288 +} 1.289 + 1.290 +/* 1.291 + * is certa newer than certb? If one is expired, pick the other one. 1.292 + */ 1.293 +PRBool 1.294 +nsslowcert_IsNewer(NSSLOWCERTCertificate *certa, NSSLOWCERTCertificate *certb) 1.295 +{ 1.296 + PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now; 1.297 + SECStatus rv; 1.298 + PRBool newerbefore, newerafter; 1.299 + 1.300 + rv = nsslowcert_GetCertTimes(certa, ¬BeforeA, ¬AfterA); 1.301 + if ( rv != SECSuccess ) { 1.302 + return(PR_FALSE); 1.303 + } 1.304 + 1.305 + rv = nsslowcert_GetCertTimes(certb, ¬BeforeB, ¬AfterB); 1.306 + if ( rv != SECSuccess ) { 1.307 + return(PR_TRUE); 1.308 + } 1.309 + 1.310 + newerbefore = PR_FALSE; 1.311 + if ( LL_CMP(notBeforeA, >, notBeforeB) ) { 1.312 + newerbefore = PR_TRUE; 1.313 + } 1.314 + 1.315 + newerafter = PR_FALSE; 1.316 + if ( LL_CMP(notAfterA, >, notAfterB) ) { 1.317 + newerafter = PR_TRUE; 1.318 + } 1.319 + 1.320 + if ( newerbefore && newerafter ) { 1.321 + return(PR_TRUE); 1.322 + } 1.323 + 1.324 + if ( ( !newerbefore ) && ( !newerafter ) ) { 1.325 + return(PR_FALSE); 1.326 + } 1.327 + 1.328 + /* get current time */ 1.329 + now = PR_Now(); 1.330 + 1.331 + if ( newerbefore ) { 1.332 + /* cert A was issued after cert B, but expires sooner */ 1.333 + /* if A is expired, then pick B */ 1.334 + if ( LL_CMP(notAfterA, <, now ) ) { 1.335 + return(PR_FALSE); 1.336 + } 1.337 + return(PR_TRUE); 1.338 + } else { 1.339 + /* cert B was issued after cert A, but expires sooner */ 1.340 + /* if B is expired, then pick A */ 1.341 + if ( LL_CMP(notAfterB, <, now ) ) { 1.342 + return(PR_TRUE); 1.343 + } 1.344 + return(PR_FALSE); 1.345 + } 1.346 +} 1.347 + 1.348 +#define SOFT_DEFAULT_CHUNKSIZE 2048 1.349 + 1.350 +static SECStatus 1.351 +nsslowcert_KeyFromIssuerAndSN(PLArenaPool *arena, 1.352 + SECItem *issuer, SECItem *sn, SECItem *key) 1.353 +{ 1.354 + unsigned int len = sn->len + issuer->len; 1.355 + 1.356 + if (!arena) { 1.357 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.358 + goto loser; 1.359 + } 1.360 + if (len > NSS_MAX_LEGACY_DB_KEY_SIZE) { 1.361 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.362 + goto loser; 1.363 + } 1.364 + key->data = (unsigned char*)PORT_ArenaAlloc(arena, len); 1.365 + if ( !key->data ) { 1.366 + goto loser; 1.367 + } 1.368 + 1.369 + key->len = len; 1.370 + /* copy the serialNumber */ 1.371 + PORT_Memcpy(key->data, sn->data, sn->len); 1.372 + 1.373 + /* copy the issuer */ 1.374 + PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len); 1.375 + 1.376 + return(SECSuccess); 1.377 + 1.378 +loser: 1.379 + return(SECFailure); 1.380 +} 1.381 + 1.382 +static SECStatus 1.383 +nsslowcert_KeyFromIssuerAndSNStatic(unsigned char *space, 1.384 + int spaceLen, SECItem *issuer, SECItem *sn, SECItem *key) 1.385 +{ 1.386 + unsigned int len = sn->len + issuer->len; 1.387 + 1.388 + key->data = pkcs11_allocStaticData(len, space, spaceLen); 1.389 + if ( !key->data ) { 1.390 + goto loser; 1.391 + } 1.392 + 1.393 + key->len = len; 1.394 + /* copy the serialNumber */ 1.395 + PORT_Memcpy(key->data, sn->data, sn->len); 1.396 + 1.397 + /* copy the issuer */ 1.398 + PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len); 1.399 + 1.400 + return(SECSuccess); 1.401 + 1.402 +loser: 1.403 + return(SECFailure); 1.404 +} 1.405 + 1.406 + 1.407 +static char * 1.408 +nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len) 1.409 +{ 1.410 + unsigned char *buf; 1.411 + unsigned int buf_length; 1.412 + 1.413 + /* unwrap outer sequence */ 1.414 + buf=nsslowcert_dataStart(derDN->data,derDN->len,&buf_length,PR_FALSE,NULL); 1.415 + if (buf == NULL) return NULL; 1.416 + 1.417 + /* Walk each RDN */ 1.418 + while (buf_length > 0) { 1.419 + unsigned char *rdn; 1.420 + unsigned int rdn_length; 1.421 + 1.422 + /* grab next rdn */ 1.423 + rdn=nsslowcert_dataStart(buf, buf_length, &rdn_length, PR_FALSE, NULL); 1.424 + if (rdn == NULL) { return NULL; } 1.425 + buf_length -= (rdn - buf) + rdn_length; 1.426 + buf = rdn+rdn_length; 1.427 + 1.428 + while (rdn_length > 0) { 1.429 + unsigned char *ava; 1.430 + unsigned int ava_length; 1.431 + unsigned char *oid; 1.432 + unsigned int oid_length; 1.433 + unsigned char *name; 1.434 + unsigned int name_length; 1.435 + SECItem oidItem; 1.436 + SECOidTag type; 1.437 + 1.438 + /* unwrap the ava */ 1.439 + ava=nsslowcert_dataStart(rdn, rdn_length, &ava_length, PR_FALSE, 1.440 + NULL); 1.441 + if (ava == NULL) return NULL; 1.442 + rdn_length -= (ava-rdn)+ava_length; 1.443 + rdn = ava + ava_length; 1.444 + 1.445 + oid=nsslowcert_dataStart(ava, ava_length, &oid_length, PR_FALSE, 1.446 + NULL); 1.447 + if (oid == NULL) { return NULL; } 1.448 + ava_length -= (oid-ava)+oid_length; 1.449 + ava = oid+oid_length; 1.450 + 1.451 + name=nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE, 1.452 + NULL); 1.453 + if (oid == NULL) { return NULL; } 1.454 + ava_length -= (name-ava)+name_length; 1.455 + ava = name+name_length; 1.456 + 1.457 + oidItem.data = oid; 1.458 + oidItem.len = oid_length; 1.459 + type = SECOID_FindOIDTag(&oidItem); 1.460 + if ((type == SEC_OID_PKCS9_EMAIL_ADDRESS) || 1.461 + (type == SEC_OID_RFC1274_MAIL)) { 1.462 + /* Email is supposed to be IA5String, so no 1.463 + * translation necessary */ 1.464 + char *emailAddr; 1.465 + emailAddr = (char *)pkcs11_copyStaticData(name,name_length+1, 1.466 + (unsigned char *)space,len); 1.467 + if (emailAddr) { 1.468 + emailAddr[name_length] = 0; 1.469 + } 1.470 + return emailAddr; 1.471 + } 1.472 + } 1.473 + } 1.474 + return NULL; 1.475 +} 1.476 + 1.477 +static char * 1.478 +nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space, 1.479 + unsigned int len) 1.480 +{ 1.481 + unsigned char *exts; 1.482 + unsigned int exts_length; 1.483 + 1.484 + /* unwrap the sequence */ 1.485 + exts = nsslowcert_dataStart(cert->extensions.data, cert->extensions.len, 1.486 + &exts_length, PR_FALSE, NULL); 1.487 + /* loop through extension */ 1.488 + while (exts && exts_length > 0) { 1.489 + unsigned char * ext; 1.490 + unsigned int ext_length; 1.491 + unsigned char *oid; 1.492 + unsigned int oid_length; 1.493 + unsigned char *nameList; 1.494 + unsigned int nameList_length; 1.495 + SECItem oidItem; 1.496 + SECOidTag type; 1.497 + 1.498 + ext = nsslowcert_dataStart(exts, exts_length, &ext_length, 1.499 + PR_FALSE, NULL); 1.500 + if (ext == NULL) { break; } 1.501 + exts_length -= (ext - exts) + ext_length; 1.502 + exts = ext+ext_length; 1.503 + 1.504 + oid=nsslowcert_dataStart(ext, ext_length, &oid_length, PR_FALSE, NULL); 1.505 + if (oid == NULL) { break; } 1.506 + ext_length -= (oid - ext) + oid_length; 1.507 + ext = oid+oid_length; 1.508 + oidItem.data = oid; 1.509 + oidItem.len = oid_length; 1.510 + type = SECOID_FindOIDTag(&oidItem); 1.511 + 1.512 + /* get Alt Extension */ 1.513 + if (type != SEC_OID_X509_SUBJECT_ALT_NAME) { 1.514 + continue; 1.515 + } 1.516 + 1.517 + /* skip passed the critical flag */ 1.518 + if (ext[0] == 0x01) { /* BOOLEAN */ 1.519 + unsigned char *dummy; 1.520 + unsigned int dummy_length; 1.521 + dummy = nsslowcert_dataStart(ext, ext_length, &dummy_length, 1.522 + PR_FALSE, NULL); 1.523 + if (dummy == NULL) { break; } 1.524 + ext_length -= (dummy - ext) + dummy_length; 1.525 + ext = dummy+dummy_length; 1.526 + } 1.527 + 1.528 + 1.529 + /* unwrap the name list */ 1.530 + nameList = nsslowcert_dataStart(ext, ext_length, &nameList_length, 1.531 + PR_FALSE, NULL); 1.532 + if (nameList == NULL) { break; } 1.533 + ext_length -= (nameList - ext) + nameList_length; 1.534 + ext = nameList+nameList_length; 1.535 + nameList = nsslowcert_dataStart(nameList, nameList_length, 1.536 + &nameList_length, PR_FALSE, NULL); 1.537 + /* loop through the name list */ 1.538 + while (nameList && nameList_length > 0) { 1.539 + unsigned char *thisName; 1.540 + unsigned int thisName_length; 1.541 + 1.542 + thisName = nsslowcert_dataStart(nameList, nameList_length, 1.543 + &thisName_length, PR_FALSE, NULL); 1.544 + if (thisName == NULL) { break; } 1.545 + if (nameList[0] == 0xa2) { /* DNS Name */ 1.546 + SECItem dn; 1.547 + char *emailAddr; 1.548 + 1.549 + dn.data = thisName; 1.550 + dn.len = thisName_length; 1.551 + emailAddr = nsslowcert_EmailName(&dn, space, len); 1.552 + if (emailAddr) { 1.553 + return emailAddr; 1.554 + } 1.555 + } 1.556 + if (nameList[0] == 0x81) { /* RFC 822name */ 1.557 + char *emailAddr; 1.558 + emailAddr = (char *)pkcs11_copyStaticData(thisName, 1.559 + thisName_length+1, (unsigned char *)space,len); 1.560 + if (emailAddr) { 1.561 + emailAddr[thisName_length] = 0; 1.562 + } 1.563 + return emailAddr; 1.564 + } 1.565 + nameList_length -= (thisName-nameList) + thisName_length; 1.566 + nameList = thisName + thisName_length; 1.567 + } 1.568 + break; 1.569 + } 1.570 + return NULL; 1.571 +} 1.572 + 1.573 +static char * 1.574 +nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert) 1.575 +{ 1.576 + char *emailAddr = NULL; 1.577 + char *str; 1.578 + 1.579 + emailAddr = nsslowcert_EmailName(&cert->derSubject,cert->emailAddrSpace, 1.580 + sizeof(cert->emailAddrSpace)); 1.581 + /* couldn't find the email address in the DN, check the subject Alt name */ 1.582 + if (!emailAddr && cert->extensions.data) { 1.583 + emailAddr = nsslowcert_EmailAltName(cert, cert->emailAddrSpace, 1.584 + sizeof(cert->emailAddrSpace)); 1.585 + } 1.586 + 1.587 + 1.588 + /* make it lower case */ 1.589 + str = emailAddr; 1.590 + while ( str && *str ) { 1.591 + *str = tolower( *str ); 1.592 + str++; 1.593 + } 1.594 + return emailAddr; 1.595 + 1.596 +} 1.597 + 1.598 +/* 1.599 + * take a DER certificate and decode it into a certificate structure 1.600 + */ 1.601 +NSSLOWCERTCertificate * 1.602 +nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname) 1.603 +{ 1.604 + NSSLOWCERTCertificate *cert; 1.605 + int rv; 1.606 + 1.607 + /* allocate the certificate structure */ 1.608 + cert = nsslowcert_CreateCert(); 1.609 + 1.610 + if ( !cert ) { 1.611 + goto loser; 1.612 + } 1.613 + 1.614 + /* point to passed in DER data */ 1.615 + cert->derCert = *derSignedCert; 1.616 + cert->nickname = NULL; 1.617 + cert->certKey.data = NULL; 1.618 + cert->referenceCount = 1; 1.619 + 1.620 + /* decode the certificate info */ 1.621 + rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len, 1.622 + &cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject, 1.623 + &cert->validity, &cert->derSubjKeyInfo, &cert->extensions); 1.624 + 1.625 + if (rv != SECSuccess) { 1.626 + goto loser; 1.627 + } 1.628 + 1.629 + /* cert->subjectKeyID; x509v3 subject key identifier */ 1.630 + cert->subjectKeyID.data = NULL; 1.631 + cert->subjectKeyID.len = 0; 1.632 + cert->dbEntry = NULL; 1.633 + cert ->trust = NULL; 1.634 + cert ->dbhandle = NULL; 1.635 + 1.636 + /* generate and save the database key for the cert */ 1.637 + rv = nsslowcert_KeyFromIssuerAndSNStatic(cert->certKeySpace, 1.638 + sizeof(cert->certKeySpace), &cert->derIssuer, 1.639 + &cert->serialNumber, &cert->certKey); 1.640 + if ( rv ) { 1.641 + goto loser; 1.642 + } 1.643 + 1.644 + /* set the nickname */ 1.645 + if ( nickname == NULL ) { 1.646 + cert->nickname = NULL; 1.647 + } else { 1.648 + /* copy and install the nickname */ 1.649 + cert->nickname = pkcs11_copyNickname(nickname,cert->nicknameSpace, 1.650 + sizeof(cert->nicknameSpace)); 1.651 + } 1.652 + 1.653 +#ifdef FIXME 1.654 + /* initialize the subjectKeyID */ 1.655 + rv = cert_GetKeyID(cert); 1.656 + if ( rv != SECSuccess ) { 1.657 + goto loser; 1.658 + } 1.659 +#endif 1.660 + 1.661 + /* set the email address */ 1.662 + cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert); 1.663 + 1.664 + 1.665 + cert->referenceCount = 1; 1.666 + 1.667 + return(cert); 1.668 + 1.669 +loser: 1.670 + if (cert) { 1.671 + nsslowcert_DestroyCertificate(cert); 1.672 + } 1.673 + 1.674 + return(0); 1.675 +} 1.676 + 1.677 +char * 1.678 +nsslowcert_FixupEmailAddr(char *emailAddr) 1.679 +{ 1.680 + char *retaddr; 1.681 + char *str; 1.682 + 1.683 + if ( emailAddr == NULL ) { 1.684 + return(NULL); 1.685 + } 1.686 + 1.687 + /* copy the string */ 1.688 + str = retaddr = PORT_Strdup(emailAddr); 1.689 + if ( str == NULL ) { 1.690 + return(NULL); 1.691 + } 1.692 + 1.693 + /* make it lower case */ 1.694 + while ( *str ) { 1.695 + *str = tolower( *str ); 1.696 + str++; 1.697 + } 1.698 + 1.699 + return(retaddr); 1.700 +} 1.701 + 1.702 + 1.703 +/* 1.704 + * Generate a database key, based on serial number and issuer, from a 1.705 + * DER certificate. 1.706 + */ 1.707 +SECStatus 1.708 +nsslowcert_KeyFromDERCert(PLArenaPool *arena, SECItem *derCert, SECItem *key) 1.709 +{ 1.710 + int rv; 1.711 + NSSLOWCERTCertKey certkey; 1.712 + 1.713 + PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey)); 1.714 + 1.715 + rv = nsslowcert_GetCertFields(derCert->data, derCert->len, 1.716 + &certkey.derIssuer, &certkey.serialNumber, NULL, NULL, 1.717 + NULL, NULL, NULL); 1.718 + 1.719 + if ( rv ) { 1.720 + goto loser; 1.721 + } 1.722 + 1.723 + return(nsslowcert_KeyFromIssuerAndSN(arena, &certkey.derIssuer, 1.724 + &certkey.serialNumber, key)); 1.725 +loser: 1.726 + return(SECFailure); 1.727 +} 1.728 + 1.729 +NSSLOWKEYPublicKey * 1.730 +nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *cert) 1.731 +{ 1.732 + NSSLOWCERTSubjectPublicKeyInfo spki; 1.733 + NSSLOWKEYPublicKey *pubk; 1.734 + SECItem os; 1.735 + SECStatus rv; 1.736 + PLArenaPool *arena; 1.737 + SECOidTag tag; 1.738 + SECItem newDerSubjKeyInfo; 1.739 + 1.740 + arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); 1.741 + if (arena == NULL) 1.742 + return NULL; 1.743 + 1.744 + pubk = (NSSLOWKEYPublicKey *) 1.745 + PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPublicKey)); 1.746 + if (pubk == NULL) { 1.747 + PORT_FreeArena (arena, PR_FALSE); 1.748 + return NULL; 1.749 + } 1.750 + 1.751 + pubk->arena = arena; 1.752 + PORT_Memset(&spki,0,sizeof(spki)); 1.753 + 1.754 + /* copy the DER into the arena, since Quick DER returns data that points 1.755 + into the DER input, which may get freed by the caller */ 1.756 + rv = SECITEM_CopyItem(arena, &newDerSubjKeyInfo, &cert->derSubjKeyInfo); 1.757 + if ( rv != SECSuccess ) { 1.758 + PORT_FreeArena (arena, PR_FALSE); 1.759 + return NULL; 1.760 + } 1.761 + 1.762 + /* we haven't bothered decoding the spki struct yet, do it now */ 1.763 + rv = SEC_QuickDERDecodeItem(arena, &spki, 1.764 + nsslowcert_SubjectPublicKeyInfoTemplate, &newDerSubjKeyInfo); 1.765 + if (rv != SECSuccess) { 1.766 + PORT_FreeArena (arena, PR_FALSE); 1.767 + return NULL; 1.768 + } 1.769 + 1.770 + /* Convert bit string length from bits to bytes */ 1.771 + os = spki.subjectPublicKey; 1.772 + DER_ConvertBitString (&os); 1.773 + 1.774 + tag = SECOID_GetAlgorithmTag(&spki.algorithm); 1.775 + switch ( tag ) { 1.776 + case SEC_OID_X500_RSA_ENCRYPTION: 1.777 + case SEC_OID_PKCS1_RSA_ENCRYPTION: 1.778 + pubk->keyType = NSSLOWKEYRSAKey; 1.779 + prepare_low_rsa_pub_key_for_asn1(pubk); 1.780 + rv = SEC_QuickDERDecodeItem(arena, pubk, 1.781 + nsslowcert_RSAPublicKeyTemplate, &os); 1.782 + if (rv == SECSuccess) 1.783 + return pubk; 1.784 + break; 1.785 + case SEC_OID_ANSIX9_DSA_SIGNATURE: 1.786 + pubk->keyType = NSSLOWKEYDSAKey; 1.787 + prepare_low_dsa_pub_key_for_asn1(pubk); 1.788 + rv = SEC_QuickDERDecodeItem(arena, pubk, 1.789 + nsslowcert_DSAPublicKeyTemplate, &os); 1.790 + if (rv == SECSuccess) return pubk; 1.791 + break; 1.792 + case SEC_OID_X942_DIFFIE_HELMAN_KEY: 1.793 + pubk->keyType = NSSLOWKEYDHKey; 1.794 + prepare_low_dh_pub_key_for_asn1(pubk); 1.795 + rv = SEC_QuickDERDecodeItem(arena, pubk, 1.796 + nsslowcert_DHPublicKeyTemplate, &os); 1.797 + if (rv == SECSuccess) return pubk; 1.798 + break; 1.799 +#ifndef NSS_DISABLE_ECC 1.800 + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: 1.801 + pubk->keyType = NSSLOWKEYECKey; 1.802 + /* Since PKCS#11 directly takes the DER encoding of EC params 1.803 + * and public value, we don't need any decoding here. 1.804 + */ 1.805 + rv = SECITEM_CopyItem(arena, &pubk->u.ec.ecParams.DEREncoding, 1.806 + &spki.algorithm.parameters); 1.807 + if ( rv != SECSuccess ) 1.808 + break; 1.809 + 1.810 + /* Fill out the rest of the ecParams structure 1.811 + * based on the encoded params 1.812 + */ 1.813 + if (LGEC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding, 1.814 + &pubk->u.ec.ecParams) != SECSuccess) 1.815 + break; 1.816 + 1.817 + rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &os); 1.818 + if (rv == SECSuccess) return pubk; 1.819 + break; 1.820 +#endif /* NSS_DISABLE_ECC */ 1.821 + default: 1.822 + rv = SECFailure; 1.823 + break; 1.824 + } 1.825 + 1.826 + lg_nsslowkey_DestroyPublicKey (pubk); 1.827 + return NULL; 1.828 +} 1.829 +