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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial