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