1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/certutil/certext.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2208 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 +** certext.c 1.10 +** 1.11 +** part of certutil for managing certificates extensions 1.12 +** 1.13 +*/ 1.14 +#include <stdio.h> 1.15 +#include <string.h> 1.16 +#include <stdlib.h> 1.17 + 1.18 +#if defined(WIN32) 1.19 +#include "fcntl.h" 1.20 +#include "io.h" 1.21 +#endif 1.22 + 1.23 +#include "secutil.h" 1.24 + 1.25 +#if defined(XP_UNIX) 1.26 +#include <unistd.h> 1.27 +#endif 1.28 + 1.29 +#include "cert.h" 1.30 +#include "xconst.h" 1.31 +#include "prprf.h" 1.32 +#include "certutil.h" 1.33 +#include "genname.h" 1.34 +#include "prnetdb.h" 1.35 + 1.36 +#define GEN_BREAK(e) rv=e; break; 1.37 + 1.38 +static char * 1.39 +Gets_s(char *buff, size_t size) { 1.40 + char *str; 1.41 + 1.42 + if (buff == NULL || size < 1) { 1.43 + PORT_Assert(0); 1.44 + return NULL; 1.45 + } 1.46 + if ((str = fgets(buff, size, stdin)) != NULL) { 1.47 + int len = PORT_Strlen(str); 1.48 + /* 1.49 + * fgets() automatically converts native text file 1.50 + * line endings to '\n'. As defensive programming 1.51 + * (just in case fgets has a bug or we put stdin in 1.52 + * binary mode by mistake), we handle three native 1.53 + * text file line endings here: 1.54 + * '\n' Unix (including Linux and Mac OS X) 1.55 + * '\r''\n' DOS/Windows & OS/2 1.56 + * '\r' Mac OS Classic 1.57 + * len can not be less then 1, since in case with 1.58 + * empty string it has at least '\n' in the buffer 1.59 + */ 1.60 + if (buff[len - 1] == '\n' || buff[len - 1] == '\r') { 1.61 + buff[len - 1] = '\0'; 1.62 + if (len > 1 && buff[len - 2] == '\r') 1.63 + buff[len - 2] = '\0'; 1.64 + } 1.65 + } else { 1.66 + buff[0] = '\0'; 1.67 + } 1.68 + return str; 1.69 +} 1.70 + 1.71 + 1.72 +static SECStatus 1.73 +PrintChoicesAndGetAnswer(char* str, char* rBuff, int rSize) 1.74 +{ 1.75 + fputs(str, stdout); 1.76 + fputs(" > ", stdout); 1.77 + fflush (stdout); 1.78 + if (Gets_s(rBuff, rSize) == NULL) { 1.79 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.80 + return SECFailure; 1.81 + } 1.82 + return SECSuccess; 1.83 +} 1.84 + 1.85 +static CERTGeneralName * 1.86 +GetGeneralName(PLArenaPool *arena, CERTGeneralName *useExistingName, PRBool onlyOne) 1.87 +{ 1.88 + CERTGeneralName *namesList = NULL; 1.89 + CERTGeneralName *current; 1.90 + CERTGeneralName *tail = NULL; 1.91 + SECStatus rv = SECSuccess; 1.92 + int intValue; 1.93 + char buffer[512]; 1.94 + void *mark; 1.95 + 1.96 + PORT_Assert (arena); 1.97 + mark = PORT_ArenaMark (arena); 1.98 + do { 1.99 + if (PrintChoicesAndGetAnswer( 1.100 + "\nSelect one of the following general name type: \n" 1.101 + "\t2 - rfc822Name\n" 1.102 + "\t3 - dnsName\n" 1.103 + "\t5 - directoryName\n" 1.104 + "\t7 - uniformResourceidentifier\n" 1.105 + "\t8 - ipAddress\n" 1.106 + "\t9 - registerID\n" 1.107 + "\tAny other number to finish\n" 1.108 + "\t\tChoice:", buffer, sizeof(buffer)) == SECFailure) { 1.109 + GEN_BREAK (SECFailure); 1.110 + } 1.111 + intValue = PORT_Atoi (buffer); 1.112 + /* 1.113 + * Should use ZAlloc instead of Alloc to avoid problem with garbage 1.114 + * initialized pointers in CERT_CopyName 1.115 + */ 1.116 + switch (intValue) { 1.117 + case certRFC822Name: 1.118 + case certDNSName: 1.119 + case certDirectoryName: 1.120 + case certURI: 1.121 + case certIPAddress: 1.122 + case certRegisterID: 1.123 + break; 1.124 + default: 1.125 + intValue = 0; /* force a break for anything else */ 1.126 + } 1.127 + 1.128 + if (intValue == 0) 1.129 + break; 1.130 + 1.131 + if (namesList == NULL) { 1.132 + if (useExistingName) { 1.133 + namesList = current = tail = useExistingName; 1.134 + } else { 1.135 + namesList = current = tail = 1.136 + PORT_ArenaZNew(arena, CERTGeneralName); 1.137 + } 1.138 + } else { 1.139 + current = PORT_ArenaZNew(arena, CERTGeneralName); 1.140 + } 1.141 + if (current == NULL) { 1.142 + GEN_BREAK (SECFailure); 1.143 + } 1.144 + 1.145 + current->type = intValue; 1.146 + puts ("\nEnter data:"); 1.147 + fflush (stdout); 1.148 + if (Gets_s (buffer, sizeof(buffer)) == NULL) { 1.149 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.150 + GEN_BREAK (SECFailure); 1.151 + } 1.152 + switch (current->type) { 1.153 + case certURI: 1.154 + case certDNSName: 1.155 + case certRFC822Name: 1.156 + current->name.other.data = 1.157 + PORT_ArenaAlloc (arena, strlen (buffer)); 1.158 + if (current->name.other.data == NULL) { 1.159 + GEN_BREAK (SECFailure); 1.160 + } 1.161 + PORT_Memcpy(current->name.other.data, buffer, 1.162 + current->name.other.len = strlen(buffer)); 1.163 + break; 1.164 + 1.165 + case certEDIPartyName: 1.166 + case certIPAddress: 1.167 + case certOtherName: 1.168 + case certRegisterID: 1.169 + case certX400Address: { 1.170 + 1.171 + current->name.other.data = 1.172 + PORT_ArenaAlloc (arena, strlen (buffer) + 2); 1.173 + if (current->name.other.data == NULL) { 1.174 + GEN_BREAK (SECFailure); 1.175 + } 1.176 + 1.177 + PORT_Memcpy (current->name.other.data + 2, buffer, 1.178 + strlen (buffer)); 1.179 + /* This may not be accurate for all cases. For now, 1.180 + * use this tag type */ 1.181 + current->name.other.data[0] = 1.182 + (char)(((current->type - 1) & 0x1f)| 0x80); 1.183 + current->name.other.data[1] = (char)strlen (buffer); 1.184 + current->name.other.len = strlen (buffer) + 2; 1.185 + break; 1.186 + } 1.187 + 1.188 + case certDirectoryName: { 1.189 + CERTName *directoryName = NULL; 1.190 + 1.191 + directoryName = CERT_AsciiToName (buffer); 1.192 + if (!directoryName) { 1.193 + fprintf(stderr, "certutil: improperly formatted name: " 1.194 + "\"%s\"\n", buffer); 1.195 + break; 1.196 + } 1.197 + 1.198 + rv = CERT_CopyName (arena, ¤t->name.directoryName, 1.199 + directoryName); 1.200 + CERT_DestroyName (directoryName); 1.201 + 1.202 + break; 1.203 + } 1.204 + } 1.205 + if (rv != SECSuccess) 1.206 + break; 1.207 + current->l.next = &(namesList->l); 1.208 + current->l.prev = &(tail->l); 1.209 + tail->l.next = &(current->l); 1.210 + tail = current; 1.211 + 1.212 + }while (!onlyOne); 1.213 + 1.214 + if (rv != SECSuccess) { 1.215 + PORT_ArenaRelease (arena, mark); 1.216 + namesList = NULL; 1.217 + } 1.218 + return (namesList); 1.219 +} 1.220 + 1.221 +static CERTGeneralName * 1.222 +CreateGeneralName(PLArenaPool *arena) 1.223 +{ 1.224 + return GetGeneralName(arena, NULL, PR_FALSE); 1.225 +} 1.226 + 1.227 +static SECStatus 1.228 +GetString(PLArenaPool *arena, char *prompt, SECItem *value) 1.229 +{ 1.230 + char buffer[251]; 1.231 + char *buffPrt; 1.232 + 1.233 + buffer[0] = '\0'; 1.234 + value->data = NULL; 1.235 + value->len = 0; 1.236 + 1.237 + puts (prompt); 1.238 + buffPrt = Gets_s (buffer, sizeof(buffer)); 1.239 + /* returned NULL here treated the same way as empty string */ 1.240 + if (buffPrt && strlen (buffer) > 0) { 1.241 + value->data = PORT_ArenaAlloc (arena, strlen (buffer)); 1.242 + if (value->data == NULL) { 1.243 + PORT_SetError (SEC_ERROR_NO_MEMORY); 1.244 + return (SECFailure); 1.245 + } 1.246 + PORT_Memcpy (value->data, buffer, value->len = strlen(buffer)); 1.247 + } 1.248 + return (SECSuccess); 1.249 +} 1.250 + 1.251 +static PRBool 1.252 +GetYesNo(char *prompt) 1.253 +{ 1.254 + char buf[3]; 1.255 + char *buffPrt; 1.256 + 1.257 + buf[0] = 'n'; 1.258 + puts(prompt); 1.259 + buffPrt = Gets_s(buf, sizeof(buf)); 1.260 + return (buffPrt && (buf[0] == 'y' || buf[0] == 'Y')) ? PR_TRUE : PR_FALSE; 1.261 +} 1.262 + 1.263 +/* Parses comma separated values out of the string pointed by nextPos. 1.264 + * Parsed value is compared to an array of possible values(valueArray). 1.265 + * If match is found, a value index is returned, otherwise returns SECFailue. 1.266 + * nextPos is set to the token after found comma separator or to NULL. 1.267 + * NULL in nextPos should be used as indication of the last parsed token. 1.268 + * A special value "critical" can be parsed out from the supplied sting.*/ 1.269 + 1.270 +static SECStatus 1.271 +parseNextCmdInput(const char * const *valueArray, int *value, char **nextPos, 1.272 + PRBool *critical) 1.273 +{ 1.274 + char *thisPos = *nextPos; 1.275 + int keyLen = 0; 1.276 + int arrIndex = 0; 1.277 + 1.278 + if (!valueArray || !value || !nextPos || !critical) { 1.279 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.280 + return SECFailure; 1.281 + } 1.282 + while (1) { 1.283 + if ((*nextPos = strchr(thisPos, ',')) == NULL) { 1.284 + keyLen = strlen(thisPos); 1.285 + } else { 1.286 + keyLen = *nextPos - thisPos; 1.287 + *nextPos += 1; 1.288 + } 1.289 + /* if critical keyword is found, go for another loop, 1.290 + * but check, if it is the last keyword of 1.291 + * the string.*/ 1.292 + if (!strncmp("critical", thisPos, keyLen)) { 1.293 + *critical = PR_TRUE; 1.294 + if (*nextPos == NULL) { 1.295 + return SECSuccess; 1.296 + } 1.297 + thisPos = *nextPos; 1.298 + continue; 1.299 + } 1.300 + break; 1.301 + } 1.302 + for (arrIndex = 0; valueArray[arrIndex]; arrIndex++) { 1.303 + if (!strncmp(valueArray[arrIndex], thisPos, keyLen)) { 1.304 + *value = arrIndex; 1.305 + return SECSuccess; 1.306 + } 1.307 + } 1.308 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.309 + return SECFailure; 1.310 +} 1.311 + 1.312 +static const char * const 1.313 +keyUsageKeyWordArray[] = { "digitalSignature", 1.314 + "nonRepudiation", 1.315 + "keyEncipherment", 1.316 + "dataEncipherment", 1.317 + "keyAgreement", 1.318 + "certSigning", 1.319 + "crlSigning", 1.320 + NULL}; 1.321 + 1.322 +static SECStatus 1.323 +AddKeyUsage (void *extHandle, const char *userSuppliedValue) 1.324 +{ 1.325 + SECItem bitStringValue; 1.326 + unsigned char keyUsage = 0x0; 1.327 + char buffer[5]; 1.328 + int value; 1.329 + char *nextPos = (char*)userSuppliedValue; 1.330 + PRBool isCriticalExt = PR_FALSE; 1.331 + 1.332 + if (!userSuppliedValue) { 1.333 + while (1) { 1.334 + if (PrintChoicesAndGetAnswer( 1.335 + "\t\t0 - Digital Signature\n" 1.336 + "\t\t1 - Non-repudiation\n" 1.337 + "\t\t2 - Key encipherment\n" 1.338 + "\t\t3 - Data encipherment\n" 1.339 + "\t\t4 - Key agreement\n" 1.340 + "\t\t5 - Cert signing key\n" 1.341 + "\t\t6 - CRL signing key\n" 1.342 + "\t\tOther to finish\n", 1.343 + buffer, sizeof(buffer)) == SECFailure) { 1.344 + return SECFailure; 1.345 + } 1.346 + value = PORT_Atoi (buffer); 1.347 + if (value < 0 || value > 6) 1.348 + break; 1.349 + if (value == 0) { 1.350 + /* Checking that zero value of variable 'value' 1.351 + * corresponds to '0' input made by user */ 1.352 + char *chPtr = strchr(buffer, '0'); 1.353 + if (chPtr == NULL) { 1.354 + continue; 1.355 + } 1.356 + } 1.357 + keyUsage |= (0x80 >> value); 1.358 + } 1.359 + isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); 1.360 + } else { 1.361 + while (1) { 1.362 + if (parseNextCmdInput(keyUsageKeyWordArray, &value, &nextPos, 1.363 + &isCriticalExt) == SECFailure) { 1.364 + return SECFailure; 1.365 + } 1.366 + keyUsage |= (0x80 >> value); 1.367 + if (!nextPos) 1.368 + break; 1.369 + } 1.370 + } 1.371 + 1.372 + bitStringValue.data = &keyUsage; 1.373 + bitStringValue.len = 1; 1.374 + 1.375 + return (CERT_EncodeAndAddBitStrExtension 1.376 + (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue, 1.377 + isCriticalExt)); 1.378 + 1.379 +} 1.380 + 1.381 + 1.382 +static CERTOidSequence * 1.383 +CreateOidSequence(void) 1.384 +{ 1.385 + CERTOidSequence *rv = (CERTOidSequence *)NULL; 1.386 + PLArenaPool *arena = (PLArenaPool *)NULL; 1.387 + 1.388 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.389 + if( (PLArenaPool *)NULL == arena ) { 1.390 + goto loser; 1.391 + } 1.392 + 1.393 + rv = (CERTOidSequence *)PORT_ArenaZNew(arena, CERTOidSequence); 1.394 + if( (CERTOidSequence *)NULL == rv ) { 1.395 + goto loser; 1.396 + } 1.397 + 1.398 + rv->oids = (SECItem **)PORT_ArenaZNew(arena, SECItem *); 1.399 + if( (SECItem **)NULL == rv->oids ) { 1.400 + goto loser; 1.401 + } 1.402 + 1.403 + rv->arena = arena; 1.404 + return rv; 1.405 + 1.406 +loser: 1.407 + if( (PLArenaPool *)NULL != arena ) { 1.408 + PORT_FreeArena(arena, PR_FALSE); 1.409 + } 1.410 + 1.411 + return (CERTOidSequence *)NULL; 1.412 +} 1.413 + 1.414 +static void 1.415 +DestroyOidSequence(CERTOidSequence *os) 1.416 +{ 1.417 + if (os->arena) { 1.418 + PORT_FreeArena(os->arena, PR_FALSE); 1.419 + } 1.420 +} 1.421 + 1.422 +static SECStatus 1.423 +AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag) 1.424 +{ 1.425 + SECItem **oids; 1.426 + PRUint32 count = 0; 1.427 + SECOidData *od; 1.428 + 1.429 + od = SECOID_FindOIDByTag(oidTag); 1.430 + if( (SECOidData *)NULL == od ) { 1.431 + return SECFailure; 1.432 + } 1.433 + 1.434 + for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) { 1.435 + if (*oids == &od->oid) { 1.436 + /* We already have this oid */ 1.437 + return SECSuccess; 1.438 + } 1.439 + count++; 1.440 + } 1.441 + 1.442 + /* ArenaZRealloc */ 1.443 + 1.444 + { 1.445 + PRUint32 i; 1.446 + 1.447 + oids = (SECItem **)PORT_ArenaZNewArray(os->arena, SECItem *, count + 2); 1.448 + if( (SECItem **)NULL == oids ) { 1.449 + return SECFailure; 1.450 + } 1.451 + 1.452 + for( i = 0; i < count; i++ ) { 1.453 + oids[i] = os->oids[i]; 1.454 + } 1.455 + 1.456 + /* ArenaZFree(os->oids); */ 1.457 + } 1.458 + 1.459 + os->oids = oids; 1.460 + os->oids[count] = &od->oid; 1.461 + 1.462 + return SECSuccess; 1.463 +} 1.464 + 1.465 +SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) 1.466 + 1.467 +const SEC_ASN1Template CERT_OidSeqTemplate[] = { 1.468 + { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, offsetof(CERTOidSequence, oids), 1.469 + SEC_ASN1_SUB(SEC_ObjectIDTemplate) } 1.470 +}; 1.471 + 1.472 + 1.473 +static SECItem * 1.474 +EncodeOidSequence(CERTOidSequence *os) 1.475 +{ 1.476 + SECItem *rv; 1.477 + 1.478 + rv = (SECItem *)PORT_ArenaZNew(os->arena, SECItem); 1.479 + if( (SECItem *)NULL == rv ) { 1.480 + goto loser; 1.481 + } 1.482 + 1.483 + if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) { 1.484 + goto loser; 1.485 + } 1.486 + 1.487 + return rv; 1.488 + 1.489 +loser: 1.490 + return (SECItem *)NULL; 1.491 +} 1.492 + 1.493 +static const char * const 1.494 +extKeyUsageKeyWordArray[] = { "serverAuth", 1.495 + "clientAuth", 1.496 + "codeSigning", 1.497 + "emailProtection", 1.498 + "timeStamp", 1.499 + "ocspResponder", 1.500 + "stepUp", 1.501 + "msTrustListSigning", 1.502 + NULL}; 1.503 + 1.504 +static SECStatus 1.505 +AddExtKeyUsage (void *extHandle, const char *userSuppliedValue) 1.506 +{ 1.507 + char buffer[5]; 1.508 + int value; 1.509 + CERTOidSequence *os; 1.510 + SECStatus rv; 1.511 + SECItem *item; 1.512 + PRBool isCriticalExt = PR_FALSE; 1.513 + char *nextPos = (char*)userSuppliedValue; 1.514 + 1.515 + os = CreateOidSequence(); 1.516 + if( (CERTOidSequence *)NULL == os ) { 1.517 + return SECFailure; 1.518 + } 1.519 + 1.520 + while (1) { 1.521 + if (!userSuppliedValue) { 1.522 + if (PrintChoicesAndGetAnswer( 1.523 + "\t\t0 - Server Auth\n" 1.524 + "\t\t1 - Client Auth\n" 1.525 + "\t\t2 - Code Signing\n" 1.526 + "\t\t3 - Email Protection\n" 1.527 + "\t\t4 - Timestamp\n" 1.528 + "\t\t5 - OCSP Responder\n" 1.529 + "\t\t6 - Step-up\n" 1.530 + "\t\t7 - Microsoft Trust List Signing\n" 1.531 + "\t\tOther to finish\n", 1.532 + buffer, sizeof(buffer)) == SECFailure) { 1.533 + GEN_BREAK(SECFailure); 1.534 + } 1.535 + value = PORT_Atoi(buffer); 1.536 + 1.537 + if (value == 0) { 1.538 + /* Checking that zero value of variable 'value' 1.539 + * corresponds to '0' input made by user */ 1.540 + char *chPtr = strchr(buffer, '0'); 1.541 + if (chPtr == NULL) { 1.542 + continue; 1.543 + } 1.544 + } 1.545 + } else { 1.546 + if (parseNextCmdInput(extKeyUsageKeyWordArray, &value, &nextPos, 1.547 + &isCriticalExt) == SECFailure) { 1.548 + return SECFailure; 1.549 + } 1.550 + } 1.551 + 1.552 + switch( value ) { 1.553 + case 0: 1.554 + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH); 1.555 + break; 1.556 + case 1: 1.557 + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH); 1.558 + break; 1.559 + case 2: 1.560 + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN); 1.561 + break; 1.562 + case 3: 1.563 + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT); 1.564 + break; 1.565 + case 4: 1.566 + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP); 1.567 + break; 1.568 + case 5: 1.569 + rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER); 1.570 + break; 1.571 + case 6: 1.572 + rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED); 1.573 + break; 1.574 + case 7: 1.575 + rv = AddOidToSequence(os, SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING); 1.576 + break; 1.577 + default: 1.578 + goto endloop; 1.579 + } 1.580 + 1.581 + if (userSuppliedValue && !nextPos) 1.582 + break; 1.583 + if( SECSuccess != rv ) 1.584 + goto loser; 1.585 + } 1.586 + 1.587 +endloop: 1.588 + item = EncodeOidSequence(os); 1.589 + 1.590 + if (!userSuppliedValue) { 1.591 + isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); 1.592 + } 1.593 + 1.594 + rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item, 1.595 + isCriticalExt, PR_TRUE); 1.596 + /*FALLTHROUGH*/ 1.597 +loser: 1.598 + DestroyOidSequence(os); 1.599 + return rv; 1.600 +} 1.601 + 1.602 +static const char * const 1.603 +nsCertTypeKeyWordArray[] = { "sslClient", 1.604 + "sslServer", 1.605 + "smime", 1.606 + "objectSigning", 1.607 + "Not!Used", 1.608 + "sslCA", 1.609 + "smimeCA", 1.610 + "objectSigningCA", 1.611 + NULL }; 1.612 + 1.613 +static SECStatus 1.614 +AddNscpCertType (void *extHandle, const char *userSuppliedValue) 1.615 +{ 1.616 + SECItem bitStringValue; 1.617 + unsigned char keyUsage = 0x0; 1.618 + char buffer[5]; 1.619 + int value; 1.620 + char *nextPos = (char*)userSuppliedValue; 1.621 + PRBool isCriticalExt = PR_FALSE; 1.622 + 1.623 + if (!userSuppliedValue) { 1.624 + while (1) { 1.625 + if (PrintChoicesAndGetAnswer( 1.626 + "\t\t0 - SSL Client\n" 1.627 + "\t\t1 - SSL Server\n" 1.628 + "\t\t2 - S/MIME\n" 1.629 + "\t\t3 - Object Signing\n" 1.630 + "\t\t4 - Reserved for future use\n" 1.631 + "\t\t5 - SSL CA\n" 1.632 + "\t\t6 - S/MIME CA\n" 1.633 + "\t\t7 - Object Signing CA\n" 1.634 + "\t\tOther to finish\n", 1.635 + buffer, sizeof(buffer)) == SECFailure) { 1.636 + return SECFailure; 1.637 + } 1.638 + value = PORT_Atoi (buffer); 1.639 + if (value < 0 || value > 7) 1.640 + break; 1.641 + if (value == 0) { 1.642 + /* Checking that zero value of variable 'value' 1.643 + * corresponds to '0' input made by user */ 1.644 + char *chPtr = strchr(buffer, '0'); 1.645 + if (chPtr == NULL) { 1.646 + continue; 1.647 + } 1.648 + } 1.649 + keyUsage |= (0x80 >> value); 1.650 + } 1.651 + isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); 1.652 + } else { 1.653 + while (1) { 1.654 + if (parseNextCmdInput(nsCertTypeKeyWordArray, &value, &nextPos, 1.655 + &isCriticalExt) == SECFailure) { 1.656 + return SECFailure; 1.657 + } 1.658 + keyUsage |= (0x80 >> value); 1.659 + if (!nextPos) 1.660 + break; 1.661 + } 1.662 + } 1.663 + 1.664 + bitStringValue.data = &keyUsage; 1.665 + bitStringValue.len = 1; 1.666 + 1.667 + return (CERT_EncodeAndAddBitStrExtension 1.668 + (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue, 1.669 + isCriticalExt)); 1.670 + 1.671 +} 1.672 + 1.673 +SECStatus 1.674 +GetOidFromString(PLArenaPool *arena, SECItem *to, 1.675 + const char *from, size_t fromLen) 1.676 +{ 1.677 + SECStatus rv; 1.678 + SECOidTag tag; 1.679 + SECOidData *coid; 1.680 + 1.681 + /* try dotted form first */ 1.682 + rv = SEC_StringToOID(arena, to, from, fromLen); 1.683 + if (rv == SECSuccess) { 1.684 + return rv; 1.685 + } 1.686 + 1.687 + /* Check to see if it matches a name in our oid table. 1.688 + * SECOID_FindOIDByTag returns NULL if tag is out of bounds. 1.689 + */ 1.690 + tag = SEC_OID_UNKNOWN; 1.691 + coid = SECOID_FindOIDByTag(tag); 1.692 + for ( ; coid; coid = SECOID_FindOIDByTag(++tag)) { 1.693 + if (PORT_Strncasecmp(from, coid->desc, fromLen) == 0) { 1.694 + break; 1.695 + } 1.696 + } 1.697 + if (coid == NULL) { 1.698 + /* none found */ 1.699 + return SECFailure; 1.700 + } 1.701 + return SECITEM_CopyItem(arena, to, &coid->oid); 1.702 +} 1.703 + 1.704 +static SECStatus 1.705 +AddSubjectAltNames(PLArenaPool *arena, CERTGeneralName **existingListp, 1.706 + const char *constNames, CERTGeneralNameType type) 1.707 +{ 1.708 + CERTGeneralName *nameList = NULL; 1.709 + CERTGeneralName *current = NULL; 1.710 + PRCList *prev = NULL; 1.711 + char *cp, *nextName = NULL; 1.712 + SECStatus rv = SECSuccess; 1.713 + PRBool readTypeFromName = (PRBool) (type == 0); 1.714 + char *names = NULL; 1.715 + 1.716 + if (constNames) 1.717 + names = PORT_Strdup(constNames); 1.718 + 1.719 + if (names == NULL) { 1.720 + return SECFailure; 1.721 + } 1.722 + 1.723 + /* 1.724 + * walk down the comma separated list of names. NOTE: there is 1.725 + * no sanity checks to see if the email address look like 1.726 + * email addresses. 1.727 + * 1.728 + * Each name may optionally be prefixed with a type: string. 1.729 + * If it isn't, the type from the previous name will be used. 1.730 + * If there wasn't a previous name yet, the type given 1.731 + * as a parameter to this function will be used. 1.732 + * If the type value is zero (undefined), we'll fail. 1.733 + */ 1.734 + for (cp=names; cp; cp=nextName) { 1.735 + int len; 1.736 + char *oidString; 1.737 + char *nextComma; 1.738 + CERTName *name; 1.739 + PRStatus status; 1.740 + unsigned char *data; 1.741 + PRNetAddr addr; 1.742 + 1.743 + nextName = NULL; 1.744 + if (*cp == ',') { 1.745 + cp++; 1.746 + } 1.747 + nextComma = PORT_Strchr(cp, ','); 1.748 + if (nextComma) { 1.749 + *nextComma = 0; 1.750 + nextName = nextComma+1; 1.751 + } 1.752 + if ((*cp) == 0) { 1.753 + continue; 1.754 + } 1.755 + if (readTypeFromName) { 1.756 + char *save=cp; 1.757 + /* Because we already replaced nextComma with end-of-string, 1.758 + * a found colon belongs to the current name */ 1.759 + cp = PORT_Strchr(cp, ':'); 1.760 + if (cp) { 1.761 + *cp = 0; 1.762 + cp++; 1.763 + type = CERT_GetGeneralNameTypeFromString(save); 1.764 + if (*cp == 0) { 1.765 + continue; 1.766 + } 1.767 + } else { 1.768 + if (type == 0) { 1.769 + /* no type known yet */ 1.770 + rv = SECFailure; 1.771 + break; 1.772 + } 1.773 + cp = save; 1.774 + } 1.775 + } 1.776 + 1.777 + current = PORT_ArenaZNew(arena, CERTGeneralName); 1.778 + if (!current) { 1.779 + rv = SECFailure; 1.780 + break; 1.781 + } 1.782 + 1.783 + current->type = type; 1.784 + switch (type) { 1.785 + /* string types */ 1.786 + case certRFC822Name: 1.787 + case certDNSName: 1.788 + case certURI: 1.789 + current->name.other.data = 1.790 + (unsigned char *) PORT_ArenaStrdup(arena,cp); 1.791 + current->name.other.len = PORT_Strlen(cp); 1.792 + break; 1.793 + /* unformated data types */ 1.794 + case certX400Address: 1.795 + case certEDIPartyName: 1.796 + /* turn a string into a data and len */ 1.797 + rv = SECFailure; /* punt on these for now */ 1.798 + fprintf(stderr,"EDI Party Name and X.400 Address not supported\n"); 1.799 + break; 1.800 + case certDirectoryName: 1.801 + /* certDirectoryName */ 1.802 + name = CERT_AsciiToName(cp); 1.803 + if (name == NULL) { 1.804 + rv = SECFailure; 1.805 + fprintf(stderr, "Invalid Directory Name (\"%s\")\n", cp); 1.806 + break; 1.807 + } 1.808 + rv = CERT_CopyName(arena,¤t->name.directoryName,name); 1.809 + CERT_DestroyName(name); 1.810 + break; 1.811 + /* types that require more processing */ 1.812 + case certIPAddress: 1.813 + /* convert the string to an ip address */ 1.814 + status = PR_StringToNetAddr(cp, &addr); 1.815 + if (status != PR_SUCCESS) { 1.816 + rv = SECFailure; 1.817 + fprintf(stderr, "Invalid IP Address (\"%s\")\n", cp); 1.818 + break; 1.819 + } 1.820 + 1.821 + if (PR_NetAddrFamily(&addr) == PR_AF_INET) { 1.822 + len = sizeof(addr.inet.ip); 1.823 + data = (unsigned char *)&addr.inet.ip; 1.824 + } else if (PR_NetAddrFamily(&addr) == PR_AF_INET6) { 1.825 + len = sizeof(addr.ipv6.ip); 1.826 + data = (unsigned char *)&addr.ipv6.ip; 1.827 + } else { 1.828 + fprintf(stderr, "Invalid IP Family\n"); 1.829 + rv = SECFailure; 1.830 + break; 1.831 + } 1.832 + current->name.other.data = PORT_ArenaAlloc(arena, len); 1.833 + if (current->name.other.data == NULL) { 1.834 + rv = SECFailure; 1.835 + break; 1.836 + } 1.837 + current->name.other.len = len; 1.838 + PORT_Memcpy(current->name.other.data,data, len); 1.839 + break; 1.840 + case certRegisterID: 1.841 + rv = GetOidFromString(arena, ¤t->name.other, cp, strlen(cp)); 1.842 + break; 1.843 + case certOtherName: 1.844 + oidString = cp; 1.845 + cp = PORT_Strchr(cp,';'); 1.846 + if (cp == NULL) { 1.847 + rv = SECFailure; 1.848 + fprintf(stderr, "missing name in other name\n"); 1.849 + break; 1.850 + } 1.851 + *cp++ = 0; 1.852 + current->name.OthName.name.data = 1.853 + (unsigned char *) PORT_ArenaStrdup(arena,cp); 1.854 + if (current->name.OthName.name.data == NULL) { 1.855 + rv = SECFailure; 1.856 + break; 1.857 + } 1.858 + current->name.OthName.name.len = PORT_Strlen(cp); 1.859 + rv = GetOidFromString(arena, ¤t->name.OthName.oid, 1.860 + oidString, strlen(oidString)); 1.861 + break; 1.862 + default: 1.863 + rv = SECFailure; 1.864 + fprintf(stderr, "Missing or invalid Subject Alternate Name type\n"); 1.865 + break; 1.866 + } 1.867 + if (rv == SECFailure) { 1.868 + break; 1.869 + } 1.870 + 1.871 + if (prev) { 1.872 + current->l.prev = prev; 1.873 + prev->next = &(current->l); 1.874 + } else { 1.875 + nameList = current; 1.876 + } 1.877 + prev = &(current->l); 1.878 + } 1.879 + PORT_Free(names); 1.880 + /* at this point nameList points to the head of a doubly linked, 1.881 + * but not yet circular, list and current points to its tail. */ 1.882 + if (rv == SECSuccess && nameList) { 1.883 + if (*existingListp != NULL) { 1.884 + PRCList *existingprev; 1.885 + /* add nameList to the end of the existing list */ 1.886 + existingprev = (*existingListp)->l.prev; 1.887 + (*existingListp)->l.prev = &(current->l); 1.888 + nameList->l.prev = existingprev; 1.889 + existingprev->next = &(nameList->l); 1.890 + current->l.next = &((*existingListp)->l); 1.891 + } 1.892 + else { 1.893 + /* make nameList circular and set it as the new existingList */ 1.894 + nameList->l.prev = prev; 1.895 + current->l.next = &(nameList->l); 1.896 + *existingListp = nameList; 1.897 + } 1.898 + } 1.899 + return rv; 1.900 +} 1.901 + 1.902 +static SECStatus 1.903 +AddEmailSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, 1.904 + const char *emailAddrs) 1.905 +{ 1.906 + return AddSubjectAltNames(arena, existingListp, emailAddrs, 1.907 + certRFC822Name); 1.908 +} 1.909 + 1.910 +static SECStatus 1.911 +AddDNSSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, 1.912 + const char *dnsNames) 1.913 +{ 1.914 + return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName); 1.915 +} 1.916 + 1.917 +static SECStatus 1.918 +AddGeneralSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, 1.919 + const char *altNames) 1.920 +{ 1.921 + return AddSubjectAltNames(arena, existingListp, altNames, 0); 1.922 +} 1.923 + 1.924 +static SECStatus 1.925 +AddBasicConstraint(void *extHandle) 1.926 +{ 1.927 + CERTBasicConstraints basicConstraint; 1.928 + SECStatus rv; 1.929 + char buffer[10]; 1.930 + PRBool yesNoAns; 1.931 + 1.932 + do { 1.933 + basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; 1.934 + basicConstraint.isCA = GetYesNo ("Is this a CA certificate [y/N]?"); 1.935 + 1.936 + buffer[0] = '\0'; 1.937 + if (PrintChoicesAndGetAnswer("Enter the path length constraint, " 1.938 + "enter to skip [<0 for unlimited path]:", 1.939 + buffer, sizeof(buffer)) == SECFailure) { 1.940 + GEN_BREAK(SECFailure); 1.941 + } 1.942 + if (PORT_Strlen (buffer) > 0) 1.943 + basicConstraint.pathLenConstraint = PORT_Atoi (buffer); 1.944 + 1.945 + yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); 1.946 + 1.947 + rv = SECU_EncodeAndAddExtensionValue(NULL, extHandle, 1.948 + &basicConstraint, yesNoAns, SEC_OID_X509_BASIC_CONSTRAINTS, 1.949 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeBasicConstraintValue); 1.950 + } while (0); 1.951 + 1.952 + return (rv); 1.953 +} 1.954 + 1.955 +static SECStatus 1.956 +AddNameConstraints(void *extHandle) 1.957 +{ 1.958 + PLArenaPool *arena = NULL; 1.959 + CERTNameConstraints *constraints = NULL; 1.960 + 1.961 + CERTNameConstraint *current = NULL; 1.962 + CERTNameConstraint *last_permited = NULL; 1.963 + CERTNameConstraint *last_excluded = NULL; 1.964 + SECStatus rv = SECSuccess; 1.965 + 1.966 + char buffer[512]; 1.967 + int intValue = 0; 1.968 + 1.969 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.970 + if (arena) { 1.971 + constraints = PORT_ArenaZNew(arena, CERTNameConstraints); 1.972 + } 1.973 + 1.974 + if (!arena || ! constraints) { 1.975 + SECU_PrintError(progName, "out of memory"); 1.976 + return SECFailure; 1.977 + } 1.978 + 1.979 + constraints->permited = constraints->excluded = NULL; 1.980 + 1.981 + do { 1.982 + current = PORT_ArenaZNew(arena, CERTNameConstraint); 1.983 + if (!current) { 1.984 + GEN_BREAK(SECFailure); 1.985 + } 1.986 + 1.987 + (void) SEC_ASN1EncodeInteger(arena, ¤t->min, 0); 1.988 + 1.989 + if (!GetGeneralName(arena, ¤t->name, PR_TRUE)) { 1.990 + GEN_BREAK(SECFailure); 1.991 + } 1.992 + 1.993 + PrintChoicesAndGetAnswer("Type of Name Constraint?\n" 1.994 + "\t1 - permitted\n\t2 - excluded\n\tAny" 1.995 + "other number to finish\n\tChoice", 1.996 + buffer, sizeof(buffer)); 1.997 + intValue = PORT_Atoi(buffer); 1.998 + switch (intValue) { 1.999 + case 1: 1.1000 + if (constraints->permited == NULL) { 1.1001 + constraints->permited = last_permited = current; 1.1002 + } 1.1003 + last_permited->l.next = &(current->l); 1.1004 + current->l.prev = &(last_permited->l); 1.1005 + last_permited = current; 1.1006 + break; 1.1007 + case 2: 1.1008 + if (constraints->excluded == NULL) { 1.1009 + constraints->excluded = last_excluded = current; 1.1010 + } 1.1011 + last_excluded->l.next = &(current->l); 1.1012 + current->l.prev = &(last_excluded->l); 1.1013 + last_excluded = current; 1.1014 + break; 1.1015 + } 1.1016 + 1.1017 + PR_snprintf(buffer, sizeof(buffer), "Add another entry to the" 1.1018 + " Name Constraint Extension [y/N]"); 1.1019 + 1.1020 + if (GetYesNo (buffer) == 0) { 1.1021 + break; 1.1022 + } 1.1023 + 1.1024 + } while (1); 1.1025 + 1.1026 + if (rv == SECSuccess) { 1.1027 + int oidIdent = SEC_OID_X509_NAME_CONSTRAINTS; 1.1028 + 1.1029 + PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1.1030 + 1.1031 + if (constraints->permited != NULL) { 1.1032 + last_permited->l.next = &(constraints->permited->l); 1.1033 + constraints->permited->l.prev = &(last_permited->l); 1.1034 + } 1.1035 + if (constraints->excluded != NULL) { 1.1036 + last_excluded->l.next = &(constraints->excluded->l); 1.1037 + constraints->excluded->l.prev = &(last_excluded->l); 1.1038 + } 1.1039 + 1.1040 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, constraints, 1.1041 + yesNoAns, oidIdent, 1.1042 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeNameConstraintsExtension); 1.1043 + } 1.1044 + if (arena) 1.1045 + PORT_FreeArena(arena, PR_FALSE); 1.1046 + return (rv); 1.1047 +} 1.1048 + 1.1049 +static SECStatus 1.1050 +AddAuthKeyID (void *extHandle) 1.1051 +{ 1.1052 + CERTAuthKeyID *authKeyID = NULL; 1.1053 + PLArenaPool *arena = NULL; 1.1054 + SECStatus rv = SECSuccess; 1.1055 + PRBool yesNoAns; 1.1056 + 1.1057 + do { 1.1058 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1059 + if ( !arena ) { 1.1060 + SECU_PrintError(progName, "out of memory"); 1.1061 + GEN_BREAK (SECFailure); 1.1062 + } 1.1063 + 1.1064 + if (GetYesNo ("Enter value for the authKeyID extension [y/N]?") == 0) 1.1065 + break; 1.1066 + 1.1067 + authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID); 1.1068 + if (authKeyID == NULL) { 1.1069 + GEN_BREAK (SECFailure); 1.1070 + } 1.1071 + 1.1072 + rv = GetString (arena, "Enter value for the key identifier fields," 1.1073 + "enter to omit:", &authKeyID->keyID); 1.1074 + if (rv != SECSuccess) 1.1075 + break; 1.1076 + 1.1077 + SECU_SECItemHexStringToBinary(&authKeyID->keyID); 1.1078 + 1.1079 + authKeyID->authCertIssuer = CreateGeneralName (arena); 1.1080 + if (authKeyID->authCertIssuer == NULL && 1.1081 + SECFailure == PORT_GetError ()) 1.1082 + break; 1.1083 + 1.1084 + 1.1085 + rv = GetString (arena, "Enter value for the authCertSerial field, " 1.1086 + "enter to omit:", &authKeyID->authCertSerialNumber); 1.1087 + 1.1088 + yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); 1.1089 + 1.1090 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, 1.1091 + authKeyID, yesNoAns, SEC_OID_X509_AUTH_KEY_ID, 1.1092 + (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID); 1.1093 + if (rv) 1.1094 + break; 1.1095 + 1.1096 + } while (0); 1.1097 + if (arena) 1.1098 + PORT_FreeArena (arena, PR_FALSE); 1.1099 + return (rv); 1.1100 +} 1.1101 + 1.1102 +static SECStatus 1.1103 +AddSubjKeyID (void *extHandle) 1.1104 +{ 1.1105 + SECItem keyID; 1.1106 + PLArenaPool *arena = NULL; 1.1107 + SECStatus rv = SECSuccess; 1.1108 + PRBool yesNoAns; 1.1109 + 1.1110 + do { 1.1111 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1112 + if ( !arena ) { 1.1113 + SECU_PrintError(progName, "out of memory"); 1.1114 + GEN_BREAK (SECFailure); 1.1115 + } 1.1116 + printf("Adding Subject Key ID extension.\n"); 1.1117 + 1.1118 + rv = GetString (arena, "Enter value for the key identifier fields," 1.1119 + "enter to omit:", &keyID); 1.1120 + if (rv != SECSuccess) 1.1121 + break; 1.1122 + 1.1123 + SECU_SECItemHexStringToBinary(&keyID); 1.1124 + 1.1125 + yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); 1.1126 + 1.1127 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, 1.1128 + &keyID, yesNoAns, SEC_OID_X509_SUBJECT_KEY_ID, 1.1129 + (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeSubjectKeyID); 1.1130 + if (rv) 1.1131 + break; 1.1132 + 1.1133 + } while (0); 1.1134 + if (arena) 1.1135 + PORT_FreeArena (arena, PR_FALSE); 1.1136 + return (rv); 1.1137 +} 1.1138 + 1.1139 +static SECStatus 1.1140 +AddCrlDistPoint(void *extHandle) 1.1141 +{ 1.1142 + PLArenaPool *arena = NULL; 1.1143 + CERTCrlDistributionPoints *crlDistPoints = NULL; 1.1144 + CRLDistributionPoint *current; 1.1145 + SECStatus rv = SECSuccess; 1.1146 + int count = 0, intValue; 1.1147 + char buffer[512]; 1.1148 + 1.1149 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1150 + if ( !arena ) 1.1151 + return (SECFailure); 1.1152 + 1.1153 + do { 1.1154 + current = NULL; 1.1155 + 1.1156 + current = PORT_ArenaZNew(arena, CRLDistributionPoint); 1.1157 + if (current == NULL) { 1.1158 + GEN_BREAK (SECFailure); 1.1159 + } 1.1160 + 1.1161 + /* Get the distributionPointName fields - this field is optional */ 1.1162 + if (PrintChoicesAndGetAnswer( 1.1163 + "Enter the type of the distribution point name:\n" 1.1164 + "\t1 - Full Name\n\t2 - Relative Name\n\tAny other " 1.1165 + "number to finish\n\t\tChoice: ", 1.1166 + buffer, sizeof(buffer)) == SECFailure) { 1.1167 + GEN_BREAK (SECFailure); 1.1168 + } 1.1169 + intValue = PORT_Atoi (buffer); 1.1170 + switch (intValue) { 1.1171 + case generalName: 1.1172 + current->distPointType = intValue; 1.1173 + current->distPoint.fullName = CreateGeneralName (arena); 1.1174 + rv = PORT_GetError(); 1.1175 + break; 1.1176 + 1.1177 + case relativeDistinguishedName: { 1.1178 + CERTName *name; 1.1179 + 1.1180 + current->distPointType = intValue; 1.1181 + puts ("Enter the relative name: "); 1.1182 + fflush (stdout); 1.1183 + if (Gets_s (buffer, sizeof(buffer)) == NULL) { 1.1184 + GEN_BREAK (SECFailure); 1.1185 + } 1.1186 + /* For simplicity, use CERT_AsciiToName to converse from a string 1.1187 + to NAME, but we only interest in the first RDN */ 1.1188 + name = CERT_AsciiToName (buffer); 1.1189 + if (!name) { 1.1190 + GEN_BREAK (SECFailure); 1.1191 + } 1.1192 + rv = CERT_CopyRDN (arena, ¤t->distPoint.relativeName, 1.1193 + name->rdns[0]); 1.1194 + CERT_DestroyName (name); 1.1195 + break; 1.1196 + } 1.1197 + } 1.1198 + if (rv != SECSuccess) 1.1199 + break; 1.1200 + 1.1201 + /* Get the reason flags */ 1.1202 + if (PrintChoicesAndGetAnswer( 1.1203 + "\nSelect one of the following for the reason flags\n" 1.1204 + "\t0 - unused\n\t1 - keyCompromise\n" 1.1205 + "\t2 - caCompromise\n\t3 - affiliationChanged\n" 1.1206 + "\t4 - superseded\n\t5 - cessationOfOperation\n" 1.1207 + "\t6 - certificateHold\n" 1.1208 + "\tAny other number to finish\t\tChoice: ", 1.1209 + buffer, sizeof(buffer)) == SECFailure) { 1.1210 + GEN_BREAK(SECFailure); 1.1211 + } 1.1212 + intValue = PORT_Atoi (buffer); 1.1213 + if (intValue == 0) { 1.1214 + /* Checking that zero value of variable 'value' 1.1215 + * corresponds to '0' input made by user */ 1.1216 + char *chPtr = strchr(buffer, '0'); 1.1217 + if (chPtr == NULL) { 1.1218 + intValue = -1; 1.1219 + } 1.1220 + } 1.1221 + if (intValue >= 0 && intValue <8) { 1.1222 + current->reasons.data = PORT_ArenaAlloc (arena, sizeof(char)); 1.1223 + if (current->reasons.data == NULL) { 1.1224 + GEN_BREAK (SECFailure); 1.1225 + } 1.1226 + *current->reasons.data = (char)(0x80 >> intValue); 1.1227 + current->reasons.len = 1; 1.1228 + } 1.1229 + puts ("Enter value for the CRL Issuer name:\n"); 1.1230 + current->crlIssuer = CreateGeneralName (arena); 1.1231 + if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure) 1.1232 + break; 1.1233 + 1.1234 + if (crlDistPoints == NULL) { 1.1235 + crlDistPoints = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); 1.1236 + if (crlDistPoints == NULL) { 1.1237 + GEN_BREAK (SECFailure); 1.1238 + } 1.1239 + } 1.1240 + 1.1241 + crlDistPoints->distPoints = 1.1242 + PORT_ArenaGrow (arena, crlDistPoints->distPoints, 1.1243 + sizeof (*crlDistPoints->distPoints) * count, 1.1244 + sizeof (*crlDistPoints->distPoints) *(count + 1)); 1.1245 + if (crlDistPoints->distPoints == NULL) { 1.1246 + GEN_BREAK (SECFailure); 1.1247 + } 1.1248 + 1.1249 + crlDistPoints->distPoints[count] = current; 1.1250 + ++count; 1.1251 + if (GetYesNo("Enter another value for the CRLDistributionPoint " 1.1252 + "extension [y/N]?") == 0) { 1.1253 + /* Add null to the end to mark end of data */ 1.1254 + crlDistPoints->distPoints = 1.1255 + PORT_ArenaGrow(arena, crlDistPoints->distPoints, 1.1256 + sizeof (*crlDistPoints->distPoints) * count, 1.1257 + sizeof (*crlDistPoints->distPoints) *(count + 1)); 1.1258 + crlDistPoints->distPoints[count] = NULL; 1.1259 + break; 1.1260 + } 1.1261 + 1.1262 + 1.1263 + } while (1); 1.1264 + 1.1265 + if (rv == SECSuccess) { 1.1266 + PRBool yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); 1.1267 + 1.1268 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, 1.1269 + crlDistPoints, yesNoAns, SEC_OID_X509_CRL_DIST_POINTS, 1.1270 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCRLDistributionPoints); 1.1271 + } 1.1272 + if (arena) 1.1273 + PORT_FreeArena (arena, PR_FALSE); 1.1274 + return (rv); 1.1275 +} 1.1276 + 1.1277 + 1.1278 + 1.1279 +static SECStatus 1.1280 +AddPolicyConstraints(void *extHandle) 1.1281 +{ 1.1282 + CERTCertificatePolicyConstraints *policyConstr; 1.1283 + PLArenaPool *arena = NULL; 1.1284 + SECStatus rv = SECSuccess; 1.1285 + SECItem *item, *dummy; 1.1286 + char buffer[512]; 1.1287 + int value; 1.1288 + PRBool yesNoAns; 1.1289 + PRBool skipExt = PR_TRUE; 1.1290 + 1.1291 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1292 + if ( !arena ) { 1.1293 + SECU_PrintError(progName, "out of memory"); 1.1294 + return SECFailure; 1.1295 + } 1.1296 + 1.1297 + policyConstr = PORT_ArenaZNew(arena, CERTCertificatePolicyConstraints); 1.1298 + if (policyConstr == NULL) { 1.1299 + SECU_PrintError(progName, "out of memory"); 1.1300 + goto loser; 1.1301 + } 1.1302 + 1.1303 + if (PrintChoicesAndGetAnswer("for requireExplicitPolicy enter the number " 1.1304 + "of certs in path\nbefore explicit policy is required\n" 1.1305 + "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) { 1.1306 + goto loser; 1.1307 + } 1.1308 + 1.1309 + if (PORT_Strlen(buffer)) { 1.1310 + value = PORT_Atoi(buffer); 1.1311 + if (value < 0) { 1.1312 + goto loser; 1.1313 + } 1.1314 + item = &policyConstr->explicitPolicySkipCerts; 1.1315 + dummy = SEC_ASN1EncodeInteger(arena, item, value); 1.1316 + if (!dummy) { 1.1317 + goto loser; 1.1318 + } 1.1319 + skipExt = PR_FALSE; 1.1320 + } 1.1321 + 1.1322 + if (PrintChoicesAndGetAnswer("for inihibitPolicyMapping enter " 1.1323 + "the number of certs in path\n" 1.1324 + "after which policy mapping is not allowed\n" 1.1325 + "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) { 1.1326 + goto loser; 1.1327 + } 1.1328 + 1.1329 + if (PORT_Strlen(buffer)) { 1.1330 + value = PORT_Atoi(buffer); 1.1331 + if (value < 0) { 1.1332 + goto loser; 1.1333 + } 1.1334 + item = &policyConstr->inhibitMappingSkipCerts; 1.1335 + dummy = SEC_ASN1EncodeInteger(arena, item, value); 1.1336 + if (!dummy) { 1.1337 + goto loser; 1.1338 + } 1.1339 + skipExt = PR_FALSE; 1.1340 + } 1.1341 + 1.1342 + 1.1343 + if (!skipExt) { 1.1344 + yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1.1345 + 1.1346 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, policyConstr, 1.1347 + yesNoAns, SEC_OID_X509_POLICY_CONSTRAINTS, 1.1348 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyConstraintsExtension); 1.1349 + } else { 1.1350 + fprintf(stdout, "Policy Constraint extensions must contain " 1.1351 + "at least one policy field\n"); 1.1352 + rv = SECFailure; 1.1353 + } 1.1354 + 1.1355 +loser: 1.1356 + if (arena) { 1.1357 + PORT_FreeArena (arena, PR_FALSE); 1.1358 + } 1.1359 + return (rv); 1.1360 +} 1.1361 + 1.1362 + 1.1363 +static SECStatus 1.1364 +AddInhibitAnyPolicy(void *extHandle) 1.1365 +{ 1.1366 + CERTCertificateInhibitAny certInhibitAny; 1.1367 + PLArenaPool *arena = NULL; 1.1368 + SECStatus rv = SECSuccess; 1.1369 + SECItem *item, *dummy; 1.1370 + char buffer[10]; 1.1371 + int value; 1.1372 + PRBool yesNoAns; 1.1373 + 1.1374 + 1.1375 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1376 + if ( !arena ) { 1.1377 + SECU_PrintError(progName, "out of memory"); 1.1378 + return SECFailure; 1.1379 + } 1.1380 + 1.1381 + if (PrintChoicesAndGetAnswer("Enter the number of certs in the path " 1.1382 + "permitted to use anyPolicy.\n" 1.1383 + "(press Enter for 0)", 1.1384 + buffer, sizeof(buffer)) == SECFailure) { 1.1385 + goto loser; 1.1386 + } 1.1387 + 1.1388 + item = &certInhibitAny.inhibitAnySkipCerts; 1.1389 + value = PORT_Atoi(buffer); 1.1390 + if (value < 0) { 1.1391 + goto loser; 1.1392 + } 1.1393 + dummy = SEC_ASN1EncodeInteger(arena, item, value); 1.1394 + if (!dummy) { 1.1395 + goto loser; 1.1396 + } 1.1397 + 1.1398 + yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1.1399 + 1.1400 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &certInhibitAny, 1.1401 + yesNoAns, SEC_OID_X509_INHIBIT_ANY_POLICY, 1.1402 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInhibitAnyExtension); 1.1403 +loser: 1.1404 + if (arena) { 1.1405 + PORT_FreeArena (arena, PR_FALSE); 1.1406 + } 1.1407 + return (rv); 1.1408 +} 1.1409 + 1.1410 + 1.1411 +static SECStatus 1.1412 +AddPolicyMappings(void *extHandle) 1.1413 +{ 1.1414 + CERTPolicyMap **policyMapArr = NULL; 1.1415 + CERTPolicyMap *current; 1.1416 + PLArenaPool *arena = NULL; 1.1417 + SECStatus rv = SECSuccess; 1.1418 + int count = 0; 1.1419 + char buffer[512]; 1.1420 + 1.1421 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1422 + if ( !arena ) { 1.1423 + SECU_PrintError(progName, "out of memory"); 1.1424 + return SECFailure; 1.1425 + } 1.1426 + 1.1427 + do { 1.1428 + if (PrintChoicesAndGetAnswer("Enter an Object Identifier (dotted " 1.1429 + "decimal format) for Issuer Domain Policy", 1.1430 + buffer, sizeof(buffer)) == SECFailure) { 1.1431 + GEN_BREAK (SECFailure); 1.1432 + } 1.1433 + 1.1434 + current = PORT_ArenaZNew(arena, CERTPolicyMap); 1.1435 + if (current == NULL) { 1.1436 + GEN_BREAK(SECFailure); 1.1437 + } 1.1438 + 1.1439 + rv = SEC_StringToOID(arena, ¤t->issuerDomainPolicy, buffer, 0); 1.1440 + if (rv == SECFailure) { 1.1441 + GEN_BREAK(SECFailure); 1.1442 + } 1.1443 + 1.1444 + if (PrintChoicesAndGetAnswer("Enter an Object Identifier for " 1.1445 + "Subject Domain Policy", 1.1446 + buffer, sizeof(buffer)) == SECFailure) { 1.1447 + GEN_BREAK (SECFailure); 1.1448 + } 1.1449 + 1.1450 + rv = SEC_StringToOID(arena, ¤t->subjectDomainPolicy, buffer, 0); 1.1451 + if (rv == SECFailure) { 1.1452 + GEN_BREAK(SECFailure); 1.1453 + } 1.1454 + 1.1455 + if (policyMapArr == NULL) { 1.1456 + policyMapArr = PORT_ArenaZNew(arena, CERTPolicyMap *); 1.1457 + if (policyMapArr == NULL) { 1.1458 + GEN_BREAK (SECFailure); 1.1459 + } 1.1460 + } 1.1461 + 1.1462 + policyMapArr = PORT_ArenaGrow(arena, policyMapArr, 1.1463 + sizeof (current) * count, 1.1464 + sizeof (current) *(count + 1)); 1.1465 + if (policyMapArr == NULL) { 1.1466 + GEN_BREAK (SECFailure); 1.1467 + } 1.1468 + 1.1469 + policyMapArr[count] = current; 1.1470 + ++count; 1.1471 + 1.1472 + if (!GetYesNo("Enter another Policy Mapping [y/N]")) { 1.1473 + /* Add null to the end to mark end of data */ 1.1474 + policyMapArr = PORT_ArenaGrow (arena, policyMapArr, 1.1475 + sizeof (current) * count, 1.1476 + sizeof (current) *(count + 1)); 1.1477 + if (policyMapArr == NULL) { 1.1478 + GEN_BREAK (SECFailure); 1.1479 + } 1.1480 + policyMapArr[count] = NULL; 1.1481 + break; 1.1482 + } 1.1483 + 1.1484 + } while (1); 1.1485 + 1.1486 + if (rv == SECSuccess) { 1.1487 + CERTCertificatePolicyMappings mappings; 1.1488 + PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1.1489 + 1.1490 + mappings.arena = arena; 1.1491 + mappings.policyMaps = policyMapArr; 1.1492 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &mappings, 1.1493 + yesNoAns, SEC_OID_X509_POLICY_MAPPINGS, 1.1494 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyMappingExtension); 1.1495 + } 1.1496 + if (arena) 1.1497 + PORT_FreeArena (arena, PR_FALSE); 1.1498 + return (rv); 1.1499 +} 1.1500 + 1.1501 +enum PoliciQualifierEnum { 1.1502 + cpsPointer = 1, 1.1503 + userNotice = 2 1.1504 +}; 1.1505 + 1.1506 + 1.1507 +static CERTPolicyQualifier ** 1.1508 +RequestPolicyQualifiers(PLArenaPool *arena, SECItem *policyID) 1.1509 +{ 1.1510 + CERTPolicyQualifier **policyQualifArr = NULL; 1.1511 + CERTPolicyQualifier *current; 1.1512 + SECStatus rv = SECSuccess; 1.1513 + int count = 0; 1.1514 + char buffer[512]; 1.1515 + void *mark; 1.1516 + SECOidData *oid = NULL; 1.1517 + int intValue = 0; 1.1518 + int inCount = 0; 1.1519 + 1.1520 + PORT_Assert(arena); 1.1521 + mark = PORT_ArenaMark(arena); 1.1522 + do { 1.1523 + current = PORT_ArenaZNew(arena, CERTPolicyQualifier); 1.1524 + if (current == NULL) { 1.1525 + GEN_BREAK(SECFailure); 1.1526 + } 1.1527 + 1.1528 + /* Get the accessMethod fields */ 1.1529 + SECU_PrintObjectID(stdout, policyID, 1.1530 + "Choose the type of qualifier for policy" , 0); 1.1531 + 1.1532 + if (PrintChoicesAndGetAnswer( 1.1533 + "\t1 - CPS Pointer qualifier\n" 1.1534 + "\t2 - User notice qualifier\n" 1.1535 + "\tAny other number to finish\n" 1.1536 + "\t\tChoice: ", buffer, sizeof(buffer)) == SECFailure) { 1.1537 + GEN_BREAK (SECFailure); 1.1538 + } 1.1539 + intValue = PORT_Atoi(buffer); 1.1540 + switch (intValue) { 1.1541 + case cpsPointer: { 1.1542 + SECItem input; 1.1543 + 1.1544 + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CPS_POINTER_QUALIFIER); 1.1545 + if (PrintChoicesAndGetAnswer("Enter CPS pointer URI: ", 1.1546 + buffer, sizeof(buffer)) == SECFailure) { 1.1547 + GEN_BREAK (SECFailure); 1.1548 + } 1.1549 + input.len = PORT_Strlen(buffer); 1.1550 + input.data = (void*)PORT_ArenaStrdup(arena, buffer); 1.1551 + if (input.data == NULL || 1.1552 + SEC_ASN1EncodeItem(arena, ¤t->qualifierValue, &input, 1.1553 + SEC_ASN1_GET(SEC_IA5StringTemplate)) == NULL) { 1.1554 + GEN_BREAK (SECFailure); 1.1555 + } 1.1556 + break; 1.1557 + } 1.1558 + case userNotice: { 1.1559 + SECItem **noticeNumArr; 1.1560 + CERTUserNotice *notice = PORT_ArenaZNew(arena, CERTUserNotice); 1.1561 + if (!notice) { 1.1562 + GEN_BREAK(SECFailure); 1.1563 + } 1.1564 + 1.1565 + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_USER_NOTICE_QUALIFIER); 1.1566 + 1.1567 + if (GetYesNo("\t add a User Notice reference? [y/N]")) { 1.1568 + 1.1569 + if (PrintChoicesAndGetAnswer("Enter user organization string: ", 1.1570 + buffer, sizeof(buffer)) == SECFailure) { 1.1571 + GEN_BREAK (SECFailure); 1.1572 + } 1.1573 + 1.1574 + notice->noticeReference.organization.type = siAsciiString; 1.1575 + notice->noticeReference.organization.len = 1.1576 + PORT_Strlen(buffer); 1.1577 + notice->noticeReference.organization.data = 1.1578 + (void*)PORT_ArenaStrdup(arena, buffer); 1.1579 + 1.1580 + 1.1581 + noticeNumArr = PORT_ArenaZNewArray(arena, SECItem *, 2); 1.1582 + if (!noticeNumArr) { 1.1583 + GEN_BREAK (SECFailure); 1.1584 + } 1.1585 + 1.1586 + do { 1.1587 + SECItem *noticeNum; 1.1588 + 1.1589 + noticeNum = PORT_ArenaZNew(arena, SECItem); 1.1590 + 1.1591 + if (PrintChoicesAndGetAnswer( 1.1592 + "Enter User Notice reference number " 1.1593 + "(or -1 to quit): ", 1.1594 + buffer, sizeof(buffer)) == SECFailure) { 1.1595 + GEN_BREAK (SECFailure); 1.1596 + } 1.1597 + 1.1598 + intValue = PORT_Atoi(buffer); 1.1599 + if (noticeNum == NULL) { 1.1600 + if (intValue < 0) { 1.1601 + fprintf(stdout, "a noticeReference must have at " 1.1602 + "least one reference number\n"); 1.1603 + GEN_BREAK (SECFailure); 1.1604 + } 1.1605 + } else { 1.1606 + if (intValue >= 0) { 1.1607 + noticeNumArr = PORT_ArenaGrow(arena, noticeNumArr, 1.1608 + sizeof (current) * inCount, 1.1609 + sizeof (current) *(inCount + 1)); 1.1610 + if (noticeNumArr == NULL) { 1.1611 + GEN_BREAK (SECFailure); 1.1612 + } 1.1613 + } else { 1.1614 + break; 1.1615 + } 1.1616 + } 1.1617 + if (!SEC_ASN1EncodeInteger(arena, noticeNum, intValue)) { 1.1618 + GEN_BREAK (SECFailure); 1.1619 + } 1.1620 + noticeNumArr[inCount++] = noticeNum; 1.1621 + noticeNumArr[inCount] = NULL; 1.1622 + 1.1623 + } while (1); 1.1624 + if (rv == SECFailure) { 1.1625 + GEN_BREAK(SECFailure); 1.1626 + } 1.1627 + notice->noticeReference.noticeNumbers = noticeNumArr; 1.1628 + rv = CERT_EncodeNoticeReference(arena, ¬ice->noticeReference, 1.1629 + ¬ice->derNoticeReference); 1.1630 + if (rv == SECFailure) { 1.1631 + GEN_BREAK(SECFailure); 1.1632 + } 1.1633 + } 1.1634 + if (GetYesNo("\t EnterUser Notice explicit text? [y/N]")) { 1.1635 + /* Getting only 200 bytes - RFC limitation */ 1.1636 + if (PrintChoicesAndGetAnswer( 1.1637 + "\t", buffer, 200) == SECFailure) { 1.1638 + GEN_BREAK (SECFailure); 1.1639 + } 1.1640 + notice->displayText.type = siAsciiString; 1.1641 + notice->displayText.len = PORT_Strlen(buffer); 1.1642 + notice->displayText.data = 1.1643 + (void*)PORT_ArenaStrdup(arena, buffer); 1.1644 + if (notice->displayText.data == NULL) { 1.1645 + GEN_BREAK(SECFailure); 1.1646 + } 1.1647 + } 1.1648 + 1.1649 + rv = CERT_EncodeUserNotice(arena, notice, ¤t->qualifierValue); 1.1650 + if (rv == SECFailure) { 1.1651 + GEN_BREAK(SECFailure); 1.1652 + } 1.1653 + 1.1654 + break; 1.1655 + } 1.1656 + } 1.1657 + if (rv == SECFailure || oid == NULL || 1.1658 + SECITEM_CopyItem(arena, ¤t->qualifierID, &oid->oid) 1.1659 + == SECFailure) { 1.1660 + GEN_BREAK (SECFailure); 1.1661 + } 1.1662 + 1.1663 + if (!policyQualifArr) { 1.1664 + policyQualifArr = PORT_ArenaZNew(arena, CERTPolicyQualifier *); 1.1665 + } else { 1.1666 + policyQualifArr = PORT_ArenaGrow (arena, policyQualifArr, 1.1667 + sizeof (current) * count, 1.1668 + sizeof (current) *(count + 1)); 1.1669 + } 1.1670 + if (policyQualifArr == NULL) { 1.1671 + GEN_BREAK (SECFailure); 1.1672 + } 1.1673 + 1.1674 + policyQualifArr[count] = current; 1.1675 + ++count; 1.1676 + 1.1677 + if (!GetYesNo ("Enter another policy qualifier [y/N]")) { 1.1678 + /* Add null to the end to mark end of data */ 1.1679 + policyQualifArr = PORT_ArenaGrow(arena, policyQualifArr, 1.1680 + sizeof (current) * count, 1.1681 + sizeof (current) *(count + 1)); 1.1682 + if (policyQualifArr == NULL) { 1.1683 + GEN_BREAK (SECFailure); 1.1684 + } 1.1685 + policyQualifArr[count] = NULL; 1.1686 + break; 1.1687 + } 1.1688 + 1.1689 + } while (1); 1.1690 + 1.1691 + if (rv != SECSuccess) { 1.1692 + PORT_ArenaRelease (arena, mark); 1.1693 + policyQualifArr = NULL; 1.1694 + } 1.1695 + return (policyQualifArr); 1.1696 +} 1.1697 + 1.1698 +static SECStatus 1.1699 +AddCertPolicies(void *extHandle) 1.1700 +{ 1.1701 + CERTPolicyInfo **certPoliciesArr = NULL; 1.1702 + CERTPolicyInfo *current; 1.1703 + PLArenaPool *arena = NULL; 1.1704 + SECStatus rv = SECSuccess; 1.1705 + int count = 0; 1.1706 + char buffer[512]; 1.1707 + 1.1708 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1709 + if ( !arena ) { 1.1710 + SECU_PrintError(progName, "out of memory"); 1.1711 + return SECFailure; 1.1712 + } 1.1713 + 1.1714 + do { 1.1715 + current = PORT_ArenaZNew(arena, CERTPolicyInfo); 1.1716 + if (current == NULL) { 1.1717 + GEN_BREAK(SECFailure); 1.1718 + } 1.1719 + 1.1720 + if (PrintChoicesAndGetAnswer("Enter a CertPolicy Object Identifier " 1.1721 + "(dotted decimal format)\n" 1.1722 + "or \"any\" for AnyPolicy:", 1.1723 + buffer, sizeof(buffer)) == SECFailure) { 1.1724 + GEN_BREAK (SECFailure); 1.1725 + } 1.1726 + 1.1727 + if (strncmp(buffer, "any", 3) == 0) { 1.1728 + /* use string version of X509_CERTIFICATE_POLICIES.anyPolicy */ 1.1729 + strcpy(buffer, "OID.2.5.29.32.0"); 1.1730 + } 1.1731 + rv = SEC_StringToOID(arena, ¤t->policyID, buffer, 0); 1.1732 + 1.1733 + if (rv == SECFailure) { 1.1734 + GEN_BREAK(SECFailure); 1.1735 + } 1.1736 + 1.1737 + current->policyQualifiers = 1.1738 + RequestPolicyQualifiers(arena, ¤t->policyID); 1.1739 + 1.1740 + if (!certPoliciesArr) { 1.1741 + certPoliciesArr = PORT_ArenaZNew(arena, CERTPolicyInfo *); 1.1742 + } else { 1.1743 + certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, 1.1744 + sizeof (current) * count, 1.1745 + sizeof (current) *(count + 1)); 1.1746 + } 1.1747 + if (certPoliciesArr == NULL) { 1.1748 + GEN_BREAK (SECFailure); 1.1749 + } 1.1750 + 1.1751 + certPoliciesArr[count] = current; 1.1752 + ++count; 1.1753 + 1.1754 + if (!GetYesNo ("Enter another PolicyInformation field [y/N]?")) { 1.1755 + /* Add null to the end to mark end of data */ 1.1756 + certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, 1.1757 + sizeof (current) * count, 1.1758 + sizeof (current) *(count + 1)); 1.1759 + if (certPoliciesArr == NULL) { 1.1760 + GEN_BREAK (SECFailure); 1.1761 + } 1.1762 + certPoliciesArr[count] = NULL; 1.1763 + break; 1.1764 + } 1.1765 + 1.1766 + } while (1); 1.1767 + 1.1768 + if (rv == SECSuccess) { 1.1769 + CERTCertificatePolicies policies; 1.1770 + PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1.1771 + 1.1772 + policies.arena = arena; 1.1773 + policies.policyInfos = certPoliciesArr; 1.1774 + 1.1775 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &policies, 1.1776 + yesNoAns, SEC_OID_X509_CERTIFICATE_POLICIES, 1.1777 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCertPoliciesExtension); 1.1778 + } 1.1779 + if (arena) 1.1780 + PORT_FreeArena(arena, PR_FALSE); 1.1781 + return (rv); 1.1782 +} 1.1783 + 1.1784 +enum AuthInfoAccessTypesEnum { 1.1785 + caIssuers = 1, 1.1786 + ocsp = 2 1.1787 +}; 1.1788 + 1.1789 +enum SubjInfoAccessTypesEnum { 1.1790 + caRepository = 1, 1.1791 + timeStamping = 2 1.1792 +}; 1.1793 + 1.1794 +/* Encode and add an AIA or SIA extension */ 1.1795 +static SECStatus 1.1796 +AddInfoAccess(void *extHandle, PRBool addSIAExt, PRBool isCACert) 1.1797 +{ 1.1798 + CERTAuthInfoAccess **infoAccArr = NULL; 1.1799 + CERTAuthInfoAccess *current; 1.1800 + PLArenaPool *arena = NULL; 1.1801 + SECStatus rv = SECSuccess; 1.1802 + int count = 0; 1.1803 + char buffer[512]; 1.1804 + SECOidData *oid = NULL; 1.1805 + int intValue = 0; 1.1806 + 1.1807 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1808 + if ( !arena ) { 1.1809 + SECU_PrintError(progName, "out of memory"); 1.1810 + return SECFailure; 1.1811 + } 1.1812 + 1.1813 + do { 1.1814 + current = NULL; 1.1815 + current = PORT_ArenaZNew(arena, CERTAuthInfoAccess); 1.1816 + if (current == NULL) { 1.1817 + GEN_BREAK(SECFailure); 1.1818 + } 1.1819 + 1.1820 + /* Get the accessMethod fields */ 1.1821 + if (addSIAExt) { 1.1822 + if (isCACert) { 1.1823 + puts("Adding \"CA Repository\" access method type for " 1.1824 + "Subject Information Access extension:\n"); 1.1825 + intValue = caRepository; 1.1826 + } else { 1.1827 + puts("Adding \"Time Stamping Services\" access method type for " 1.1828 + "Subject Information Access extension:\n"); 1.1829 + intValue = timeStamping; 1.1830 + } 1.1831 + } else { 1.1832 + PrintChoicesAndGetAnswer("Enter access method type " 1.1833 + "for Authority Information Access extension:\n" 1.1834 + "\t1 - CA Issuers\n\t2 - OCSP\n\tAny" 1.1835 + "other number to finish\n\tChoice", 1.1836 + buffer, sizeof(buffer)); 1.1837 + intValue = PORT_Atoi(buffer); 1.1838 + } 1.1839 + if (addSIAExt) { 1.1840 + switch (intValue) { 1.1841 + case caRepository: 1.1842 + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_REPOSITORY); 1.1843 + break; 1.1844 + 1.1845 + case timeStamping: 1.1846 + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_TIMESTAMPING); 1.1847 + break; 1.1848 + } 1.1849 + } else { 1.1850 + switch (intValue) { 1.1851 + case caIssuers: 1.1852 + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_ISSUERS); 1.1853 + break; 1.1854 + 1.1855 + case ocsp: 1.1856 + oid = SECOID_FindOIDByTag(SEC_OID_PKIX_OCSP); 1.1857 + break; 1.1858 + } 1.1859 + } 1.1860 + if (oid == NULL || 1.1861 + SECITEM_CopyItem(arena, ¤t->method, &oid->oid) 1.1862 + == SECFailure) { 1.1863 + GEN_BREAK (SECFailure); 1.1864 + } 1.1865 + 1.1866 + current->location = CreateGeneralName(arena); 1.1867 + if (!current->location) { 1.1868 + GEN_BREAK(SECFailure); 1.1869 + } 1.1870 + 1.1871 + if (infoAccArr == NULL) { 1.1872 + infoAccArr = PORT_ArenaZNew(arena, CERTAuthInfoAccess *); 1.1873 + } else { 1.1874 + infoAccArr = PORT_ArenaGrow(arena, infoAccArr, 1.1875 + sizeof (current) * count, 1.1876 + sizeof (current) *(count + 1)); 1.1877 + } 1.1878 + if (infoAccArr == NULL) { 1.1879 + GEN_BREAK (SECFailure); 1.1880 + } 1.1881 + 1.1882 + infoAccArr[count] = current; 1.1883 + ++count; 1.1884 + 1.1885 + PR_snprintf(buffer, sizeof(buffer), "Add another location to the %s" 1.1886 + " Information Access extension [y/N]", 1.1887 + (addSIAExt) ? "Subject" : "Authority"); 1.1888 + 1.1889 + if (GetYesNo (buffer) == 0) { 1.1890 + /* Add null to the end to mark end of data */ 1.1891 + infoAccArr = PORT_ArenaGrow(arena, infoAccArr, 1.1892 + sizeof (current) * count, 1.1893 + sizeof (current) *(count + 1)); 1.1894 + if (infoAccArr == NULL) { 1.1895 + GEN_BREAK (SECFailure); 1.1896 + } 1.1897 + infoAccArr[count] = NULL; 1.1898 + break; 1.1899 + } 1.1900 + 1.1901 + } while (1); 1.1902 + 1.1903 + if (rv == SECSuccess) { 1.1904 + int oidIdent = SEC_OID_X509_AUTH_INFO_ACCESS; 1.1905 + 1.1906 + PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); 1.1907 + 1.1908 + if (addSIAExt) { 1.1909 + oidIdent = SEC_OID_X509_SUBJECT_INFO_ACCESS; 1.1910 + } 1.1911 + rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, infoAccArr, 1.1912 + yesNoAns, oidIdent, 1.1913 + (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInfoAccessExtension); 1.1914 + } 1.1915 + if (arena) 1.1916 + PORT_FreeArena(arena, PR_FALSE); 1.1917 + return (rv); 1.1918 +} 1.1919 + 1.1920 +/* Example of valid input: 1.1921 + * 1.2.3.4:critical:/tmp/abc,5.6.7.8:not-critical:/tmp/xyz 1.1922 + */ 1.1923 +static SECStatus 1.1924 +parseNextGenericExt(const char *nextExtension, const char **oid, int *oidLen, 1.1925 + const char **crit, int *critLen, 1.1926 + const char **filename, int *filenameLen, 1.1927 + const char **next) 1.1928 +{ 1.1929 + const char *nextColon; 1.1930 + const char *nextComma; 1.1931 + const char *iter = nextExtension; 1.1932 + 1.1933 + if (!iter || !*iter) 1.1934 + return SECFailure; 1.1935 + 1.1936 + /* Require colons at earlier positions than nextComma (or end of string ) */ 1.1937 + nextComma = strchr(iter, ','); 1.1938 + 1.1939 + *oid = iter; 1.1940 + nextColon = strchr(iter, ':'); 1.1941 + if (!nextColon || (nextComma && nextColon > nextComma)) 1.1942 + return SECFailure; 1.1943 + *oidLen = (nextColon - *oid); 1.1944 + 1.1945 + if (!*oidLen) 1.1946 + return SECFailure; 1.1947 + 1.1948 + iter = nextColon; 1.1949 + ++iter; 1.1950 + 1.1951 + *crit = iter; 1.1952 + nextColon = strchr(iter, ':'); 1.1953 + if (!nextColon || (nextComma && nextColon > nextComma)) 1.1954 + return SECFailure; 1.1955 + *critLen = (nextColon - *crit); 1.1956 + 1.1957 + if (!*critLen) 1.1958 + return SECFailure; 1.1959 + 1.1960 + iter = nextColon; 1.1961 + ++iter; 1.1962 + 1.1963 + *filename = iter; 1.1964 + if (nextComma) { 1.1965 + *filenameLen = (nextComma - *filename); 1.1966 + iter = nextComma; 1.1967 + ++iter; 1.1968 + *next = iter; 1.1969 + } else { 1.1970 + *filenameLen = strlen(*filename); 1.1971 + *next = NULL; 1.1972 + } 1.1973 + 1.1974 + if (!*filenameLen) 1.1975 + return SECFailure; 1.1976 + 1.1977 + return SECSuccess; 1.1978 +} 1.1979 + 1.1980 +SECStatus 1.1981 +AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames, 1.1982 + certutilExtnList extList, const char *extGeneric) 1.1983 +{ 1.1984 + SECStatus rv = SECSuccess; 1.1985 + char *errstring = NULL; 1.1986 + const char *nextExtension = NULL; 1.1987 + 1.1988 + do { 1.1989 + /* Add key usage extension */ 1.1990 + if (extList[ext_keyUsage].activated) { 1.1991 + rv = AddKeyUsage(extHandle, extList[ext_keyUsage].arg); 1.1992 + if (rv) { 1.1993 + errstring = "KeyUsage"; 1.1994 + break; 1.1995 + } 1.1996 + } 1.1997 + 1.1998 + /* Add extended key usage extension */ 1.1999 + if (extList[ext_extKeyUsage].activated) { 1.2000 + rv = AddExtKeyUsage(extHandle, extList[ext_extKeyUsage].arg); 1.2001 + if (rv) { 1.2002 + errstring = "ExtendedKeyUsage"; 1.2003 + break; 1.2004 + } 1.2005 + } 1.2006 + 1.2007 + /* Add basic constraint extension */ 1.2008 + if (extList[ext_basicConstraint].activated) { 1.2009 + rv = AddBasicConstraint(extHandle); 1.2010 + if (rv) { 1.2011 + errstring = "BasicConstraint"; 1.2012 + break; 1.2013 + } 1.2014 + } 1.2015 + 1.2016 + /* Add name constraints extension */ 1.2017 + if (extList[ext_nameConstraints].activated) { 1.2018 + rv = AddNameConstraints(extHandle); 1.2019 + if (rv) { 1.2020 + errstring = "NameConstraints"; 1.2021 + break; 1.2022 + } 1.2023 + } 1.2024 + 1.2025 + if (extList[ext_authorityKeyID].activated) { 1.2026 + rv = AddAuthKeyID(extHandle); 1.2027 + if (rv) { 1.2028 + errstring = "AuthorityKeyID"; 1.2029 + break; 1.2030 + } 1.2031 + } 1.2032 + 1.2033 + if (extList[ext_subjectKeyID].activated) { 1.2034 + rv = AddSubjKeyID(extHandle); 1.2035 + if (rv) { 1.2036 + errstring = "SubjectKeyID"; 1.2037 + break; 1.2038 + } 1.2039 + } 1.2040 + 1.2041 + if (extList[ext_CRLDistPts].activated) { 1.2042 + rv = AddCrlDistPoint(extHandle); 1.2043 + if (rv) { 1.2044 + errstring = "CRLDistPoints"; 1.2045 + break; 1.2046 + } 1.2047 + } 1.2048 + 1.2049 + if (extList[ext_NSCertType].activated) { 1.2050 + rv = AddNscpCertType(extHandle, extList[ext_NSCertType].arg); 1.2051 + if (rv) { 1.2052 + errstring = "NSCertType"; 1.2053 + break; 1.2054 + } 1.2055 + } 1.2056 + 1.2057 + if (extList[ext_authInfoAcc].activated || 1.2058 + extList[ext_subjInfoAcc].activated) { 1.2059 + rv = AddInfoAccess(extHandle, extList[ext_subjInfoAcc].activated, 1.2060 + extList[ext_basicConstraint].activated); 1.2061 + if (rv) { 1.2062 + errstring = "InformationAccess"; 1.2063 + break; 1.2064 + } 1.2065 + } 1.2066 + 1.2067 + if (extList[ext_certPolicies].activated) { 1.2068 + rv = AddCertPolicies(extHandle); 1.2069 + if (rv) { 1.2070 + errstring = "Policies"; 1.2071 + break; 1.2072 + } 1.2073 + } 1.2074 + 1.2075 + if (extList[ext_policyMappings].activated) { 1.2076 + rv = AddPolicyMappings(extHandle); 1.2077 + if (rv) { 1.2078 + errstring = "PolicyMappings"; 1.2079 + break; 1.2080 + } 1.2081 + } 1.2082 + 1.2083 + if (extList[ext_policyConstr].activated) { 1.2084 + rv = AddPolicyConstraints(extHandle); 1.2085 + if (rv) { 1.2086 + errstring = "PolicyConstraints"; 1.2087 + break; 1.2088 + } 1.2089 + } 1.2090 + 1.2091 + if (extList[ext_inhibitAnyPolicy].activated) { 1.2092 + rv = AddInhibitAnyPolicy(extHandle); 1.2093 + if (rv) { 1.2094 + errstring = "InhibitAnyPolicy"; 1.2095 + break; 1.2096 + } 1.2097 + } 1.2098 + 1.2099 + if (emailAddrs || dnsNames || extList[ext_subjectAltName].activated) { 1.2100 + PLArenaPool *arena; 1.2101 + CERTGeneralName *namelist = NULL; 1.2102 + SECItem item = { 0, NULL, 0 }; 1.2103 + 1.2104 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.2105 + if (arena == NULL) { 1.2106 + rv = SECFailure; 1.2107 + break; 1.2108 + } 1.2109 + 1.2110 + rv = SECSuccess; 1.2111 + 1.2112 + if (emailAddrs) { 1.2113 + rv |= AddEmailSubjectAlt(arena, &namelist, emailAddrs); 1.2114 + } 1.2115 + 1.2116 + if (dnsNames) { 1.2117 + rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames); 1.2118 + } 1.2119 + 1.2120 + if (extList[ext_subjectAltName].activated) { 1.2121 + rv |= AddGeneralSubjectAlt(arena, &namelist, 1.2122 + extList[ext_subjectAltName].arg); 1.2123 + } 1.2124 + 1.2125 + if (rv == SECSuccess) { 1.2126 + rv = CERT_EncodeAltNameExtension(arena, namelist, &item); 1.2127 + if (rv == SECSuccess) { 1.2128 + rv = CERT_AddExtension(extHandle, 1.2129 + SEC_OID_X509_SUBJECT_ALT_NAME, 1.2130 + &item, PR_FALSE, PR_TRUE); 1.2131 + } 1.2132 + } 1.2133 + PORT_FreeArena(arena, PR_FALSE); 1.2134 + if (rv) { 1.2135 + errstring = "SubjectAltName"; 1.2136 + break; 1.2137 + } 1.2138 + } 1.2139 + } while (0); 1.2140 + 1.2141 + if (rv != SECSuccess) { 1.2142 + SECU_PrintError(progName, "Problem creating %s extension", errstring); 1.2143 + } 1.2144 + 1.2145 + nextExtension = extGeneric; 1.2146 + while (nextExtension && *nextExtension) { 1.2147 + SECItem oid_item, value; 1.2148 + PRBool isCritical; 1.2149 + const char *oid, *crit, *filename, *next; 1.2150 + int oidLen, critLen, filenameLen; 1.2151 + PRFileDesc *inFile = NULL; 1.2152 + char *zeroTerminatedFilename = NULL; 1.2153 + 1.2154 + rv = parseNextGenericExt(nextExtension, &oid, &oidLen, &crit, &critLen, 1.2155 + &filename, &filenameLen, &next); 1.2156 + if (rv!= SECSuccess) { 1.2157 + SECU_PrintError(progName, 1.2158 + "error parsing generic extension parameter %s", 1.2159 + nextExtension); 1.2160 + break; 1.2161 + } 1.2162 + oid_item.data = NULL; 1.2163 + oid_item.len = 0; 1.2164 + rv = GetOidFromString(NULL, &oid_item, oid, oidLen); 1.2165 + if (rv != SECSuccess) { 1.2166 + SECU_PrintError(progName, "malformed extension OID %s", nextExtension); 1.2167 + break; 1.2168 + } 1.2169 + if (!strncmp("critical", crit, critLen)) { 1.2170 + isCritical = PR_TRUE; 1.2171 + } else if (!strncmp("not-critical", crit, critLen)) { 1.2172 + isCritical = PR_FALSE; 1.2173 + } else { 1.2174 + rv = SECFailure; 1.2175 + SECU_PrintError(progName, "expected 'critical' or 'not-critical'"); 1.2176 + break; 1.2177 + } 1.2178 + zeroTerminatedFilename = PL_strndup(filename, filenameLen); 1.2179 + if (!zeroTerminatedFilename) { 1.2180 + rv = SECFailure; 1.2181 + SECU_PrintError(progName, "out of memory"); 1.2182 + break; 1.2183 + } 1.2184 + rv = SECFailure; 1.2185 + inFile = PR_Open(zeroTerminatedFilename, PR_RDONLY, 0); 1.2186 + if (inFile) { 1.2187 + rv = SECU_ReadDERFromFile(&value, inFile, PR_FALSE, PR_FALSE); 1.2188 + PR_Close(inFile); 1.2189 + inFile = NULL; 1.2190 + } 1.2191 + if (rv != SECSuccess) { 1.2192 + SECU_PrintError(progName, "unable to read file %s", 1.2193 + zeroTerminatedFilename); 1.2194 + } 1.2195 + PL_strfree(zeroTerminatedFilename); 1.2196 + if (rv != SECSuccess) { 1.2197 + break; 1.2198 + } 1.2199 + rv = CERT_AddExtensionByOID(extHandle, &oid_item, &value, isCritical, 1.2200 + PR_FALSE /*copyData*/); 1.2201 + if (rv != SECSuccess) { 1.2202 + SECITEM_FreeItem(&oid_item, PR_FALSE); 1.2203 + SECITEM_FreeItem(&value, PR_FALSE); 1.2204 + SECU_PrintError(progName, "failed to add extension %s", nextExtension); 1.2205 + break; 1.2206 + } 1.2207 + nextExtension = next; 1.2208 + } 1.2209 + 1.2210 + return rv; 1.2211 +}