certhigh.c (33086B)
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 #include "nspr.h" 5 #include "secerr.h" 6 #include "secasn1.h" 7 #include "seccomon.h" 8 #include "pk11func.h" 9 #include "certdb.h" 10 #include "certt.h" 11 #include "cert.h" 12 #include "certxutl.h" 13 14 #include "certi.h" 15 #include "nsspki.h" 16 #include "pki.h" 17 #include "pkit.h" 18 #include "pkitm.h" 19 #include "pki3hack.h" 20 21 PRBool 22 CERT_MatchNickname(char *name1, char *name2) 23 { 24 char *nickname1 = NULL; 25 char *nickname2 = NULL; 26 char *token1; 27 char *token2; 28 29 /* first deal with the straight comparison */ 30 if (PORT_Strcmp(name1, name2) == 0) { 31 return PR_TRUE; 32 } 33 /* we need to handle the case where one name has an explicit token and the other 34 * doesn't */ 35 token1 = PORT_Strchr(name1, ':'); 36 token2 = PORT_Strchr(name2, ':'); 37 if ((token1 && token2) || (!token1 && !token2)) { 38 /* either both token names are specified or neither are, not match */ 39 return PR_FALSE; 40 } 41 if (token1) { 42 nickname1 = token1; 43 nickname2 = name2; 44 } else { 45 nickname1 = token2; 46 nickname2 = name1; 47 } 48 nickname1++; 49 if (PORT_Strcmp(nickname1, nickname2) != 0) { 50 return PR_FALSE; 51 } 52 /* Bug 1192443 - compare the other token with the internal slot here */ 53 return PR_TRUE; 54 } 55 56 /* 57 * Find all user certificates that match the given criteria. 58 * 59 * "handle" - database to search 60 * "usage" - certificate usage to match 61 * "oneCertPerName" - if set then only return the "best" cert per 62 * name 63 * "validOnly" - only return certs that are curently valid 64 * "proto_win" - window handle passed to pkcs11 65 */ 66 CERTCertList * 67 CERT_FindUserCertsByUsage(CERTCertDBHandle *handle, 68 SECCertUsage usage, 69 PRBool oneCertPerName, 70 PRBool validOnly, 71 void *proto_win) 72 { 73 CERTCertNicknames *nicknames = NULL; 74 char **nnptr; 75 int nn; 76 CERTCertificate *cert = NULL; 77 CERTCertList *certList = NULL; 78 SECStatus rv; 79 PRTime time; 80 CERTCertListNode *node = NULL; 81 CERTCertListNode *freenode = NULL; 82 int n; 83 84 time = PR_Now(); 85 86 nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER, 87 proto_win); 88 89 if ((nicknames == NULL) || (nicknames->numnicknames == 0)) { 90 goto loser; 91 } 92 93 nnptr = nicknames->nicknames; 94 nn = nicknames->numnicknames; 95 96 while (nn > 0) { 97 cert = NULL; 98 /* use the pk11 call so that we pick up any certs on tokens, 99 * which may require login 100 */ 101 if (proto_win != NULL) { 102 cert = PK11_FindCertFromNickname(*nnptr, proto_win); 103 } 104 105 /* Sigh, It turns out if the cert is already in the temp db, because 106 * it's in the perm db, then the nickname lookup doesn't work. 107 * since we already have the cert here, though, than we can just call 108 * CERT_CreateSubjectCertList directly. For those cases where we didn't 109 * find the cert in pkcs #11 (because we didn't have a password arg, 110 * or because the nickname is for a peer, server, or CA cert, then we 111 * go look the cert up. 112 */ 113 if (cert == NULL) { 114 cert = CERT_FindCertByNickname(handle, *nnptr); 115 } 116 117 if (cert != NULL) { 118 /* collect certs for this nickname, sorting them into the list */ 119 certList = CERT_CreateSubjectCertList(certList, handle, 120 &cert->derSubject, time, validOnly); 121 122 CERT_FilterCertListForUserCerts(certList); 123 124 /* drop the extra reference */ 125 CERT_DestroyCertificate(cert); 126 } 127 128 nnptr++; 129 nn--; 130 } 131 132 /* remove certs with incorrect usage */ 133 rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); 134 135 if (rv != SECSuccess) { 136 goto loser; 137 } 138 139 /* remove any extra certs for each name */ 140 if (oneCertPerName) { 141 PRBool *flags; 142 143 nn = nicknames->numnicknames; 144 nnptr = nicknames->nicknames; 145 146 if (!certList) { 147 goto loser; 148 } 149 150 flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn); 151 if (flags == NULL) { 152 goto loser; 153 } 154 155 node = CERT_LIST_HEAD(certList); 156 157 /* treverse all certs in the list */ 158 while (!CERT_LIST_END(node, certList)) { 159 160 /* find matching nickname index */ 161 for (n = 0; n < nn; n++) { 162 if (CERT_MatchNickname(nnptr[n], node->cert->nickname)) { 163 /* We found a match. If this is the first one, then 164 * set the flag and move on to the next cert. If this 165 * is not the first one then delete it from the list. 166 */ 167 if (flags[n]) { 168 /* We have already seen a cert with this nickname, 169 * so delete this one. 170 */ 171 freenode = node; 172 node = CERT_LIST_NEXT(node); 173 CERT_RemoveCertListNode(freenode); 174 } else { 175 /* keep the first cert for each nickname, but set the 176 * flag so we know to delete any others with the same 177 * nickname. 178 */ 179 flags[n] = PR_TRUE; 180 node = CERT_LIST_NEXT(node); 181 } 182 break; 183 } 184 } 185 if (n == nn) { 186 /* if we get here it means that we didn't find a matching 187 * nickname, which should not happen. 188 */ 189 PORT_Assert(0); 190 node = CERT_LIST_NEXT(node); 191 } 192 } 193 PORT_Free(flags); 194 } 195 196 goto done; 197 198 loser: 199 if (certList != NULL) { 200 CERT_DestroyCertList(certList); 201 certList = NULL; 202 } 203 204 done: 205 if (nicknames != NULL) { 206 CERT_FreeNicknames(nicknames); 207 } 208 209 return (certList); 210 } 211 212 /* 213 * Find a user certificate that matchs the given criteria. 214 * 215 * "handle" - database to search 216 * "nickname" - nickname to match 217 * "usage" - certificate usage to match 218 * "validOnly" - only return certs that are curently valid 219 * "proto_win" - window handle passed to pkcs11 220 */ 221 CERTCertificate * 222 CERT_FindUserCertByUsage(CERTCertDBHandle *handle, 223 const char *nickname, 224 SECCertUsage usage, 225 PRBool validOnly, 226 void *proto_win) 227 { 228 CERTCertificate *cert = NULL; 229 CERTCertList *certList = NULL; 230 SECStatus rv; 231 PRTime time; 232 233 time = PR_Now(); 234 235 /* use the pk11 call so that we pick up any certs on tokens, 236 * which may require login 237 */ 238 /* XXX - why is this restricted? */ 239 if (proto_win != NULL) { 240 cert = PK11_FindCertFromNickname(nickname, proto_win); 241 } 242 243 /* sigh, There are still problems find smart cards from the temp 244 * db. This will get smart cards working again. The real fix 245 * is to make sure we can search the temp db by their token nickname. 246 */ 247 if (cert == NULL) { 248 cert = CERT_FindCertByNickname(handle, nickname); 249 } 250 251 if (cert != NULL) { 252 unsigned int requiredKeyUsage; 253 unsigned int requiredCertType; 254 255 rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE, 256 &requiredKeyUsage, &requiredCertType); 257 if (rv != SECSuccess) { 258 /* drop the extra reference */ 259 CERT_DestroyCertificate(cert); 260 cert = NULL; 261 goto loser; 262 } 263 /* If we already found the right cert, just return it */ 264 if ((!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE) == secCertTimeValid) && 265 (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) && 266 (cert->nsCertType & requiredCertType) && 267 CERT_IsUserCert(cert)) { 268 return (cert); 269 } 270 271 /* collect certs for this nickname, sorting them into the list */ 272 certList = CERT_CreateSubjectCertList(certList, handle, 273 &cert->derSubject, time, validOnly); 274 275 CERT_FilterCertListForUserCerts(certList); 276 277 /* drop the extra reference */ 278 CERT_DestroyCertificate(cert); 279 cert = NULL; 280 } 281 282 if (certList == NULL) { 283 goto loser; 284 } 285 286 /* remove certs with incorrect usage */ 287 rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); 288 289 if (rv != SECSuccess) { 290 goto loser; 291 } 292 293 if (!CERT_LIST_EMPTY(certList)) { 294 cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert); 295 } 296 297 loser: 298 if (certList != NULL) { 299 CERT_DestroyCertList(certList); 300 } 301 302 return (cert); 303 } 304 305 CERTCertList * 306 CERT_MatchUserCert(CERTCertDBHandle *handle, 307 SECCertUsage usage, 308 int nCANames, char **caNames, 309 void *proto_win) 310 { 311 CERTCertList *certList = NULL; 312 SECStatus rv; 313 314 certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE, 315 proto_win); 316 if (certList == NULL) { 317 goto loser; 318 } 319 320 rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage); 321 if (rv != SECSuccess) { 322 goto loser; 323 } 324 325 goto done; 326 327 loser: 328 if (certList != NULL) { 329 CERT_DestroyCertList(certList); 330 certList = NULL; 331 } 332 333 done: 334 335 return (certList); 336 } 337 338 typedef struct stringNode { 339 struct stringNode *next; 340 char *string; 341 } stringNode; 342 343 static PRStatus 344 CollectNicknames(NSSCertificate *c, void *data) 345 { 346 CERTCertNicknames *names; 347 PRBool saveit = PR_FALSE; 348 stringNode *node; 349 int len; 350 #ifdef notdef 351 NSSTrustDomain *td; 352 NSSTrust *trust; 353 #endif 354 char *stanNickname; 355 char *nickname = NULL; 356 357 names = (CERTCertNicknames *)data; 358 359 stanNickname = nssCertificate_GetNickname(c, NULL); 360 361 if (stanNickname) { 362 nss_ZFreeIf(stanNickname); 363 stanNickname = NULL; 364 if (names->what == SEC_CERT_NICKNAMES_USER) { 365 saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL); 366 } 367 #ifdef notdef 368 else { 369 td = NSSCertificate_GetTrustDomain(c); 370 if (!td) { 371 return PR_SUCCESS; 372 } 373 trust = nssTrustDomain_FindTrustForCertificate(td, c); 374 375 switch (names->what) { 376 case SEC_CERT_NICKNAMES_ALL: 377 if ((trust->sslFlags & (CERTDB_VALID_CA | CERTDB_VALID_PEER)) || 378 (trust->emailFlags & (CERTDB_VALID_CA | CERTDB_VALID_PEER)) || 379 (trust->objectSigningFlags & 380 (CERTDB_VALID_CA | CERTDB_VALID_PEER))) { 381 saveit = PR_TRUE; 382 } 383 384 break; 385 case SEC_CERT_NICKNAMES_SERVER: 386 if (trust->sslFlags & CERTDB_VALID_PEER) { 387 saveit = PR_TRUE; 388 } 389 390 break; 391 case SEC_CERT_NICKNAMES_CA: 392 if (((trust->sslFlags & CERTDB_VALID_CA) == CERTDB_VALID_CA) || 393 ((trust->emailFlags & CERTDB_VALID_CA) == CERTDB_VALID_CA) || 394 ((trust->objectSigningFlags & CERTDB_VALID_CA) == 395 CERTDB_VALID_CA)) { 396 saveit = PR_TRUE; 397 } 398 break; 399 } 400 } 401 #endif 402 } 403 404 /* traverse the list of collected nicknames and make sure we don't make 405 * a duplicate 406 */ 407 if (saveit) { 408 nickname = STAN_GetCERTCertificateName(NULL, c); 409 /* nickname can only be NULL here if we are having memory 410 * alloc problems */ 411 if (nickname == NULL) { 412 return PR_FAILURE; 413 } 414 node = (stringNode *)names->head; 415 while (node != NULL) { 416 if (PORT_Strcmp(nickname, node->string) == 0) { 417 /* if the string matches, then don't save this one */ 418 saveit = PR_FALSE; 419 break; 420 } 421 node = node->next; 422 } 423 } 424 425 if (saveit) { 426 427 /* allocate the node */ 428 node = (stringNode *)PORT_ArenaAlloc(names->arena, sizeof(stringNode)); 429 if (node == NULL) { 430 PORT_Free(nickname); 431 return PR_FAILURE; 432 } 433 434 /* copy the string */ 435 len = PORT_Strlen(nickname) + 1; 436 node->string = (char *)PORT_ArenaAlloc(names->arena, len); 437 if (node->string == NULL) { 438 PORT_Free(nickname); 439 return PR_FAILURE; 440 } 441 PORT_Memcpy(node->string, nickname, len); 442 443 /* link it into the list */ 444 node->next = (stringNode *)names->head; 445 names->head = (void *)node; 446 447 /* bump the count */ 448 names->numnicknames++; 449 } 450 451 if (nickname) 452 PORT_Free(nickname); 453 return (PR_SUCCESS); 454 } 455 456 CERTCertNicknames * 457 CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx) 458 { 459 PLArenaPool *arena; 460 CERTCertNicknames *names; 461 int i; 462 stringNode *node; 463 464 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 465 if (arena == NULL) { 466 PORT_SetError(SEC_ERROR_NO_MEMORY); 467 return (NULL); 468 } 469 470 names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); 471 if (names == NULL) { 472 goto loser; 473 } 474 475 names->arena = arena; 476 names->head = NULL; 477 names->numnicknames = 0; 478 names->nicknames = NULL; 479 names->what = what; 480 names->totallen = 0; 481 482 /* make sure we are logged in */ 483 (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx); 484 485 NSSTrustDomain_TraverseCertificates(handle, 486 CollectNicknames, (void *)names); 487 if (names->numnicknames) { 488 names->nicknames = (char **)PORT_ArenaAlloc(arena, 489 names->numnicknames * 490 sizeof(char *)); 491 492 if (names->nicknames == NULL) { 493 goto loser; 494 } 495 496 node = (stringNode *)names->head; 497 498 for (i = 0; i < names->numnicknames; i++) { 499 PORT_Assert(node != NULL); 500 501 names->nicknames[i] = node->string; 502 names->totallen += PORT_Strlen(node->string); 503 node = node->next; 504 } 505 506 PORT_Assert(node == NULL); 507 } 508 509 return (names); 510 511 loser: 512 PORT_FreeArena(arena, PR_FALSE); 513 return (NULL); 514 } 515 516 void 517 CERT_FreeNicknames(CERTCertNicknames *nicknames) 518 { 519 PORT_FreeArena(nicknames->arena, PR_FALSE); 520 521 return; 522 } 523 524 /* [ FROM pcertdb.c ] */ 525 526 typedef struct dnameNode { 527 struct dnameNode *next; 528 SECItem name; 529 } dnameNode; 530 531 void 532 CERT_FreeDistNames(CERTDistNames *names) 533 { 534 PORT_FreeArena(names->arena, PR_FALSE); 535 536 return; 537 } 538 539 static SECStatus 540 CollectDistNames(CERTCertificate *cert, SECItem *k, void *data) 541 { 542 CERTDistNames *names; 543 PRBool saveit = PR_FALSE; 544 CERTCertTrust trust; 545 dnameNode *node; 546 int len; 547 548 names = (CERTDistNames *)data; 549 550 if (CERT_GetCertTrust(cert, &trust) == SECSuccess) { 551 /* only collect names of CAs trusted for issuing SSL clients */ 552 if (trust.sslFlags & CERTDB_TRUSTED_CLIENT_CA) { 553 saveit = PR_TRUE; 554 } 555 } 556 557 if (saveit) { 558 /* allocate the node */ 559 node = (dnameNode *)PORT_ArenaAlloc(names->arena, sizeof(dnameNode)); 560 if (node == NULL) { 561 return (SECFailure); 562 } 563 564 /* copy the name */ 565 node->name.len = len = cert->derSubject.len; 566 node->name.type = siBuffer; 567 node->name.data = (unsigned char *)PORT_ArenaAlloc(names->arena, len); 568 if (node->name.data == NULL) { 569 return (SECFailure); 570 } 571 PORT_Memcpy(node->name.data, cert->derSubject.data, len); 572 573 /* link it into the list */ 574 node->next = (dnameNode *)names->head; 575 names->head = (void *)node; 576 577 /* bump the count */ 578 names->nnames++; 579 } 580 581 return (SECSuccess); 582 } 583 584 /* 585 * Return all of the CAs that are "trusted" for SSL. 586 */ 587 CERTDistNames * 588 CERT_DupDistNames(CERTDistNames *orig) 589 { 590 PLArenaPool *arena; 591 CERTDistNames *names; 592 int i; 593 SECStatus rv; 594 595 /* allocate an arena to use */ 596 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 597 if (arena == NULL) { 598 PORT_SetError(SEC_ERROR_NO_MEMORY); 599 return (NULL); 600 } 601 602 /* allocate the header structure */ 603 names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames)); 604 if (names == NULL) { 605 goto loser; 606 } 607 608 /* initialize the header struct */ 609 names->arena = arena; 610 names->head = NULL; 611 names->nnames = orig->nnames; 612 names->names = NULL; 613 614 /* construct the array from the list */ 615 if (orig->nnames) { 616 names->names = (SECItem *)PORT_ArenaNewArray(arena, SECItem, 617 orig->nnames); 618 if (names->names == NULL) { 619 goto loser; 620 } 621 for (i = 0; i < orig->nnames; i++) { 622 rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]); 623 if (rv != SECSuccess) { 624 goto loser; 625 } 626 } 627 } 628 return (names); 629 630 loser: 631 PORT_FreeArena(arena, PR_FALSE); 632 return (NULL); 633 } 634 635 CERTDistNames * 636 CERT_GetSSLCACerts(CERTCertDBHandle *handle) 637 { 638 PLArenaPool *arena; 639 CERTDistNames *names; 640 int i; 641 SECStatus rv; 642 dnameNode *node; 643 644 /* allocate an arena to use */ 645 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 646 if (arena == NULL) { 647 PORT_SetError(SEC_ERROR_NO_MEMORY); 648 return (NULL); 649 } 650 651 /* allocate the header structure */ 652 names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames)); 653 if (names == NULL) { 654 goto loser; 655 } 656 657 /* initialize the header struct */ 658 names->arena = arena; 659 names->head = NULL; 660 names->nnames = 0; 661 names->names = NULL; 662 663 /* collect the names from the database */ 664 rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL); 665 if (rv) { 666 goto loser; 667 } 668 669 /* construct the array from the list */ 670 if (names->nnames) { 671 names->names = (SECItem *)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem)); 672 673 if (names->names == NULL) { 674 goto loser; 675 } 676 677 node = (dnameNode *)names->head; 678 679 for (i = 0; i < names->nnames; i++) { 680 PORT_Assert(node != NULL); 681 682 names->names[i] = node->name; 683 node = node->next; 684 } 685 686 PORT_Assert(node == NULL); 687 } 688 689 return (names); 690 691 loser: 692 PORT_FreeArena(arena, PR_FALSE); 693 return (NULL); 694 } 695 696 CERTDistNames * 697 CERT_DistNamesFromCertList(CERTCertList *certList) 698 { 699 CERTDistNames *dnames = NULL; 700 PLArenaPool *arena; 701 CERTCertListNode *node = NULL; 702 SECItem *names = NULL; 703 int listLen = 0, i = 0; 704 705 if (certList == NULL) { 706 PORT_SetError(SEC_ERROR_INVALID_ARGS); 707 return NULL; 708 } 709 710 node = CERT_LIST_HEAD(certList); 711 while (!CERT_LIST_END(node, certList)) { 712 listLen += 1; 713 node = CERT_LIST_NEXT(node); 714 } 715 716 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 717 if (arena == NULL) 718 goto loser; 719 dnames = PORT_ArenaZNew(arena, CERTDistNames); 720 if (dnames == NULL) 721 goto loser; 722 723 dnames->arena = arena; 724 dnames->nnames = listLen; 725 dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen); 726 if (names == NULL) 727 goto loser; 728 729 node = CERT_LIST_HEAD(certList); 730 while (!CERT_LIST_END(node, certList)) { 731 CERTCertificate *cert = node->cert; 732 SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject); 733 if (rv == SECFailure) { 734 goto loser; 735 } 736 node = CERT_LIST_NEXT(node); 737 } 738 return dnames; 739 loser: 740 if (arena) { 741 PORT_FreeArena(arena, PR_FALSE); 742 } 743 return NULL; 744 } 745 746 CERTDistNames * 747 CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames, 748 int nnames) 749 { 750 CERTDistNames *dnames = NULL; 751 PLArenaPool *arena; 752 int i, rv; 753 SECItem *names = NULL; 754 CERTCertificate *cert = NULL; 755 756 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 757 if (arena == NULL) 758 goto loser; 759 dnames = PORT_ArenaZNew(arena, CERTDistNames); 760 if (dnames == NULL) 761 goto loser; 762 763 dnames->arena = arena; 764 dnames->nnames = nnames; 765 dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames); 766 if (names == NULL) 767 goto loser; 768 769 for (i = 0; i < nnames; i++) { 770 cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]); 771 if (cert == NULL) 772 goto loser; 773 rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject); 774 if (rv == SECFailure) 775 goto loser; 776 CERT_DestroyCertificate(cert); 777 } 778 return dnames; 779 780 loser: 781 if (cert != NULL) 782 CERT_DestroyCertificate(cert); 783 if (arena != NULL) 784 PORT_FreeArena(arena, PR_FALSE); 785 return NULL; 786 } 787 788 /* [ from pcertdb.c - calls Ascii to Name ] */ 789 /* 790 * Lookup a certificate in the database by name 791 */ 792 CERTCertificate * 793 CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr) 794 { 795 CERTName *name; 796 SECItem *nameItem; 797 CERTCertificate *cert = NULL; 798 PLArenaPool *arena = NULL; 799 800 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 801 802 if (arena == NULL) { 803 goto loser; 804 } 805 806 name = CERT_AsciiToName(nameStr); 807 808 if (name) { 809 nameItem = SEC_ASN1EncodeItem(arena, NULL, (void *)name, 810 CERT_NameTemplate); 811 if (nameItem != NULL) { 812 cert = CERT_FindCertByName(handle, nameItem); 813 } 814 CERT_DestroyName(name); 815 } 816 817 loser: 818 if (arena) { 819 PORT_FreeArena(arena, PR_FALSE); 820 } 821 822 return (cert); 823 } 824 825 /* From certv3.c */ 826 827 CERTCrlDistributionPoints * 828 CERT_FindCRLDistributionPoints(CERTCertificate *cert) 829 { 830 SECItem encodedExtenValue; 831 SECStatus rv; 832 CERTCrlDistributionPoints *dps; 833 834 encodedExtenValue.data = NULL; 835 encodedExtenValue.len = 0; 836 837 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS, 838 &encodedExtenValue); 839 if (rv != SECSuccess) { 840 return (NULL); 841 } 842 843 dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue); 844 845 PORT_Free(encodedExtenValue.data); 846 847 return dps; 848 } 849 850 /* From crl.c */ 851 CERTSignedCrl * 852 CERT_ImportCRL(CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx) 853 { 854 CERTSignedCrl *retCrl = NULL; 855 PK11SlotInfo *slot = PK11_GetInternalKeySlot(); 856 retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx, 857 CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS); 858 PK11_FreeSlot(slot); 859 860 return retCrl; 861 } 862 863 /* From certdb.c */ 864 static SECStatus 865 cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted) 866 { 867 SECStatus rv; 868 SECItem *derCert; 869 CERTCertificate *cert = NULL; 870 CERTCertificate *newcert = NULL; 871 CERTCertDBHandle *handle; 872 CERTCertTrust trust; 873 PRBool isca; 874 char *nickname; 875 unsigned int certtype; 876 PRBool istemp = PR_FALSE; 877 878 handle = CERT_GetDefaultCertDB(); 879 880 while (numcerts--) { 881 derCert = certs; 882 certs++; 883 884 /* decode my certificate */ 885 /* This use is ok -- only looks at decoded parts, calls NewTemp later */ 886 newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); 887 if (newcert == NULL) { 888 goto loser; 889 } 890 891 if (!trusted) { 892 /* make sure that cert is valid */ 893 rv = CERT_CertTimesValid(newcert); 894 if (rv == SECFailure) { 895 goto endloop; 896 } 897 } 898 899 /* does it have the CA extension */ 900 901 /* 902 * Make sure that if this is an intermediate CA in the chain that 903 * it was given permission by its signer to be a CA. 904 */ 905 isca = CERT_IsCACert(newcert, &certtype); 906 907 if (!isca) { 908 if (!trusted) { 909 goto endloop; 910 } 911 trust.sslFlags = CERTDB_VALID_CA; 912 trust.emailFlags = CERTDB_VALID_CA; 913 trust.objectSigningFlags = CERTDB_VALID_CA; 914 } else { 915 /* SSL ca's must have the ssl bit set */ 916 if ((certUsage == certUsageSSLCA) && 917 ((certtype & NS_CERT_TYPE_SSL_CA) != NS_CERT_TYPE_SSL_CA)) { 918 goto endloop; 919 } 920 921 /* it passed all of the tests, so lets add it to the database */ 922 /* mark it as a CA */ 923 PORT_Memset((void *)&trust, 0, sizeof(trust)); 924 switch (certUsage) { 925 case certUsageSSLCA: 926 trust.sslFlags = CERTDB_VALID_CA; 927 break; 928 case certUsageUserCertImport: 929 if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { 930 trust.sslFlags = CERTDB_VALID_CA; 931 } 932 if ((certtype & NS_CERT_TYPE_EMAIL_CA) == 933 NS_CERT_TYPE_EMAIL_CA) { 934 trust.emailFlags = CERTDB_VALID_CA; 935 } 936 if ((certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA) == 937 NS_CERT_TYPE_OBJECT_SIGNING_CA) { 938 trust.objectSigningFlags = CERTDB_VALID_CA; 939 } 940 break; 941 default: 942 PORT_Assert(0); 943 break; 944 } 945 } 946 947 cert = CERT_NewTempCertificate(handle, derCert, NULL, 948 PR_FALSE, PR_FALSE); 949 if (cert == NULL) { 950 goto loser; 951 } 952 953 /* if the cert is temp, make it perm; otherwise we're done */ 954 rv = CERT_GetCertIsTemp(cert, &istemp); 955 if (rv != SECSuccess) { 956 goto loser; 957 } 958 if (istemp) { 959 /* get a default nickname for it */ 960 nickname = CERT_MakeCANickname(cert); 961 962 rv = CERT_AddTempCertToPerm(cert, nickname, &trust); 963 964 /* free the nickname */ 965 if (nickname) { 966 PORT_Free(nickname); 967 } 968 } else { 969 rv = SECSuccess; 970 } 971 972 if (rv != SECSuccess) { 973 goto loser; 974 } 975 976 endloop: 977 if (newcert) { 978 CERT_DestroyCertificate(newcert); 979 newcert = NULL; 980 } 981 } 982 983 rv = SECSuccess; 984 goto done; 985 loser: 986 rv = SECFailure; 987 done: 988 989 if (newcert) { 990 CERT_DestroyCertificate(newcert); 991 newcert = NULL; 992 } 993 994 if (cert) { 995 CERT_DestroyCertificate(cert); 996 cert = NULL; 997 } 998 999 return (rv); 1000 } 1001 1002 SECStatus 1003 CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage) 1004 { 1005 return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE); 1006 } 1007 1008 SECStatus 1009 CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) 1010 { 1011 return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE); 1012 } 1013 1014 /* Moved from certdb.c */ 1015 /* 1016 ** CERT_CertChainFromCert 1017 ** 1018 ** Construct a CERTCertificateList consisting of the given certificate and all 1019 ** of the issuer certs until we either get to a self-signed cert or can't find 1020 ** an issuer. Since we don't know how many certs are in the chain we have to 1021 ** build a linked list first as we count them. 1022 */ 1023 1024 typedef struct certNode { 1025 struct certNode *next; 1026 CERTCertificate *cert; 1027 } certNode; 1028 1029 CERTCertificateList * 1030 CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage, 1031 PRBool includeRoot) 1032 { 1033 CERTCertificateList *chain = NULL; 1034 NSSCertificate **stanChain; 1035 NSSCertificate *stanCert; 1036 PLArenaPool *arena; 1037 NSSUsage nssUsage; 1038 int i, len; 1039 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); 1040 NSSCryptoContext *cc = STAN_GetDefaultCryptoContext(); 1041 1042 stanCert = STAN_GetNSSCertificate(cert); 1043 if (!stanCert) { 1044 /* error code is set */ 1045 return NULL; 1046 } 1047 nssUsage.anyUsage = PR_FALSE; 1048 nssUsage.nss3usage = usage; 1049 nssUsage.nss3lookingForCA = PR_FALSE; 1050 stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL, 1051 CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc); 1052 if (!stanChain) { 1053 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); 1054 return NULL; 1055 } 1056 1057 len = 0; 1058 stanCert = stanChain[0]; 1059 while (stanCert) { 1060 stanCert = stanChain[++len]; 1061 } 1062 1063 arena = PORT_NewArena(4096); 1064 if (arena == NULL) { 1065 goto loser; 1066 } 1067 1068 chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, 1069 sizeof(CERTCertificateList)); 1070 if (!chain) 1071 goto loser; 1072 chain->certs = (SECItem *)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); 1073 if (!chain->certs) 1074 goto loser; 1075 i = 0; 1076 stanCert = stanChain[i]; 1077 while (stanCert) { 1078 SECItem derCert; 1079 CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); 1080 if (!cCert) { 1081 goto loser; 1082 } 1083 derCert.len = (unsigned int)stanCert->encoding.size; 1084 derCert.data = (unsigned char *)stanCert->encoding.data; 1085 derCert.type = siBuffer; 1086 if (SECITEM_CopyItem(arena, &chain->certs[i], &derCert) != SECSuccess) { 1087 CERT_DestroyCertificate(cCert); 1088 goto loser; 1089 } 1090 stanCert = stanChain[++i]; 1091 if (!stanCert && !cCert->isRoot) { 1092 /* reached the end of the chain, but the final cert is 1093 * not a root. Don't discard it. 1094 */ 1095 includeRoot = PR_TRUE; 1096 } 1097 CERT_DestroyCertificate(cCert); 1098 } 1099 if (!includeRoot && len > 1) { 1100 chain->len = len - 1; 1101 } else { 1102 chain->len = len; 1103 } 1104 1105 chain->arena = arena; 1106 nss_ZFreeIf(stanChain); 1107 return chain; 1108 loser: 1109 i = 0; 1110 stanCert = stanChain[i]; 1111 while (stanCert) { 1112 CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); 1113 if (cCert) { 1114 CERT_DestroyCertificate(cCert); 1115 } 1116 stanCert = stanChain[++i]; 1117 } 1118 nss_ZFreeIf(stanChain); 1119 if (arena) { 1120 PORT_FreeArena(arena, PR_FALSE); 1121 } 1122 return NULL; 1123 } 1124 1125 /* Builds a CERTCertificateList holding just one DER-encoded cert, namely 1126 ** the one for the cert passed as an argument. 1127 */ 1128 CERTCertificateList * 1129 CERT_CertListFromCert(CERTCertificate *cert) 1130 { 1131 CERTCertificateList *chain = NULL; 1132 int rv; 1133 PLArenaPool *arena; 1134 1135 /* arena for SecCertificateList */ 1136 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1137 if (arena == NULL) 1138 goto no_memory; 1139 1140 /* build the CERTCertificateList */ 1141 chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList)); 1142 if (chain == NULL) 1143 goto no_memory; 1144 chain->certs = (SECItem *)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem)); 1145 if (chain->certs == NULL) 1146 goto no_memory; 1147 rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert)); 1148 if (rv < 0) 1149 goto loser; 1150 chain->len = 1; 1151 chain->arena = arena; 1152 1153 return chain; 1154 1155 no_memory: 1156 PORT_SetError(SEC_ERROR_NO_MEMORY); 1157 loser: 1158 if (arena != NULL) { 1159 PORT_FreeArena(arena, PR_FALSE); 1160 } 1161 return NULL; 1162 } 1163 1164 CERTCertificateList * 1165 CERT_DupCertList(const CERTCertificateList *oldList) 1166 { 1167 CERTCertificateList *newList = NULL; 1168 PLArenaPool *arena = NULL; 1169 SECItem *newItem; 1170 SECItem *oldItem; 1171 int len = oldList->len; 1172 int rv; 1173 1174 /* arena for SecCertificateList */ 1175 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1176 if (arena == NULL) 1177 goto no_memory; 1178 1179 /* now build the CERTCertificateList */ 1180 newList = PORT_ArenaNew(arena, CERTCertificateList); 1181 if (newList == NULL) 1182 goto no_memory; 1183 newList->arena = arena; 1184 newItem = (SECItem *)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); 1185 if (newItem == NULL) 1186 goto no_memory; 1187 newList->certs = newItem; 1188 newList->len = len; 1189 1190 for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) { 1191 rv = SECITEM_CopyItem(arena, newItem, oldItem); 1192 if (rv < 0) 1193 goto loser; 1194 } 1195 return newList; 1196 1197 no_memory: 1198 PORT_SetError(SEC_ERROR_NO_MEMORY); 1199 loser: 1200 if (arena != NULL) { 1201 PORT_FreeArena(arena, PR_FALSE); 1202 } 1203 return NULL; 1204 } 1205 1206 void 1207 CERT_DestroyCertificateList(CERTCertificateList *list) 1208 { 1209 PORT_FreeArena(list->arena, PR_FALSE); 1210 }