certext.c (73874B)
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 ** certext.c 7 ** 8 ** part of certutil for managing certificates extensions 9 ** 10 */ 11 #include <stdio.h> 12 #include <string.h> 13 #include <stdlib.h> 14 15 #if defined(WIN32) 16 #include "fcntl.h" 17 #include "io.h" 18 #endif 19 20 #include "secutil.h" 21 22 #if defined(XP_UNIX) 23 #include <unistd.h> 24 #endif 25 26 #include "cert.h" 27 #include "xconst.h" 28 #include "prprf.h" 29 #include "certutil.h" 30 #include "genname.h" 31 #include "prnetdb.h" 32 33 #define GEN_BREAK(e) \ 34 rv = e; \ 35 break; 36 37 static char * 38 Gets_s(char *buff, size_t size) 39 { 40 char *str; 41 42 if (buff == NULL || size < 1) { 43 PORT_Assert(0); 44 return NULL; 45 } 46 if ((str = fgets(buff, size, stdin)) != NULL) { 47 int len = PORT_Strlen(str); 48 /* 49 * fgets() automatically converts native text file 50 * line endings to '\n'. As defensive programming 51 * (just in case fgets has a bug or we put stdin in 52 * binary mode by mistake), we handle three native 53 * text file line endings here: 54 * '\n' Unix (including Linux and Mac OS X) 55 * '\r''\n' DOS/Windows & OS/2 56 * '\r' Mac OS Classic 57 * len can not be less then 1, since in case with 58 * empty string it has at least '\n' in the buffer 59 */ 60 if (buff[len - 1] == '\n' || buff[len - 1] == '\r') { 61 buff[len - 1] = '\0'; 62 if (len > 1 && buff[len - 2] == '\r') 63 buff[len - 2] = '\0'; 64 } 65 } else { 66 buff[0] = '\0'; 67 } 68 return str; 69 } 70 71 static SECStatus 72 PrintChoicesAndGetAnswer(char *str, char *rBuff, int rSize) 73 { 74 fputs(str, stdout); 75 fputs(" > ", stdout); 76 fflush(stdout); 77 if (Gets_s(rBuff, rSize) == NULL) { 78 PORT_SetError(SEC_ERROR_INPUT_LEN); 79 return SECFailure; 80 } 81 return SECSuccess; 82 } 83 84 static CERTGeneralName * 85 GetGeneralName(PLArenaPool *arena, CERTGeneralName *useExistingName, PRBool onlyOne) 86 { 87 CERTGeneralName *namesList = NULL; 88 CERTGeneralName *current; 89 CERTGeneralName *tail = NULL; 90 SECStatus rv = SECSuccess; 91 int intValue; 92 char buffer[512]; 93 void *mark; 94 95 PORT_Assert(arena); 96 mark = PORT_ArenaMark(arena); 97 do { 98 if (PrintChoicesAndGetAnswer( 99 "\nSelect one of the following general name type: \n" 100 "\t2 - rfc822Name\n" 101 "\t3 - dnsName\n" 102 "\t5 - directoryName\n" 103 "\t7 - uniformResourceidentifier\n" 104 "\t8 - ipAddress\n" 105 "\t9 - registerID\n" 106 "\tAny other number to finish\n" 107 "\t\tChoice:", 108 buffer, sizeof(buffer)) == SECFailure) { 109 GEN_BREAK(SECFailure); 110 } 111 intValue = PORT_Atoi(buffer); 112 /* 113 * Should use ZAlloc instead of Alloc to avoid problem with garbage 114 * initialized pointers in CERT_CopyName 115 */ 116 switch (intValue) { 117 case certRFC822Name: 118 case certDNSName: 119 case certDirectoryName: 120 case certURI: 121 case certIPAddress: 122 case certRegisterID: 123 break; 124 default: 125 intValue = 0; /* force a break for anything else */ 126 } 127 128 if (intValue == 0) 129 break; 130 131 if (namesList == NULL) { 132 if (useExistingName) { 133 namesList = current = tail = useExistingName; 134 } else { 135 namesList = current = tail = 136 PORT_ArenaZNew(arena, CERTGeneralName); 137 } 138 } else { 139 current = PORT_ArenaZNew(arena, CERTGeneralName); 140 } 141 if (current == NULL) { 142 GEN_BREAK(SECFailure); 143 } 144 145 current->type = intValue; 146 puts("\nEnter data:"); 147 fflush(stdout); 148 if (Gets_s(buffer, sizeof(buffer)) == NULL) { 149 PORT_SetError(SEC_ERROR_INPUT_LEN); 150 GEN_BREAK(SECFailure); 151 } 152 switch (current->type) { 153 case certURI: 154 case certDNSName: 155 case certRFC822Name: 156 current->name.other.data = 157 PORT_ArenaAlloc(arena, strlen(buffer)); 158 if (current->name.other.data == NULL) { 159 GEN_BREAK(SECFailure); 160 } 161 PORT_Memcpy(current->name.other.data, buffer, 162 current->name.other.len = strlen(buffer)); 163 break; 164 165 case certEDIPartyName: 166 case certIPAddress: 167 case certOtherName: 168 case certRegisterID: 169 case certX400Address: { 170 171 current->name.other.data = 172 PORT_ArenaAlloc(arena, strlen(buffer) + 2); 173 if (current->name.other.data == NULL) { 174 GEN_BREAK(SECFailure); 175 } 176 177 PORT_Memcpy(current->name.other.data + 2, buffer, 178 strlen(buffer)); 179 /* This may not be accurate for all cases. For now, 180 * use this tag type */ 181 current->name.other.data[0] = 182 (char)(((current->type - 1) & 0x1f) | 0x80); 183 current->name.other.data[1] = (char)strlen(buffer); 184 current->name.other.len = strlen(buffer) + 2; 185 break; 186 } 187 188 case certDirectoryName: { 189 CERTName *directoryName = NULL; 190 191 directoryName = CERT_AsciiToName(buffer); 192 if (!directoryName) { 193 fprintf(stderr, "certutil: improperly formatted name: " 194 "\"%s\"\n", 195 buffer); 196 break; 197 } 198 199 rv = CERT_CopyName(arena, ¤t->name.directoryName, 200 directoryName); 201 CERT_DestroyName(directoryName); 202 203 break; 204 } 205 } 206 if (rv != SECSuccess) 207 break; 208 current->l.next = &(namesList->l); 209 current->l.prev = &(tail->l); 210 tail->l.next = &(current->l); 211 tail = current; 212 213 } while (!onlyOne); 214 215 if (rv != SECSuccess) { 216 PORT_ArenaRelease(arena, mark); 217 namesList = NULL; 218 } 219 return (namesList); 220 } 221 222 static CERTGeneralName * 223 CreateGeneralName(PLArenaPool *arena) 224 { 225 return GetGeneralName(arena, NULL, PR_FALSE); 226 } 227 228 static SECStatus 229 GetString(PLArenaPool *arena, char *prompt, SECItem *value) 230 { 231 char buffer[251]; 232 char *buffPrt; 233 234 buffer[0] = '\0'; 235 value->data = NULL; 236 value->len = 0; 237 238 puts(prompt); 239 buffPrt = Gets_s(buffer, sizeof(buffer)); 240 /* returned NULL here treated the same way as empty string */ 241 if (buffPrt && strlen(buffer) > 0) { 242 value->data = PORT_ArenaAlloc(arena, strlen(buffer)); 243 if (value->data == NULL) { 244 PORT_SetError(SEC_ERROR_NO_MEMORY); 245 return (SECFailure); 246 } 247 PORT_Memcpy(value->data, buffer, value->len = strlen(buffer)); 248 } 249 return (SECSuccess); 250 } 251 252 static PRBool 253 GetYesNo(char *prompt) 254 { 255 char buf[3]; 256 char *buffPrt; 257 258 buf[0] = 'n'; 259 puts(prompt); 260 buffPrt = Gets_s(buf, sizeof(buf)); 261 return (buffPrt && (buf[0] == 'y' || buf[0] == 'Y')) ? PR_TRUE : PR_FALSE; 262 } 263 264 /* Parses comma separated values out of the string pointed by nextPos. 265 * Parsed value is compared to an array of possible values(valueArray). 266 * If match is found, a value index is returned, otherwise returns SECFailue. 267 * nextPos is set to the token after found comma separator or to NULL. 268 * NULL in nextPos should be used as indication of the last parsed token. 269 * A special value "critical" can be parsed out from the supplied sting.*/ 270 271 static SECStatus 272 parseNextCmdInput(const char *const *valueArray, int *value, char **nextPos, 273 PRBool *critical) 274 { 275 char *thisPos; 276 int keyLen = 0; 277 int arrIndex = 0; 278 279 if (!valueArray || !value || !nextPos || !critical) { 280 PORT_SetError(SEC_ERROR_INVALID_ARGS); 281 return SECFailure; 282 } 283 *critical = PR_FALSE; 284 thisPos = *nextPos; 285 while (1) { 286 if ((*nextPos = strchr(thisPos, ',')) == NULL) { 287 keyLen = strlen(thisPos); 288 } else { 289 keyLen = *nextPos - thisPos; 290 *nextPos += 1; 291 } 292 /* if critical keyword is found, return without setting value */ 293 if (!strncmp("critical", thisPos, keyLen)) { 294 *critical = PR_TRUE; 295 return SECSuccess; 296 } 297 break; 298 } 299 for (arrIndex = 0; valueArray[arrIndex]; arrIndex++) { 300 if (!strncmp(valueArray[arrIndex], thisPos, keyLen)) { 301 *value = arrIndex; 302 return SECSuccess; 303 } 304 } 305 PORT_SetError(SEC_ERROR_INVALID_ARGS); 306 return SECFailure; 307 } 308 309 static const char *const 310 keyUsageKeyWordArray[] = { "digitalSignature", 311 "nonRepudiation", 312 "keyEncipherment", 313 "dataEncipherment", 314 "keyAgreement", 315 "certSigning", 316 "crlSigning", 317 NULL }; 318 319 static SECStatus 320 parseKeyUsage(const char *const *wordArray, const char *userSuppliedValue, 321 unsigned char *keyUsage, PRBool *isCriticalExt) 322 { 323 int value = 0; 324 char *nextPos = (char *)userSuppliedValue; 325 PRBool readCriticalToken; 326 while (1) { 327 if (parseNextCmdInput(wordArray, &value, &nextPos, 328 &readCriticalToken) == SECFailure) { 329 return SECFailure; 330 } 331 if (readCriticalToken == PR_TRUE) { 332 *isCriticalExt = PR_TRUE; 333 } else { 334 *keyUsage |= (0x80 >> value); 335 } 336 if (!nextPos) 337 break; 338 } 339 return SECSuccess; 340 } 341 342 static SECStatus 343 AddKeyUsage(void *extHandle, const char *userSuppliedValue) 344 { 345 SECItem bitStringValue; 346 unsigned char keyUsage = 0x0; 347 char buffer[5]; 348 int value; 349 PRBool isCriticalExt = PR_FALSE; 350 351 if (!userSuppliedValue) { 352 while (1) { 353 if (PrintChoicesAndGetAnswer( 354 "\t\t0 - Digital Signature\n" 355 "\t\t1 - Non-repudiation\n" 356 "\t\t2 - Key encipherment\n" 357 "\t\t3 - Data encipherment\n" 358 "\t\t4 - Key agreement\n" 359 "\t\t5 - Cert signing key\n" 360 "\t\t6 - CRL signing key\n" 361 "\t\tOther to finish\n", 362 buffer, sizeof(buffer)) == SECFailure) { 363 return SECFailure; 364 } 365 value = PORT_Atoi(buffer); 366 if (value < 0 || value > 6) 367 break; 368 if (value == 0) { 369 /* Checking that zero value of variable 'value' 370 * corresponds to '0' input made by user */ 371 char *chPtr = strchr(buffer, '0'); 372 if (chPtr == NULL) { 373 continue; 374 } 375 } 376 keyUsage |= (0x80 >> value); 377 } 378 isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); 379 } else { 380 SECStatus rv = parseKeyUsage(keyUsageKeyWordArray, userSuppliedValue, 381 &keyUsage, &isCriticalExt); 382 if (rv != SECSuccess) { 383 return rv; 384 } 385 } 386 387 bitStringValue.data = &keyUsage; 388 bitStringValue.len = 1; 389 390 return (CERT_EncodeAndAddBitStrExtension(extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue, 391 isCriticalExt)); 392 } 393 394 static CERTOidSequence * 395 CreateOidSequence(void) 396 { 397 CERTOidSequence *rv = (CERTOidSequence *)NULL; 398 PLArenaPool *arena = (PLArenaPool *)NULL; 399 400 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 401 if ((PLArenaPool *)NULL == arena) { 402 goto loser; 403 } 404 405 rv = (CERTOidSequence *)PORT_ArenaZNew(arena, CERTOidSequence); 406 if ((CERTOidSequence *)NULL == rv) { 407 goto loser; 408 } 409 410 rv->oids = (SECItem **)PORT_ArenaZNew(arena, SECItem *); 411 if ((SECItem **)NULL == rv->oids) { 412 goto loser; 413 } 414 415 rv->arena = arena; 416 return rv; 417 418 loser: 419 if ((PLArenaPool *)NULL != arena) { 420 PORT_FreeArena(arena, PR_FALSE); 421 } 422 423 return (CERTOidSequence *)NULL; 424 } 425 426 static void 427 DestroyOidSequence(CERTOidSequence *os) 428 { 429 if (os->arena) { 430 PORT_FreeArena(os->arena, PR_FALSE); 431 } 432 } 433 434 static SECStatus 435 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag) 436 { 437 SECItem **oids; 438 PRUint32 count = 0; 439 SECOidData *od; 440 441 od = SECOID_FindOIDByTag(oidTag); 442 if ((SECOidData *)NULL == od) { 443 return SECFailure; 444 } 445 446 for (oids = os->oids; (SECItem *)NULL != *oids; oids++) { 447 if (*oids == &od->oid) { 448 /* We already have this oid */ 449 return SECSuccess; 450 } 451 count++; 452 } 453 454 /* ArenaZRealloc */ 455 456 { 457 PRUint32 i; 458 459 oids = (SECItem **)PORT_ArenaZNewArray(os->arena, SECItem *, count + 2); 460 if ((SECItem **)NULL == oids) { 461 return SECFailure; 462 } 463 464 for (i = 0; i < count; i++) { 465 oids[i] = os->oids[i]; 466 } 467 468 /* ArenaZFree(os->oids); */ 469 } 470 471 os->oids = oids; 472 os->oids[count] = &od->oid; 473 474 return SECSuccess; 475 } 476 477 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) 478 479 const SEC_ASN1Template CERT_OidSeqTemplate[] = { 480 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, offsetof(CERTOidSequence, oids), 481 SEC_ASN1_SUB(SEC_ObjectIDTemplate) } 482 }; 483 484 static SECItem * 485 EncodeOidSequence(CERTOidSequence *os) 486 { 487 SECItem *rv; 488 489 rv = (SECItem *)PORT_ArenaZNew(os->arena, SECItem); 490 if ((SECItem *)NULL == rv) { 491 goto loser; 492 } 493 494 if (!SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate)) { 495 goto loser; 496 } 497 498 return rv; 499 500 loser: 501 return (SECItem *)NULL; 502 } 503 504 static const char *const 505 extKeyUsageKeyWordArray[] = { "serverAuth", 506 "clientAuth", 507 "codeSigning", 508 "emailProtection", 509 "timeStamp", 510 "ocspResponder", 511 "stepUp", 512 "msTrustListSigning", 513 "x509Any", 514 "ipsecIKE", 515 "ipsecIKEEnd", 516 "ipsecIKEIntermediate", 517 "ipsecEnd", 518 "ipsecTunnel", 519 "ipsecUser", 520 NULL }; 521 522 static SECStatus 523 AddExtKeyUsage(void *extHandle, const char *userSuppliedValue) 524 { 525 char buffer[5]; 526 int value; 527 CERTOidSequence *os; 528 SECStatus rv; 529 SECItem *item; 530 PRBool isCriticalExt = PR_FALSE; 531 char *nextPos = (char *)userSuppliedValue; 532 533 os = CreateOidSequence(); 534 if ((CERTOidSequence *)NULL == os) { 535 return SECFailure; 536 } 537 538 while (1) { 539 if (!userSuppliedValue) { 540 /* 541 * none of the 'new' extended key usage options work with the prompted menu. This is so 542 * old scripts can continue to work. 543 */ 544 if (PrintChoicesAndGetAnswer( 545 "\t\t0 - Server Auth\n" 546 "\t\t1 - Client Auth\n" 547 "\t\t2 - Code Signing\n" 548 "\t\t3 - Email Protection\n" 549 "\t\t4 - Timestamp\n" 550 "\t\t5 - OCSP Responder\n" 551 "\t\t6 - Step-up\n" 552 "\t\t7 - Microsoft Trust List Signing\n" 553 "\t\tOther to finish\n", 554 buffer, sizeof(buffer)) == SECFailure) { 555 GEN_BREAK(SECFailure); 556 } 557 value = PORT_Atoi(buffer); 558 559 if (value == 0) { 560 /* Checking that zero value of variable 'value' 561 * corresponds to '0' input made by user */ 562 char *chPtr = strchr(buffer, '0'); 563 if (chPtr == NULL) { 564 continue; 565 } 566 } 567 } else { 568 PRBool readCriticalToken = PR_FALSE; 569 if (parseNextCmdInput(extKeyUsageKeyWordArray, &value, &nextPos, 570 &readCriticalToken) == SECFailure) { 571 return SECFailure; 572 } 573 if (readCriticalToken == PR_TRUE) { 574 isCriticalExt = PR_TRUE; 575 if (!nextPos) { 576 goto endloop; 577 } 578 continue; 579 } 580 } 581 582 switch (value) { 583 case 0: 584 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH); 585 break; 586 case 1: 587 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH); 588 break; 589 case 2: 590 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN); 591 break; 592 case 3: 593 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT); 594 break; 595 case 4: 596 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP); 597 break; 598 case 5: 599 rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER); 600 break; 601 case 6: 602 rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED); 603 break; 604 case 7: 605 rv = AddOidToSequence(os, SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING); 606 break; 607 /* 608 * These new usages can only be added explicitly by the userSuppliedValues. This allows old 609 * scripts which used '>7' as an exit value to continue to work. 610 */ 611 case 8: 612 if (!userSuppliedValue) 613 goto endloop; 614 rv = AddOidToSequence(os, SEC_OID_X509_ANY_EXT_KEY_USAGE); 615 break; 616 case 9: 617 if (!userSuppliedValue) 618 goto endloop; 619 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_IKE); 620 break; 621 case 10: 622 if (!userSuppliedValue) 623 goto endloop; 624 rv = AddOidToSequence(os, SEC_OID_IPSEC_IKE_END); 625 break; 626 case 11: 627 if (!userSuppliedValue) 628 goto endloop; 629 rv = AddOidToSequence(os, SEC_OID_IPSEC_IKE_INTERMEDIATE); 630 break; 631 case 12: 632 if (!userSuppliedValue) 633 goto endloop; 634 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_END); 635 break; 636 case 13: 637 if (!userSuppliedValue) 638 goto endloop; 639 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL); 640 break; 641 case 14: 642 if (!userSuppliedValue) 643 goto endloop; 644 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_USER); 645 break; 646 default: 647 goto endloop; 648 } 649 650 if (userSuppliedValue && !nextPos) 651 break; 652 if (SECSuccess != rv) 653 goto loser; 654 } 655 656 endloop: 657 item = EncodeOidSequence(os); 658 659 if (!userSuppliedValue) { 660 isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); 661 } 662 663 rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item, 664 isCriticalExt, PR_TRUE); 665 /*FALLTHROUGH*/ 666 loser: 667 DestroyOidSequence(os); 668 return rv; 669 } 670 671 static const char *const 672 nsCertTypeKeyWordArray[] = { "sslClient", 673 "sslServer", 674 "smime", 675 "objectSigning", 676 "Not!Used", 677 "sslCA", 678 "smimeCA", 679 "objectSigningCA", 680 NULL }; 681 682 static SECStatus 683 AddNscpCertType(void *extHandle, const char *userSuppliedValue) 684 { 685 SECItem bitStringValue; 686 unsigned char keyUsage = 0x0; 687 char buffer[5]; 688 int value; 689 PRBool isCriticalExt = PR_FALSE; 690 691 if (!userSuppliedValue) { 692 while (1) { 693 if (PrintChoicesAndGetAnswer( 694 "\t\t0 - SSL Client\n" 695 "\t\t1 - SSL Server\n" 696 "\t\t2 - S/MIME\n" 697 "\t\t3 - Object Signing\n" 698 "\t\t4 - Reserved for future use\n" 699 "\t\t5 - SSL CA\n" 700 "\t\t6 - S/MIME CA\n" 701 "\t\t7 - Object Signing CA\n" 702 "\t\tOther to finish\n", 703 buffer, sizeof(buffer)) == SECFailure) { 704 return SECFailure; 705 } 706 value = PORT_Atoi(buffer); 707 if (value < 0 || value > 7) 708 break; 709 if (value == 0) { 710 /* Checking that zero value of variable 'value' 711 * corresponds to '0' input made by user */ 712 char *chPtr = strchr(buffer, '0'); 713 if (chPtr == NULL) { 714 continue; 715 } 716 } 717 keyUsage |= (0x80 >> value); 718 } 719 isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); 720 } else { 721 SECStatus rv = parseKeyUsage(nsCertTypeKeyWordArray, userSuppliedValue, 722 &keyUsage, &isCriticalExt); 723 if (rv != SECSuccess) { 724 return rv; 725 } 726 } 727 728 bitStringValue.data = &keyUsage; 729 bitStringValue.len = 1; 730 731 return (CERT_EncodeAndAddBitStrExtension(extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue, 732 isCriticalExt)); 733 } 734 735 SECStatus 736 GetOidFromString(PLArenaPool *arena, SECItem *to, 737 const char *from, size_t fromLen) 738 { 739 SECStatus rv; 740 SECOidTag tag; 741 SECOidData *coid; 742 743 /* try dotted form first */ 744 rv = SEC_StringToOID(arena, to, from, fromLen); 745 if (rv == SECSuccess) { 746 return rv; 747 } 748 749 /* Check to see if it matches a name in our oid table. */ 750 tag = SECOID_FindOIDTagFromDescripton(from, fromLen, PR_FALSE); 751 if (tag == SEC_OID_UNKNOWN) { 752 /* none found */ 753 return SECFailure; 754 } 755 756 coid = SECOID_FindOIDByTag(tag); 757 return SECITEM_CopyItem(arena, to, &coid->oid); 758 } 759 760 static SECStatus 761 AddSubjectAltNames(PLArenaPool *arena, CERTGeneralName **existingListp, 762 const char *constNames, CERTGeneralNameType type) 763 { 764 CERTGeneralName *nameList = NULL; 765 CERTGeneralName *current = NULL; 766 PRCList *prev = NULL; 767 char *cp, *nextName = NULL; 768 SECStatus rv = SECSuccess; 769 PRBool readTypeFromName = (PRBool)(type == 0); 770 char *names = NULL; 771 772 if (constNames) 773 names = PORT_Strdup(constNames); 774 775 if (names == NULL) { 776 return SECFailure; 777 } 778 779 /* 780 * walk down the comma separated list of names. NOTE: there is 781 * no sanity checks to see if the email address look like 782 * email addresses. 783 * 784 * Each name may optionally be prefixed with a type: string. 785 * If it isn't, the type from the previous name will be used. 786 * If there wasn't a previous name yet, the type given 787 * as a parameter to this function will be used. 788 * If the type value is zero (undefined), we'll fail. 789 */ 790 for (cp = names; cp; cp = nextName) { 791 int len; 792 char *oidString; 793 char *nextComma; 794 CERTName *name; 795 PRStatus status; 796 unsigned char *data; 797 PRNetAddr addr; 798 799 nextName = NULL; 800 if (*cp == ',') { 801 cp++; 802 } 803 nextComma = PORT_Strchr(cp, ','); 804 if (nextComma) { 805 *nextComma = 0; 806 nextName = nextComma + 1; 807 } 808 if ((*cp) == 0) { 809 continue; 810 } 811 if (readTypeFromName) { 812 char *save = cp; 813 /* Because we already replaced nextComma with end-of-string, 814 * a found colon belongs to the current name */ 815 cp = PORT_Strchr(cp, ':'); 816 if (cp) { 817 *cp = 0; 818 cp++; 819 type = CERT_GetGeneralNameTypeFromString(save); 820 if (*cp == 0) { 821 continue; 822 } 823 } else { 824 if (type == 0) { 825 /* no type known yet */ 826 rv = SECFailure; 827 break; 828 } 829 cp = save; 830 } 831 } 832 833 current = PORT_ArenaZNew(arena, CERTGeneralName); 834 if (!current) { 835 rv = SECFailure; 836 break; 837 } 838 839 current->type = type; 840 switch (type) { 841 /* string types */ 842 case certRFC822Name: 843 case certDNSName: 844 case certURI: 845 current->name.other.data = 846 (unsigned char *)PORT_ArenaStrdup(arena, cp); 847 current->name.other.len = PORT_Strlen(cp); 848 break; 849 /* unformated data types */ 850 case certX400Address: 851 case certEDIPartyName: 852 /* turn a string into a data and len */ 853 rv = SECFailure; /* punt on these for now */ 854 fprintf(stderr, "EDI Party Name and X.400 Address not supported\n"); 855 break; 856 case certDirectoryName: 857 /* certDirectoryName */ 858 name = CERT_AsciiToName(cp); 859 if (name == NULL) { 860 rv = SECFailure; 861 fprintf(stderr, "Invalid Directory Name (\"%s\")\n", cp); 862 break; 863 } 864 rv = CERT_CopyName(arena, ¤t->name.directoryName, name); 865 CERT_DestroyName(name); 866 break; 867 /* types that require more processing */ 868 case certIPAddress: 869 /* convert the string to an ip address */ 870 status = PR_StringToNetAddr(cp, &addr); 871 if (status != PR_SUCCESS) { 872 rv = SECFailure; 873 fprintf(stderr, "Invalid IP Address (\"%s\")\n", cp); 874 break; 875 } 876 877 if (PR_NetAddrFamily(&addr) == PR_AF_INET) { 878 len = sizeof(addr.inet.ip); 879 data = (unsigned char *)&addr.inet.ip; 880 } else if (PR_NetAddrFamily(&addr) == PR_AF_INET6) { 881 len = sizeof(addr.ipv6.ip); 882 data = (unsigned char *)&addr.ipv6.ip; 883 } else { 884 fprintf(stderr, "Invalid IP Family\n"); 885 rv = SECFailure; 886 break; 887 } 888 current->name.other.data = PORT_ArenaAlloc(arena, len); 889 if (current->name.other.data == NULL) { 890 rv = SECFailure; 891 break; 892 } 893 current->name.other.len = len; 894 PORT_Memcpy(current->name.other.data, data, len); 895 break; 896 case certRegisterID: 897 rv = GetOidFromString(arena, ¤t->name.other, cp, strlen(cp)); 898 break; 899 case certOtherName: 900 oidString = cp; 901 cp = PORT_Strchr(cp, ';'); 902 if (cp == NULL) { 903 rv = SECFailure; 904 fprintf(stderr, "missing name in other name\n"); 905 break; 906 } 907 *cp++ = 0; 908 current->name.OthName.name.data = 909 (unsigned char *)PORT_ArenaStrdup(arena, cp); 910 if (current->name.OthName.name.data == NULL) { 911 rv = SECFailure; 912 break; 913 } 914 current->name.OthName.name.len = PORT_Strlen(cp); 915 rv = GetOidFromString(arena, ¤t->name.OthName.oid, 916 oidString, strlen(oidString)); 917 break; 918 default: 919 rv = SECFailure; 920 fprintf(stderr, "Missing or invalid Subject Alternate Name type\n"); 921 break; 922 } 923 if (rv == SECFailure) { 924 break; 925 } 926 927 if (prev) { 928 current->l.prev = prev; 929 prev->next = &(current->l); 930 } else { 931 nameList = current; 932 } 933 prev = &(current->l); 934 } 935 PORT_Free(names); 936 /* at this point nameList points to the head of a doubly linked, 937 * but not yet circular, list and current points to its tail. */ 938 if (rv == SECSuccess && nameList) { 939 if (*existingListp != NULL) { 940 PRCList *existingprev; 941 /* add nameList to the end of the existing list */ 942 existingprev = (*existingListp)->l.prev; 943 (*existingListp)->l.prev = &(current->l); 944 nameList->l.prev = existingprev; 945 existingprev->next = &(nameList->l); 946 current->l.next = &((*existingListp)->l); 947 } else { 948 /* make nameList circular and set it as the new existingList */ 949 nameList->l.prev = prev; 950 current->l.next = &(nameList->l); 951 *existingListp = nameList; 952 } 953 } 954 return rv; 955 } 956 957 static SECStatus 958 AddEmailSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, 959 const char *emailAddrs) 960 { 961 return AddSubjectAltNames(arena, existingListp, emailAddrs, 962 certRFC822Name); 963 } 964 965 static SECStatus 966 AddDNSSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, 967 const char *dnsNames) 968 { 969 return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName); 970 } 971 972 static SECStatus 973 AddGeneralSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, 974 const char *altNames) 975 { 976 return AddSubjectAltNames(arena, existingListp, altNames, 0); 977 } 978 979 static SECStatus 980 AddBasicConstraint(PLArenaPool *arena, void *extHandle) 981 { 982 CERTBasicConstraints basicConstraint; 983 SECStatus rv; 984 char buffer[10]; 985 PRBool yesNoAns; 986 987 do { 988 basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; 989 basicConstraint.isCA = GetYesNo("Is this a CA certificate [y/N]?"); 990 991 buffer[0] = '\0'; 992 if (PrintChoicesAndGetAnswer("Enter the path length constraint, " 993 "enter to skip [<0 for unlimited path]:", 994 buffer, sizeof(buffer)) == SECFailure) { 995 GEN_BREAK(SECFailure); 996 } 997 if (PORT_Strlen(buffer) > 0) 998 basicConstraint.pathLenConstraint = PORT_Atoi(buffer); 999 1000 yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1001 1002 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, 1003 &basicConstraint, yesNoAns, SEC_OID_X509_BASIC_CONSTRAINTS, 1004 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeBasicConstraintValue); 1005 } while (0); 1006 1007 return (rv); 1008 } 1009 1010 static SECStatus 1011 AddNameConstraints(void *extHandle) 1012 { 1013 PLArenaPool *arena = NULL; 1014 CERTNameConstraints *constraints = NULL; 1015 1016 CERTNameConstraint *current = NULL; 1017 CERTNameConstraint *last_permited = NULL; 1018 CERTNameConstraint *last_excluded = NULL; 1019 SECStatus rv = SECSuccess; 1020 1021 char buffer[512]; 1022 int intValue = 0; 1023 1024 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1025 if (arena) { 1026 constraints = PORT_ArenaZNew(arena, CERTNameConstraints); 1027 } 1028 1029 if (!arena || !constraints) { 1030 SECU_PrintError(progName, "out of memory"); 1031 PORT_FreeArena(arena, PR_FALSE); 1032 return SECFailure; 1033 } 1034 1035 constraints->permited = constraints->excluded = NULL; 1036 1037 do { 1038 current = PORT_ArenaZNew(arena, CERTNameConstraint); 1039 if (!current) { 1040 GEN_BREAK(SECFailure); 1041 } 1042 1043 if (!GetGeneralName(arena, ¤t->name, PR_TRUE)) { 1044 GEN_BREAK(SECFailure); 1045 } 1046 1047 if (PrintChoicesAndGetAnswer("Type of Name Constraint?\n" 1048 "\t1 - permitted\n\t2 - excluded\n\tAny" 1049 "other number to finish\n\tChoice", 1050 buffer, sizeof(buffer)) != 1051 SECSuccess) { 1052 GEN_BREAK(SECFailure); 1053 } 1054 1055 intValue = PORT_Atoi(buffer); 1056 switch (intValue) { 1057 case 1: 1058 if (constraints->permited == NULL) { 1059 constraints->permited = last_permited = current; 1060 } 1061 last_permited->l.next = &(current->l); 1062 current->l.prev = &(last_permited->l); 1063 last_permited = current; 1064 break; 1065 case 2: 1066 if (constraints->excluded == NULL) { 1067 constraints->excluded = last_excluded = current; 1068 } 1069 last_excluded->l.next = &(current->l); 1070 current->l.prev = &(last_excluded->l); 1071 last_excluded = current; 1072 break; 1073 } 1074 1075 PR_snprintf(buffer, sizeof(buffer), "Add another entry to the" 1076 " Name Constraint Extension [y/N]"); 1077 1078 if (GetYesNo(buffer) == 0) { 1079 break; 1080 } 1081 1082 } while (1); 1083 1084 if (rv == SECSuccess) { 1085 int oidIdent = SEC_OID_X509_NAME_CONSTRAINTS; 1086 1087 PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1088 1089 if (constraints->permited != NULL) { 1090 last_permited->l.next = &(constraints->permited->l); 1091 constraints->permited->l.prev = &(last_permited->l); 1092 } 1093 if (constraints->excluded != NULL) { 1094 last_excluded->l.next = &(constraints->excluded->l); 1095 constraints->excluded->l.prev = &(last_excluded->l); 1096 } 1097 1098 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, constraints, 1099 yesNoAns, oidIdent, 1100 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeNameConstraintsExtension); 1101 } 1102 if (arena) 1103 PORT_FreeArena(arena, PR_FALSE); 1104 return (rv); 1105 } 1106 1107 static SECStatus 1108 AddAuthKeyID(void *extHandle) 1109 { 1110 CERTAuthKeyID *authKeyID = NULL; 1111 PLArenaPool *arena = NULL; 1112 SECStatus rv = SECSuccess; 1113 PRBool yesNoAns; 1114 1115 do { 1116 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1117 if (!arena) { 1118 SECU_PrintError(progName, "out of memory"); 1119 GEN_BREAK(SECFailure); 1120 } 1121 1122 if (GetYesNo("Enter value for the authKeyID extension [y/N]?") == 0) 1123 break; 1124 1125 authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID); 1126 if (authKeyID == NULL) { 1127 GEN_BREAK(SECFailure); 1128 } 1129 1130 rv = GetString(arena, "Enter value for the key identifier fields," 1131 "enter to omit:", 1132 &authKeyID->keyID); 1133 if (rv != SECSuccess) 1134 break; 1135 1136 SECU_SECItemHexStringToBinary(&authKeyID->keyID); 1137 1138 authKeyID->authCertIssuer = CreateGeneralName(arena); 1139 if (authKeyID->authCertIssuer == NULL && 1140 SECFailure == PORT_GetError()) 1141 break; 1142 1143 rv = GetString(arena, "Enter value for the authCertSerial field, " 1144 "enter to omit:", 1145 &authKeyID->authCertSerialNumber); 1146 1147 yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1148 1149 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, 1150 authKeyID, yesNoAns, SEC_OID_X509_AUTH_KEY_ID, 1151 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeAuthKeyID); 1152 if (rv) 1153 break; 1154 1155 } while (0); 1156 if (arena) 1157 PORT_FreeArena(arena, PR_FALSE); 1158 return (rv); 1159 } 1160 1161 static SECStatus 1162 AddSubjKeyID(void *extHandle) 1163 { 1164 SECItem keyID; 1165 PLArenaPool *arena = NULL; 1166 SECStatus rv = SECSuccess; 1167 PRBool yesNoAns; 1168 1169 do { 1170 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1171 if (!arena) { 1172 SECU_PrintError(progName, "out of memory"); 1173 GEN_BREAK(SECFailure); 1174 } 1175 printf("Adding Subject Key ID extension.\n"); 1176 1177 rv = GetString(arena, "Enter value for the key identifier fields," 1178 "enter to omit:", 1179 &keyID); 1180 if (rv != SECSuccess) 1181 break; 1182 1183 SECU_SECItemHexStringToBinary(&keyID); 1184 1185 yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1186 1187 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, 1188 &keyID, yesNoAns, SEC_OID_X509_SUBJECT_KEY_ID, 1189 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeSubjectKeyID); 1190 if (rv) 1191 break; 1192 1193 } while (0); 1194 if (arena) 1195 PORT_FreeArena(arena, PR_FALSE); 1196 return (rv); 1197 } 1198 1199 static SECStatus 1200 AddCrlDistPoint(void *extHandle) 1201 { 1202 PLArenaPool *arena = NULL; 1203 CERTCrlDistributionPoints *crlDistPoints = NULL; 1204 CRLDistributionPoint *current; 1205 SECStatus rv = SECSuccess; 1206 int count = 0, intValue; 1207 char buffer[512]; 1208 1209 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1210 if (!arena) 1211 return (SECFailure); 1212 1213 do { 1214 current = NULL; 1215 1216 current = PORT_ArenaZNew(arena, CRLDistributionPoint); 1217 if (current == NULL) { 1218 GEN_BREAK(SECFailure); 1219 } 1220 1221 /* Get the distributionPointName fields - this field is optional */ 1222 if (PrintChoicesAndGetAnswer( 1223 "Enter the type of the distribution point name:\n" 1224 "\t1 - Full Name\n\t2 - Relative Name\n\tAny other " 1225 "number to finish\n\t\tChoice: ", 1226 buffer, sizeof(buffer)) == SECFailure) { 1227 GEN_BREAK(SECFailure); 1228 } 1229 intValue = PORT_Atoi(buffer); 1230 switch (intValue) { 1231 case generalName: 1232 PORT_SetError(0); 1233 current->distPointType = intValue; 1234 current->distPoint.fullName = CreateGeneralName(arena); 1235 rv = PORT_GetError(); 1236 break; 1237 1238 case relativeDistinguishedName: { 1239 CERTName *name; 1240 1241 current->distPointType = intValue; 1242 puts("Enter the relative name: "); 1243 fflush(stdout); 1244 if (Gets_s(buffer, sizeof(buffer)) == NULL) { 1245 GEN_BREAK(SECFailure); 1246 } 1247 /* For simplicity, use CERT_AsciiToName to converse from a string 1248 to NAME, but we only interest in the first RDN */ 1249 name = CERT_AsciiToName(buffer); 1250 if (!name) { 1251 GEN_BREAK(SECFailure); 1252 } 1253 rv = CERT_CopyRDN(arena, ¤t->distPoint.relativeName, 1254 name->rdns[0]); 1255 CERT_DestroyName(name); 1256 break; 1257 } 1258 } 1259 if (rv != SECSuccess) 1260 break; 1261 1262 /* Get the reason flags */ 1263 if (PrintChoicesAndGetAnswer( 1264 "\nSelect one of the following for the reason flags\n" 1265 "\t0 - unused\n\t1 - keyCompromise\n" 1266 "\t2 - caCompromise\n\t3 - affiliationChanged\n" 1267 "\t4 - superseded\n\t5 - cessationOfOperation\n" 1268 "\t6 - certificateHold\n" 1269 "\tAny other number to finish\t\tChoice: ", 1270 buffer, sizeof(buffer)) == SECFailure) { 1271 GEN_BREAK(SECFailure); 1272 } 1273 intValue = PORT_Atoi(buffer); 1274 if (intValue == 0) { 1275 /* Checking that zero value of variable 'value' 1276 * corresponds to '0' input made by user */ 1277 char *chPtr = strchr(buffer, '0'); 1278 if (chPtr == NULL) { 1279 intValue = -1; 1280 } 1281 } 1282 if (intValue >= 0 && intValue < 8) { 1283 current->reasons.data = PORT_ArenaAlloc(arena, sizeof(char)); 1284 if (current->reasons.data == NULL) { 1285 GEN_BREAK(SECFailure); 1286 } 1287 *current->reasons.data = (char)(0x80 >> intValue); 1288 current->reasons.len = 1; 1289 } 1290 puts("Enter value for the CRL Issuer name:\n"); 1291 current->crlIssuer = CreateGeneralName(arena); 1292 if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure) 1293 break; 1294 1295 if (crlDistPoints == NULL) { 1296 crlDistPoints = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); 1297 if (crlDistPoints == NULL) { 1298 GEN_BREAK(SECFailure); 1299 } 1300 } 1301 1302 if (crlDistPoints->distPoints) { 1303 crlDistPoints->distPoints = 1304 PORT_ArenaGrow(arena, crlDistPoints->distPoints, 1305 sizeof(*crlDistPoints->distPoints) * count, 1306 sizeof(*crlDistPoints->distPoints) * (count + 1)); 1307 } else { 1308 crlDistPoints->distPoints = 1309 PORT_ArenaZAlloc(arena, sizeof(*crlDistPoints->distPoints) * (count + 1)); 1310 } 1311 if (crlDistPoints->distPoints == NULL) { 1312 GEN_BREAK(SECFailure); 1313 } 1314 1315 crlDistPoints->distPoints[count] = current; 1316 ++count; 1317 if (GetYesNo("Enter another value for the CRLDistributionPoint " 1318 "extension [y/N]?") == 0) { 1319 /* Add null to the end to mark end of data */ 1320 crlDistPoints->distPoints = 1321 PORT_ArenaGrow(arena, crlDistPoints->distPoints, 1322 sizeof(*crlDistPoints->distPoints) * count, 1323 sizeof(*crlDistPoints->distPoints) * (count + 1)); 1324 crlDistPoints->distPoints[count] = NULL; 1325 break; 1326 } 1327 1328 } while (1); 1329 1330 if (rv == SECSuccess) { 1331 PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1332 1333 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, 1334 crlDistPoints, yesNoAns, SEC_OID_X509_CRL_DIST_POINTS, 1335 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeCRLDistributionPoints); 1336 } 1337 if (arena) 1338 PORT_FreeArena(arena, PR_FALSE); 1339 return (rv); 1340 } 1341 1342 static SECStatus 1343 AddPolicyConstraints(void *extHandle) 1344 { 1345 CERTCertificatePolicyConstraints *policyConstr; 1346 PLArenaPool *arena = NULL; 1347 SECStatus rv = SECSuccess; 1348 SECItem *item, *dummy; 1349 char buffer[512]; 1350 int value; 1351 PRBool yesNoAns; 1352 PRBool skipExt = PR_TRUE; 1353 1354 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1355 if (!arena) { 1356 SECU_PrintError(progName, "out of memory"); 1357 return SECFailure; 1358 } 1359 1360 policyConstr = PORT_ArenaZNew(arena, CERTCertificatePolicyConstraints); 1361 if (policyConstr == NULL) { 1362 SECU_PrintError(progName, "out of memory"); 1363 goto loser; 1364 } 1365 1366 if (PrintChoicesAndGetAnswer("for requireExplicitPolicy enter the number " 1367 "of certs in path\nbefore explicit policy is required\n" 1368 "(press Enter to omit)", 1369 buffer, sizeof(buffer)) == SECFailure) { 1370 goto loser; 1371 } 1372 1373 if (PORT_Strlen(buffer)) { 1374 value = PORT_Atoi(buffer); 1375 if (value < 0) { 1376 goto loser; 1377 } 1378 item = &policyConstr->explicitPolicySkipCerts; 1379 dummy = SEC_ASN1EncodeInteger(arena, item, value); 1380 if (!dummy) { 1381 goto loser; 1382 } 1383 skipExt = PR_FALSE; 1384 } 1385 1386 if (PrintChoicesAndGetAnswer("for inihibitPolicyMapping enter " 1387 "the number of certs in path\n" 1388 "after which policy mapping is not allowed\n" 1389 "(press Enter to omit)", 1390 buffer, sizeof(buffer)) == SECFailure) { 1391 goto loser; 1392 } 1393 1394 if (PORT_Strlen(buffer)) { 1395 value = PORT_Atoi(buffer); 1396 if (value < 0) { 1397 goto loser; 1398 } 1399 item = &policyConstr->inhibitMappingSkipCerts; 1400 dummy = SEC_ASN1EncodeInteger(arena, item, value); 1401 if (!dummy) { 1402 goto loser; 1403 } 1404 skipExt = PR_FALSE; 1405 } 1406 1407 if (!skipExt) { 1408 yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1409 1410 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, policyConstr, 1411 yesNoAns, SEC_OID_X509_POLICY_CONSTRAINTS, 1412 EXTEN_EXT_VALUE_ENCODER_CERT_EncodePolicyConstraintsExtension); 1413 } else { 1414 fprintf(stdout, "Policy Constraint extensions must contain " 1415 "at least one policy field\n"); 1416 rv = SECFailure; 1417 } 1418 1419 loser: 1420 if (arena) { 1421 PORT_FreeArena(arena, PR_FALSE); 1422 } 1423 return (rv); 1424 } 1425 1426 static SECStatus 1427 AddInhibitAnyPolicy(void *extHandle) 1428 { 1429 CERTCertificateInhibitAny certInhibitAny; 1430 PLArenaPool *arena = NULL; 1431 SECStatus rv = SECSuccess; 1432 SECItem *item, *dummy; 1433 char buffer[10]; 1434 int value; 1435 PRBool yesNoAns; 1436 1437 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1438 if (!arena) { 1439 SECU_PrintError(progName, "out of memory"); 1440 return SECFailure; 1441 } 1442 1443 if (PrintChoicesAndGetAnswer("Enter the number of certs in the path " 1444 "permitted to use anyPolicy.\n" 1445 "(press Enter for 0)", 1446 buffer, sizeof(buffer)) == SECFailure) { 1447 goto loser; 1448 } 1449 1450 item = &certInhibitAny.inhibitAnySkipCerts; 1451 value = PORT_Atoi(buffer); 1452 if (value < 0) { 1453 goto loser; 1454 } 1455 dummy = SEC_ASN1EncodeInteger(arena, item, value); 1456 if (!dummy) { 1457 goto loser; 1458 } 1459 1460 yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1461 1462 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &certInhibitAny, 1463 yesNoAns, SEC_OID_X509_INHIBIT_ANY_POLICY, 1464 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeInhibitAnyExtension); 1465 loser: 1466 if (arena) { 1467 PORT_FreeArena(arena, PR_FALSE); 1468 } 1469 return (rv); 1470 } 1471 1472 static SECStatus 1473 AddPolicyMappings(void *extHandle) 1474 { 1475 CERTPolicyMap **policyMapArr = NULL; 1476 CERTPolicyMap *current; 1477 PLArenaPool *arena = NULL; 1478 SECStatus rv = SECSuccess; 1479 int count = 0; 1480 char buffer[512]; 1481 1482 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1483 if (!arena) { 1484 SECU_PrintError(progName, "out of memory"); 1485 return SECFailure; 1486 } 1487 1488 do { 1489 if (PrintChoicesAndGetAnswer("Enter an Object Identifier (dotted " 1490 "decimal format) for Issuer Domain Policy", 1491 buffer, sizeof(buffer)) == SECFailure) { 1492 GEN_BREAK(SECFailure); 1493 } 1494 1495 current = PORT_ArenaZNew(arena, CERTPolicyMap); 1496 if (current == NULL) { 1497 GEN_BREAK(SECFailure); 1498 } 1499 1500 rv = SEC_StringToOID(arena, ¤t->issuerDomainPolicy, buffer, 0); 1501 if (rv == SECFailure) { 1502 GEN_BREAK(SECFailure); 1503 } 1504 1505 if (PrintChoicesAndGetAnswer("Enter an Object Identifier for " 1506 "Subject Domain Policy", 1507 buffer, sizeof(buffer)) == SECFailure) { 1508 GEN_BREAK(SECFailure); 1509 } 1510 1511 rv = SEC_StringToOID(arena, ¤t->subjectDomainPolicy, buffer, 0); 1512 if (rv == SECFailure) { 1513 GEN_BREAK(SECFailure); 1514 } 1515 1516 if (policyMapArr == NULL) { 1517 policyMapArr = PORT_ArenaZNew(arena, CERTPolicyMap *); 1518 if (policyMapArr == NULL) { 1519 GEN_BREAK(SECFailure); 1520 } 1521 } 1522 1523 policyMapArr = PORT_ArenaGrow(arena, policyMapArr, 1524 sizeof(current) * count, 1525 sizeof(current) * (count + 1)); 1526 if (policyMapArr == NULL) { 1527 GEN_BREAK(SECFailure); 1528 } 1529 1530 policyMapArr[count] = current; 1531 ++count; 1532 1533 if (!GetYesNo("Enter another Policy Mapping [y/N]")) { 1534 /* Add null to the end to mark end of data */ 1535 policyMapArr = PORT_ArenaGrow(arena, policyMapArr, 1536 sizeof(current) * count, 1537 sizeof(current) * (count + 1)); 1538 if (policyMapArr == NULL) { 1539 GEN_BREAK(SECFailure); 1540 } 1541 policyMapArr[count] = NULL; 1542 break; 1543 } 1544 1545 } while (1); 1546 1547 if (rv == SECSuccess) { 1548 CERTCertificatePolicyMappings mappings; 1549 PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1550 1551 mappings.arena = arena; 1552 mappings.policyMaps = policyMapArr; 1553 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &mappings, 1554 yesNoAns, SEC_OID_X509_POLICY_MAPPINGS, 1555 EXTEN_EXT_VALUE_ENCODER_CERT_EncodePolicyMappingExtension); 1556 } 1557 if (arena) 1558 PORT_FreeArena(arena, PR_FALSE); 1559 return (rv); 1560 } 1561 1562 enum PoliciQualifierEnum { 1563 cpsPointer = 1, 1564 userNotice = 2 1565 }; 1566 1567 static CERTPolicyQualifier ** 1568 RequestPolicyQualifiers(PLArenaPool *arena, SECItem *policyID) 1569 { 1570 CERTPolicyQualifier **policyQualifArr = NULL; 1571 CERTPolicyQualifier *current; 1572 SECStatus rv = SECSuccess; 1573 int count = 0; 1574 char buffer[512]; 1575 void *mark; 1576 SECOidData *oid = NULL; 1577 int intValue = 0; 1578 int inCount = 0; 1579 1580 PORT_Assert(arena); 1581 mark = PORT_ArenaMark(arena); 1582 do { 1583 current = PORT_ArenaZNew(arena, CERTPolicyQualifier); 1584 if (current == NULL) { 1585 GEN_BREAK(SECFailure); 1586 } 1587 1588 /* Get the accessMethod fields */ 1589 SECU_PrintObjectID(stdout, policyID, 1590 "Choose the type of qualifier for policy", 0); 1591 1592 if (PrintChoicesAndGetAnswer( 1593 "\t1 - CPS Pointer qualifier\n" 1594 "\t2 - User notice qualifier\n" 1595 "\tAny other number to finish\n" 1596 "\t\tChoice: ", 1597 buffer, sizeof(buffer)) == SECFailure) { 1598 GEN_BREAK(SECFailure); 1599 } 1600 intValue = PORT_Atoi(buffer); 1601 switch (intValue) { 1602 case cpsPointer: { 1603 SECItem input; 1604 1605 oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CPS_POINTER_QUALIFIER); 1606 if (PrintChoicesAndGetAnswer("Enter CPS pointer URI: ", 1607 buffer, sizeof(buffer)) == SECFailure) { 1608 GEN_BREAK(SECFailure); 1609 } 1610 input.len = PORT_Strlen(buffer); 1611 input.data = (void *)PORT_ArenaStrdup(arena, buffer); 1612 if (input.data == NULL || 1613 SEC_ASN1EncodeItem(arena, ¤t->qualifierValue, &input, 1614 SEC_ASN1_GET(SEC_IA5StringTemplate)) == NULL) { 1615 GEN_BREAK(SECFailure); 1616 } 1617 break; 1618 } 1619 case userNotice: { 1620 SECItem **noticeNumArr; 1621 CERTUserNotice *notice = PORT_ArenaZNew(arena, CERTUserNotice); 1622 if (!notice) { 1623 GEN_BREAK(SECFailure); 1624 } 1625 1626 oid = SECOID_FindOIDByTag(SEC_OID_PKIX_USER_NOTICE_QUALIFIER); 1627 1628 if (GetYesNo("\t add a User Notice reference? [y/N]")) { 1629 1630 if (PrintChoicesAndGetAnswer("Enter user organization string: ", 1631 buffer, sizeof(buffer)) == 1632 SECFailure) { 1633 GEN_BREAK(SECFailure); 1634 } 1635 1636 notice->noticeReference.organization.type = siAsciiString; 1637 notice->noticeReference.organization.len = 1638 PORT_Strlen(buffer); 1639 notice->noticeReference.organization.data = 1640 (void *)PORT_ArenaStrdup(arena, buffer); 1641 1642 noticeNumArr = PORT_ArenaZNewArray(arena, SECItem *, 2); 1643 if (!noticeNumArr) { 1644 GEN_BREAK(SECFailure); 1645 } 1646 1647 do { 1648 SECItem *noticeNum; 1649 1650 noticeNum = PORT_ArenaZNew(arena, SECItem); 1651 1652 if (PrintChoicesAndGetAnswer( 1653 "Enter User Notice reference number " 1654 "(or -1 to quit): ", 1655 buffer, sizeof(buffer)) == SECFailure) { 1656 GEN_BREAK(SECFailure); 1657 } 1658 1659 intValue = PORT_Atoi(buffer); 1660 if (noticeNum == NULL) { 1661 if (intValue < 0) { 1662 fprintf(stdout, "a noticeReference must have at " 1663 "least one reference number\n"); 1664 GEN_BREAK(SECFailure); 1665 } 1666 } else { 1667 if (intValue >= 0) { 1668 noticeNumArr = PORT_ArenaGrow(arena, noticeNumArr, 1669 sizeof(current) * 1670 inCount, 1671 sizeof(current) * 1672 (inCount + 1)); 1673 if (noticeNumArr == NULL) { 1674 GEN_BREAK(SECFailure); 1675 } 1676 } else { 1677 break; 1678 } 1679 } 1680 if (!SEC_ASN1EncodeInteger(arena, noticeNum, intValue)) { 1681 GEN_BREAK(SECFailure); 1682 } 1683 noticeNumArr[inCount++] = noticeNum; 1684 noticeNumArr[inCount] = NULL; 1685 1686 } while (1); 1687 if (rv == SECFailure) { 1688 GEN_BREAK(SECFailure); 1689 } 1690 notice->noticeReference.noticeNumbers = noticeNumArr; 1691 rv = CERT_EncodeNoticeReference(arena, ¬ice->noticeReference, 1692 ¬ice->derNoticeReference); 1693 if (rv == SECFailure) { 1694 GEN_BREAK(SECFailure); 1695 } 1696 } 1697 if (GetYesNo("\t EnterUser Notice explicit text? [y/N]")) { 1698 /* Getting only 200 bytes - RFC limitation */ 1699 if (PrintChoicesAndGetAnswer( 1700 "\t", buffer, 200) == SECFailure) { 1701 GEN_BREAK(SECFailure); 1702 } 1703 notice->displayText.type = siAsciiString; 1704 notice->displayText.len = PORT_Strlen(buffer); 1705 notice->displayText.data = 1706 (void *)PORT_ArenaStrdup(arena, buffer); 1707 if (notice->displayText.data == NULL) { 1708 GEN_BREAK(SECFailure); 1709 } 1710 } 1711 1712 rv = CERT_EncodeUserNotice(arena, notice, ¤t->qualifierValue); 1713 if (rv == SECFailure) { 1714 GEN_BREAK(SECFailure); 1715 } 1716 1717 break; 1718 } 1719 } 1720 if (rv == SECFailure || oid == NULL || 1721 SECITEM_CopyItem(arena, ¤t->qualifierID, &oid->oid) == 1722 SECFailure) { 1723 GEN_BREAK(SECFailure); 1724 } 1725 1726 if (!policyQualifArr) { 1727 policyQualifArr = PORT_ArenaZNew(arena, CERTPolicyQualifier *); 1728 } else { 1729 policyQualifArr = PORT_ArenaGrow(arena, policyQualifArr, 1730 sizeof(current) * count, 1731 sizeof(current) * (count + 1)); 1732 } 1733 if (policyQualifArr == NULL) { 1734 GEN_BREAK(SECFailure); 1735 } 1736 1737 policyQualifArr[count] = current; 1738 ++count; 1739 1740 if (!GetYesNo("Enter another policy qualifier [y/N]")) { 1741 /* Add null to the end to mark end of data */ 1742 policyQualifArr = PORT_ArenaGrow(arena, policyQualifArr, 1743 sizeof(current) * count, 1744 sizeof(current) * (count + 1)); 1745 if (policyQualifArr == NULL) { 1746 GEN_BREAK(SECFailure); 1747 } 1748 policyQualifArr[count] = NULL; 1749 break; 1750 } 1751 1752 } while (1); 1753 1754 if (rv != SECSuccess) { 1755 PORT_ArenaRelease(arena, mark); 1756 policyQualifArr = NULL; 1757 } 1758 return (policyQualifArr); 1759 } 1760 1761 static SECStatus 1762 AddCertPolicies(void *extHandle) 1763 { 1764 CERTPolicyInfo **certPoliciesArr = NULL; 1765 CERTPolicyInfo *current; 1766 PLArenaPool *arena = NULL; 1767 SECStatus rv = SECSuccess; 1768 int count = 0; 1769 char buffer[512]; 1770 1771 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1772 if (!arena) { 1773 SECU_PrintError(progName, "out of memory"); 1774 return SECFailure; 1775 } 1776 1777 do { 1778 current = PORT_ArenaZNew(arena, CERTPolicyInfo); 1779 if (current == NULL) { 1780 GEN_BREAK(SECFailure); 1781 } 1782 1783 if (PrintChoicesAndGetAnswer("Enter a CertPolicy Object Identifier " 1784 "(dotted decimal format)\n" 1785 "or \"any\" for AnyPolicy:", 1786 buffer, sizeof(buffer)) == SECFailure) { 1787 GEN_BREAK(SECFailure); 1788 } 1789 1790 if (strncmp(buffer, "any", 3) == 0) { 1791 /* use string version of X509_CERTIFICATE_POLICIES.anyPolicy */ 1792 strcpy(buffer, "OID.2.5.29.32.0"); 1793 } 1794 rv = SEC_StringToOID(arena, ¤t->policyID, buffer, 0); 1795 1796 if (rv == SECFailure) { 1797 GEN_BREAK(SECFailure); 1798 } 1799 1800 current->policyQualifiers = 1801 RequestPolicyQualifiers(arena, ¤t->policyID); 1802 1803 if (!certPoliciesArr) { 1804 certPoliciesArr = PORT_ArenaZNew(arena, CERTPolicyInfo *); 1805 } else { 1806 certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, 1807 sizeof(current) * count, 1808 sizeof(current) * (count + 1)); 1809 } 1810 if (certPoliciesArr == NULL) { 1811 GEN_BREAK(SECFailure); 1812 } 1813 1814 certPoliciesArr[count] = current; 1815 ++count; 1816 1817 if (!GetYesNo("Enter another PolicyInformation field [y/N]?")) { 1818 /* Add null to the end to mark end of data */ 1819 certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, 1820 sizeof(current) * count, 1821 sizeof(current) * (count + 1)); 1822 if (certPoliciesArr == NULL) { 1823 GEN_BREAK(SECFailure); 1824 } 1825 certPoliciesArr[count] = NULL; 1826 break; 1827 } 1828 1829 } while (1); 1830 1831 if (rv == SECSuccess) { 1832 CERTCertificatePolicies policies; 1833 PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1834 1835 policies.arena = arena; 1836 policies.policyInfos = certPoliciesArr; 1837 1838 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &policies, 1839 yesNoAns, SEC_OID_X509_CERTIFICATE_POLICIES, 1840 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeCertPoliciesExtension); 1841 } 1842 if (arena) 1843 PORT_FreeArena(arena, PR_FALSE); 1844 return (rv); 1845 } 1846 1847 enum AuthInfoAccessTypesEnum { 1848 caIssuers = 1, 1849 ocsp = 2 1850 }; 1851 1852 enum SubjInfoAccessTypesEnum { 1853 caRepository = 1, 1854 timeStamping = 2 1855 }; 1856 1857 /* Encode and add an AIA or SIA extension */ 1858 static SECStatus 1859 AddInfoAccess(void *extHandle, PRBool addSIAExt, PRBool isCACert) 1860 { 1861 CERTAuthInfoAccess **infoAccArr = NULL; 1862 CERTAuthInfoAccess *current; 1863 PLArenaPool *arena = NULL; 1864 SECStatus rv = SECSuccess; 1865 int count = 0; 1866 char buffer[512]; 1867 SECOidData *oid = NULL; 1868 int intValue = 0; 1869 1870 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1871 if (!arena) { 1872 SECU_PrintError(progName, "out of memory"); 1873 return SECFailure; 1874 } 1875 1876 do { 1877 current = NULL; 1878 current = PORT_ArenaZNew(arena, CERTAuthInfoAccess); 1879 if (current == NULL) { 1880 GEN_BREAK(SECFailure); 1881 } 1882 1883 /* Get the accessMethod fields */ 1884 if (addSIAExt) { 1885 if (isCACert) { 1886 puts("Adding \"CA Repository\" access method type for " 1887 "Subject Information Access extension:\n"); 1888 intValue = caRepository; 1889 } else { 1890 puts("Adding \"Time Stamping Services\" access method type for " 1891 "Subject Information Access extension:\n"); 1892 intValue = timeStamping; 1893 } 1894 } else { 1895 if (PrintChoicesAndGetAnswer("Enter access method type " 1896 "for Authority Information Access extension:\n" 1897 "\t1 - CA Issuers\n\t2 - OCSP\n\tAny" 1898 "other number to finish\n\tChoice", 1899 buffer, sizeof(buffer)) != 1900 SECSuccess) { 1901 GEN_BREAK(SECFailure); 1902 } 1903 intValue = PORT_Atoi(buffer); 1904 } 1905 if (addSIAExt) { 1906 switch (intValue) { 1907 case caRepository: 1908 oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_REPOSITORY); 1909 break; 1910 1911 case timeStamping: 1912 oid = SECOID_FindOIDByTag(SEC_OID_PKIX_TIMESTAMPING); 1913 break; 1914 } 1915 } else { 1916 switch (intValue) { 1917 case caIssuers: 1918 oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_ISSUERS); 1919 break; 1920 1921 case ocsp: 1922 oid = SECOID_FindOIDByTag(SEC_OID_PKIX_OCSP); 1923 break; 1924 } 1925 } 1926 if (oid == NULL || 1927 SECITEM_CopyItem(arena, ¤t->method, &oid->oid) == 1928 SECFailure) { 1929 GEN_BREAK(SECFailure); 1930 } 1931 1932 current->location = CreateGeneralName(arena); 1933 if (!current->location) { 1934 GEN_BREAK(SECFailure); 1935 } 1936 1937 if (infoAccArr == NULL) { 1938 infoAccArr = PORT_ArenaZNew(arena, CERTAuthInfoAccess *); 1939 } else { 1940 infoAccArr = PORT_ArenaGrow(arena, infoAccArr, 1941 sizeof(current) * count, 1942 sizeof(current) * (count + 1)); 1943 } 1944 if (infoAccArr == NULL) { 1945 GEN_BREAK(SECFailure); 1946 } 1947 1948 infoAccArr[count] = current; 1949 ++count; 1950 1951 PR_snprintf(buffer, sizeof(buffer), "Add another location to the %s" 1952 " Information Access extension [y/N]", 1953 (addSIAExt) ? "Subject" : "Authority"); 1954 1955 if (GetYesNo(buffer) == 0) { 1956 /* Add null to the end to mark end of data */ 1957 infoAccArr = PORT_ArenaGrow(arena, infoAccArr, 1958 sizeof(current) * count, 1959 sizeof(current) * (count + 1)); 1960 if (infoAccArr == NULL) { 1961 GEN_BREAK(SECFailure); 1962 } 1963 infoAccArr[count] = NULL; 1964 break; 1965 } 1966 1967 } while (1); 1968 1969 if (rv == SECSuccess) { 1970 int oidIdent = SEC_OID_X509_AUTH_INFO_ACCESS; 1971 1972 PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1973 1974 if (addSIAExt) { 1975 oidIdent = SEC_OID_X509_SUBJECT_INFO_ACCESS; 1976 } 1977 rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, infoAccArr, 1978 yesNoAns, oidIdent, 1979 EXTEN_EXT_VALUE_ENCODER_CERT_EncodeInfoAccessExtension); 1980 } 1981 if (arena) 1982 PORT_FreeArena(arena, PR_FALSE); 1983 return (rv); 1984 } 1985 1986 /* Example of valid input: 1987 * 1.2.3.4:critical:/tmp/abc,5.6.7.8:not-critical:/tmp/xyz 1988 */ 1989 static SECStatus 1990 parseNextGenericExt(const char *nextExtension, const char **oid, int *oidLen, 1991 const char **crit, int *critLen, 1992 const char **filename, int *filenameLen, 1993 const char **next) 1994 { 1995 const char *nextColon; 1996 const char *nextComma; 1997 const char *iter = nextExtension; 1998 1999 if (!iter || !*iter) 2000 return SECFailure; 2001 2002 /* Require colons at earlier positions than nextComma (or end of string ) */ 2003 nextComma = strchr(iter, ','); 2004 2005 *oid = iter; 2006 nextColon = strchr(iter, ':'); 2007 if (!nextColon || (nextComma && nextColon > nextComma)) 2008 return SECFailure; 2009 *oidLen = (nextColon - *oid); 2010 2011 if (!*oidLen) 2012 return SECFailure; 2013 2014 iter = nextColon; 2015 ++iter; 2016 2017 *crit = iter; 2018 nextColon = strchr(iter, ':'); 2019 if (!nextColon || (nextComma && nextColon > nextComma)) 2020 return SECFailure; 2021 *critLen = (nextColon - *crit); 2022 2023 if (!*critLen) 2024 return SECFailure; 2025 2026 iter = nextColon; 2027 ++iter; 2028 2029 *filename = iter; 2030 if (nextComma) { 2031 *filenameLen = (nextComma - *filename); 2032 iter = nextComma; 2033 ++iter; 2034 *next = iter; 2035 } else { 2036 *filenameLen = strlen(*filename); 2037 *next = NULL; 2038 } 2039 2040 if (!*filenameLen) 2041 return SECFailure; 2042 2043 return SECSuccess; 2044 } 2045 2046 SECStatus 2047 AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames, 2048 certutilExtnList extList, const char *extGeneric) 2049 { 2050 PLArenaPool *arena; 2051 SECStatus rv = SECSuccess; 2052 char *errstring = NULL; 2053 const char *nextExtension = NULL; 2054 2055 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2056 if (arena == NULL) { 2057 return SECFailure; 2058 } 2059 2060 do { 2061 /* Add key usage extension */ 2062 if (extList[ext_keyUsage].activated) { 2063 rv = AddKeyUsage(extHandle, extList[ext_keyUsage].arg); 2064 if (rv) { 2065 errstring = "KeyUsage"; 2066 break; 2067 } 2068 } 2069 2070 /* Add extended key usage extension */ 2071 if (extList[ext_extKeyUsage].activated) { 2072 rv = AddExtKeyUsage(extHandle, extList[ext_extKeyUsage].arg); 2073 if (rv) { 2074 errstring = "ExtendedKeyUsage"; 2075 break; 2076 } 2077 } 2078 2079 /* Add basic constraint extension */ 2080 if (extList[ext_basicConstraint].activated) { 2081 rv = AddBasicConstraint(arena, extHandle); 2082 if (rv) { 2083 errstring = "BasicConstraint"; 2084 break; 2085 } 2086 } 2087 2088 /* Add name constraints extension */ 2089 if (extList[ext_nameConstraints].activated) { 2090 rv = AddNameConstraints(extHandle); 2091 if (rv) { 2092 errstring = "NameConstraints"; 2093 break; 2094 } 2095 } 2096 2097 if (extList[ext_authorityKeyID].activated) { 2098 rv = AddAuthKeyID(extHandle); 2099 if (rv) { 2100 errstring = "AuthorityKeyID"; 2101 break; 2102 } 2103 } 2104 2105 if (extList[ext_subjectKeyID].activated) { 2106 rv = AddSubjKeyID(extHandle); 2107 if (rv) { 2108 errstring = "SubjectKeyID"; 2109 break; 2110 } 2111 } 2112 2113 if (extList[ext_CRLDistPts].activated) { 2114 rv = AddCrlDistPoint(extHandle); 2115 if (rv) { 2116 errstring = "CRLDistPoints"; 2117 break; 2118 } 2119 } 2120 2121 if (extList[ext_NSCertType].activated) { 2122 rv = AddNscpCertType(extHandle, extList[ext_NSCertType].arg); 2123 if (rv) { 2124 errstring = "NSCertType"; 2125 break; 2126 } 2127 } 2128 2129 if (extList[ext_authInfoAcc].activated || 2130 extList[ext_subjInfoAcc].activated) { 2131 rv = AddInfoAccess(extHandle, extList[ext_subjInfoAcc].activated, 2132 extList[ext_basicConstraint].activated); 2133 if (rv) { 2134 errstring = "InformationAccess"; 2135 break; 2136 } 2137 } 2138 2139 if (extList[ext_certPolicies].activated) { 2140 rv = AddCertPolicies(extHandle); 2141 if (rv) { 2142 errstring = "Policies"; 2143 break; 2144 } 2145 } 2146 2147 if (extList[ext_policyMappings].activated) { 2148 rv = AddPolicyMappings(extHandle); 2149 if (rv) { 2150 errstring = "PolicyMappings"; 2151 break; 2152 } 2153 } 2154 2155 if (extList[ext_policyConstr].activated) { 2156 rv = AddPolicyConstraints(extHandle); 2157 if (rv) { 2158 errstring = "PolicyConstraints"; 2159 break; 2160 } 2161 } 2162 2163 if (extList[ext_inhibitAnyPolicy].activated) { 2164 rv = AddInhibitAnyPolicy(extHandle); 2165 if (rv) { 2166 errstring = "InhibitAnyPolicy"; 2167 break; 2168 } 2169 } 2170 2171 if (emailAddrs || dnsNames || extList[ext_subjectAltName].activated) { 2172 CERTGeneralName *namelist = NULL; 2173 SECItem item = { 0, NULL, 0 }; 2174 2175 rv = SECSuccess; 2176 2177 if (emailAddrs) { 2178 rv |= AddEmailSubjectAlt(arena, &namelist, emailAddrs); 2179 } 2180 2181 if (dnsNames) { 2182 rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames); 2183 } 2184 2185 if (extList[ext_subjectAltName].activated) { 2186 rv |= AddGeneralSubjectAlt(arena, &namelist, 2187 extList[ext_subjectAltName].arg); 2188 } 2189 2190 if (rv == SECSuccess) { 2191 rv = CERT_EncodeAltNameExtension(arena, namelist, &item); 2192 if (rv == SECSuccess) { 2193 rv = CERT_AddExtension(extHandle, 2194 SEC_OID_X509_SUBJECT_ALT_NAME, 2195 &item, PR_FALSE, PR_TRUE); 2196 } 2197 } 2198 if (rv) { 2199 errstring = "SubjectAltName"; 2200 break; 2201 } 2202 } 2203 } while (0); 2204 2205 PORT_FreeArena(arena, PR_FALSE); 2206 2207 if (rv != SECSuccess) { 2208 SECU_PrintError(progName, "Problem creating %s extension", errstring); 2209 } 2210 2211 nextExtension = extGeneric; 2212 while (nextExtension && *nextExtension) { 2213 SECItem oid_item, value; 2214 PRBool isCritical; 2215 const char *oid, *crit, *filename, *next; 2216 int oidLen, critLen, filenameLen; 2217 PRFileDesc *inFile = NULL; 2218 char *zeroTerminatedFilename = NULL; 2219 2220 rv = parseNextGenericExt(nextExtension, &oid, &oidLen, &crit, &critLen, 2221 &filename, &filenameLen, &next); 2222 if (rv != SECSuccess) { 2223 SECU_PrintError(progName, 2224 "error parsing generic extension parameter %s", 2225 nextExtension); 2226 break; 2227 } 2228 oid_item.data = NULL; 2229 oid_item.len = 0; 2230 rv = GetOidFromString(NULL, &oid_item, oid, oidLen); 2231 if (rv != SECSuccess) { 2232 SECU_PrintError(progName, "malformed extension OID %s", nextExtension); 2233 break; 2234 } 2235 if (!strncmp("critical", crit, critLen)) { 2236 isCritical = PR_TRUE; 2237 } else if (!strncmp("not-critical", crit, critLen)) { 2238 isCritical = PR_FALSE; 2239 } else { 2240 rv = SECFailure; 2241 SECU_PrintError(progName, "expected 'critical' or 'not-critical'"); 2242 break; 2243 } 2244 zeroTerminatedFilename = PL_strndup(filename, filenameLen); 2245 if (!zeroTerminatedFilename) { 2246 rv = SECFailure; 2247 SECU_PrintError(progName, "out of memory"); 2248 break; 2249 } 2250 rv = SECFailure; 2251 inFile = PR_Open(zeroTerminatedFilename, PR_RDONLY, 0); 2252 if (inFile) { 2253 rv = SECU_ReadDERFromFile(&value, inFile, PR_FALSE, PR_FALSE); 2254 PR_Close(inFile); 2255 inFile = NULL; 2256 } 2257 if (rv != SECSuccess) { 2258 SECU_PrintError(progName, "unable to read file %s", 2259 zeroTerminatedFilename); 2260 } 2261 PL_strfree(zeroTerminatedFilename); 2262 if (rv != SECSuccess) { 2263 break; 2264 } 2265 rv = CERT_AddExtensionByOID(extHandle, &oid_item, &value, isCritical, 2266 PR_TRUE /*copyData*/); 2267 SECITEM_FreeItem(&value, PR_FALSE); 2268 SECITEM_FreeItem(&oid_item, PR_FALSE); 2269 if (rv != SECSuccess) { 2270 SECU_PrintError(progName, "failed to add extension %s", nextExtension); 2271 break; 2272 } 2273 nextExtension = next; 2274 } 2275 2276 return rv; 2277 }