security/nss/cmd/certutil/certext.c

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

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

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

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

mercurial