michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: ** certext.c michael@0: ** michael@0: ** part of certutil for managing certificates extensions michael@0: ** michael@0: */ michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #if defined(WIN32) michael@0: #include "fcntl.h" michael@0: #include "io.h" michael@0: #endif michael@0: michael@0: #include "secutil.h" michael@0: michael@0: #if defined(XP_UNIX) michael@0: #include michael@0: #endif michael@0: michael@0: #include "cert.h" michael@0: #include "xconst.h" michael@0: #include "prprf.h" michael@0: #include "certutil.h" michael@0: #include "genname.h" michael@0: #include "prnetdb.h" michael@0: michael@0: #define GEN_BREAK(e) rv=e; break; michael@0: michael@0: static char * michael@0: Gets_s(char *buff, size_t size) { michael@0: char *str; michael@0: michael@0: if (buff == NULL || size < 1) { michael@0: PORT_Assert(0); michael@0: return NULL; michael@0: } michael@0: if ((str = fgets(buff, size, stdin)) != NULL) { michael@0: int len = PORT_Strlen(str); michael@0: /* michael@0: * fgets() automatically converts native text file michael@0: * line endings to '\n'. As defensive programming michael@0: * (just in case fgets has a bug or we put stdin in michael@0: * binary mode by mistake), we handle three native michael@0: * text file line endings here: michael@0: * '\n' Unix (including Linux and Mac OS X) michael@0: * '\r''\n' DOS/Windows & OS/2 michael@0: * '\r' Mac OS Classic michael@0: * len can not be less then 1, since in case with michael@0: * empty string it has at least '\n' in the buffer michael@0: */ michael@0: if (buff[len - 1] == '\n' || buff[len - 1] == '\r') { michael@0: buff[len - 1] = '\0'; michael@0: if (len > 1 && buff[len - 2] == '\r') michael@0: buff[len - 2] = '\0'; michael@0: } michael@0: } else { michael@0: buff[0] = '\0'; michael@0: } michael@0: return str; michael@0: } michael@0: michael@0: michael@0: static SECStatus michael@0: PrintChoicesAndGetAnswer(char* str, char* rBuff, int rSize) michael@0: { michael@0: fputs(str, stdout); michael@0: fputs(" > ", stdout); michael@0: fflush (stdout); michael@0: if (Gets_s(rBuff, rSize) == NULL) { michael@0: PORT_SetError(SEC_ERROR_INPUT_LEN); michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static CERTGeneralName * michael@0: GetGeneralName(PLArenaPool *arena, CERTGeneralName *useExistingName, PRBool onlyOne) michael@0: { michael@0: CERTGeneralName *namesList = NULL; michael@0: CERTGeneralName *current; michael@0: CERTGeneralName *tail = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: int intValue; michael@0: char buffer[512]; michael@0: void *mark; michael@0: michael@0: PORT_Assert (arena); michael@0: mark = PORT_ArenaMark (arena); michael@0: do { michael@0: if (PrintChoicesAndGetAnswer( michael@0: "\nSelect one of the following general name type: \n" michael@0: "\t2 - rfc822Name\n" michael@0: "\t3 - dnsName\n" michael@0: "\t5 - directoryName\n" michael@0: "\t7 - uniformResourceidentifier\n" michael@0: "\t8 - ipAddress\n" michael@0: "\t9 - registerID\n" michael@0: "\tAny other number to finish\n" michael@0: "\t\tChoice:", buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: intValue = PORT_Atoi (buffer); michael@0: /* michael@0: * Should use ZAlloc instead of Alloc to avoid problem with garbage michael@0: * initialized pointers in CERT_CopyName michael@0: */ michael@0: switch (intValue) { michael@0: case certRFC822Name: michael@0: case certDNSName: michael@0: case certDirectoryName: michael@0: case certURI: michael@0: case certIPAddress: michael@0: case certRegisterID: michael@0: break; michael@0: default: michael@0: intValue = 0; /* force a break for anything else */ michael@0: } michael@0: michael@0: if (intValue == 0) michael@0: break; michael@0: michael@0: if (namesList == NULL) { michael@0: if (useExistingName) { michael@0: namesList = current = tail = useExistingName; michael@0: } else { michael@0: namesList = current = tail = michael@0: PORT_ArenaZNew(arena, CERTGeneralName); michael@0: } michael@0: } else { michael@0: current = PORT_ArenaZNew(arena, CERTGeneralName); michael@0: } michael@0: if (current == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: current->type = intValue; michael@0: puts ("\nEnter data:"); michael@0: fflush (stdout); michael@0: if (Gets_s (buffer, sizeof(buffer)) == NULL) { michael@0: PORT_SetError(SEC_ERROR_INPUT_LEN); michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: switch (current->type) { michael@0: case certURI: michael@0: case certDNSName: michael@0: case certRFC822Name: michael@0: current->name.other.data = michael@0: PORT_ArenaAlloc (arena, strlen (buffer)); michael@0: if (current->name.other.data == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: PORT_Memcpy(current->name.other.data, buffer, michael@0: current->name.other.len = strlen(buffer)); michael@0: break; michael@0: michael@0: case certEDIPartyName: michael@0: case certIPAddress: michael@0: case certOtherName: michael@0: case certRegisterID: michael@0: case certX400Address: { michael@0: michael@0: current->name.other.data = michael@0: PORT_ArenaAlloc (arena, strlen (buffer) + 2); michael@0: if (current->name.other.data == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: PORT_Memcpy (current->name.other.data + 2, buffer, michael@0: strlen (buffer)); michael@0: /* This may not be accurate for all cases. For now, michael@0: * use this tag type */ michael@0: current->name.other.data[0] = michael@0: (char)(((current->type - 1) & 0x1f)| 0x80); michael@0: current->name.other.data[1] = (char)strlen (buffer); michael@0: current->name.other.len = strlen (buffer) + 2; michael@0: break; michael@0: } michael@0: michael@0: case certDirectoryName: { michael@0: CERTName *directoryName = NULL; michael@0: michael@0: directoryName = CERT_AsciiToName (buffer); michael@0: if (!directoryName) { michael@0: fprintf(stderr, "certutil: improperly formatted name: " michael@0: "\"%s\"\n", buffer); michael@0: break; michael@0: } michael@0: michael@0: rv = CERT_CopyName (arena, ¤t->name.directoryName, michael@0: directoryName); michael@0: CERT_DestroyName (directoryName); michael@0: michael@0: break; michael@0: } michael@0: } michael@0: if (rv != SECSuccess) michael@0: break; michael@0: current->l.next = &(namesList->l); michael@0: current->l.prev = &(tail->l); michael@0: tail->l.next = &(current->l); michael@0: tail = current; michael@0: michael@0: }while (!onlyOne); michael@0: michael@0: if (rv != SECSuccess) { michael@0: PORT_ArenaRelease (arena, mark); michael@0: namesList = NULL; michael@0: } michael@0: return (namesList); michael@0: } michael@0: michael@0: static CERTGeneralName * michael@0: CreateGeneralName(PLArenaPool *arena) michael@0: { michael@0: return GetGeneralName(arena, NULL, PR_FALSE); michael@0: } michael@0: michael@0: static SECStatus michael@0: GetString(PLArenaPool *arena, char *prompt, SECItem *value) michael@0: { michael@0: char buffer[251]; michael@0: char *buffPrt; michael@0: michael@0: buffer[0] = '\0'; michael@0: value->data = NULL; michael@0: value->len = 0; michael@0: michael@0: puts (prompt); michael@0: buffPrt = Gets_s (buffer, sizeof(buffer)); michael@0: /* returned NULL here treated the same way as empty string */ michael@0: if (buffPrt && strlen (buffer) > 0) { michael@0: value->data = PORT_ArenaAlloc (arena, strlen (buffer)); michael@0: if (value->data == NULL) { michael@0: PORT_SetError (SEC_ERROR_NO_MEMORY); michael@0: return (SECFailure); michael@0: } michael@0: PORT_Memcpy (value->data, buffer, value->len = strlen(buffer)); michael@0: } michael@0: return (SECSuccess); michael@0: } michael@0: michael@0: static PRBool michael@0: GetYesNo(char *prompt) michael@0: { michael@0: char buf[3]; michael@0: char *buffPrt; michael@0: michael@0: buf[0] = 'n'; michael@0: puts(prompt); michael@0: buffPrt = Gets_s(buf, sizeof(buf)); michael@0: return (buffPrt && (buf[0] == 'y' || buf[0] == 'Y')) ? PR_TRUE : PR_FALSE; michael@0: } michael@0: michael@0: /* Parses comma separated values out of the string pointed by nextPos. michael@0: * Parsed value is compared to an array of possible values(valueArray). michael@0: * If match is found, a value index is returned, otherwise returns SECFailue. michael@0: * nextPos is set to the token after found comma separator or to NULL. michael@0: * NULL in nextPos should be used as indication of the last parsed token. michael@0: * A special value "critical" can be parsed out from the supplied sting.*/ michael@0: michael@0: static SECStatus michael@0: parseNextCmdInput(const char * const *valueArray, int *value, char **nextPos, michael@0: PRBool *critical) michael@0: { michael@0: char *thisPos = *nextPos; michael@0: int keyLen = 0; michael@0: int arrIndex = 0; michael@0: michael@0: if (!valueArray || !value || !nextPos || !critical) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: while (1) { michael@0: if ((*nextPos = strchr(thisPos, ',')) == NULL) { michael@0: keyLen = strlen(thisPos); michael@0: } else { michael@0: keyLen = *nextPos - thisPos; michael@0: *nextPos += 1; michael@0: } michael@0: /* if critical keyword is found, go for another loop, michael@0: * but check, if it is the last keyword of michael@0: * the string.*/ michael@0: if (!strncmp("critical", thisPos, keyLen)) { michael@0: *critical = PR_TRUE; michael@0: if (*nextPos == NULL) { michael@0: return SECSuccess; michael@0: } michael@0: thisPos = *nextPos; michael@0: continue; michael@0: } michael@0: break; michael@0: } michael@0: for (arrIndex = 0; valueArray[arrIndex]; arrIndex++) { michael@0: if (!strncmp(valueArray[arrIndex], thisPos, keyLen)) { michael@0: *value = arrIndex; michael@0: return SECSuccess; michael@0: } michael@0: } michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: static const char * const michael@0: keyUsageKeyWordArray[] = { "digitalSignature", michael@0: "nonRepudiation", michael@0: "keyEncipherment", michael@0: "dataEncipherment", michael@0: "keyAgreement", michael@0: "certSigning", michael@0: "crlSigning", michael@0: NULL}; michael@0: michael@0: static SECStatus michael@0: AddKeyUsage (void *extHandle, const char *userSuppliedValue) michael@0: { michael@0: SECItem bitStringValue; michael@0: unsigned char keyUsage = 0x0; michael@0: char buffer[5]; michael@0: int value; michael@0: char *nextPos = (char*)userSuppliedValue; michael@0: PRBool isCriticalExt = PR_FALSE; michael@0: michael@0: if (!userSuppliedValue) { michael@0: while (1) { michael@0: if (PrintChoicesAndGetAnswer( michael@0: "\t\t0 - Digital Signature\n" michael@0: "\t\t1 - Non-repudiation\n" michael@0: "\t\t2 - Key encipherment\n" michael@0: "\t\t3 - Data encipherment\n" michael@0: "\t\t4 - Key agreement\n" michael@0: "\t\t5 - Cert signing key\n" michael@0: "\t\t6 - CRL signing key\n" michael@0: "\t\tOther to finish\n", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: return SECFailure; michael@0: } michael@0: value = PORT_Atoi (buffer); michael@0: if (value < 0 || value > 6) michael@0: break; michael@0: if (value == 0) { michael@0: /* Checking that zero value of variable 'value' michael@0: * corresponds to '0' input made by user */ michael@0: char *chPtr = strchr(buffer, '0'); michael@0: if (chPtr == NULL) { michael@0: continue; michael@0: } michael@0: } michael@0: keyUsage |= (0x80 >> value); michael@0: } michael@0: isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); michael@0: } else { michael@0: while (1) { michael@0: if (parseNextCmdInput(keyUsageKeyWordArray, &value, &nextPos, michael@0: &isCriticalExt) == SECFailure) { michael@0: return SECFailure; michael@0: } michael@0: keyUsage |= (0x80 >> value); michael@0: if (!nextPos) michael@0: break; michael@0: } michael@0: } michael@0: michael@0: bitStringValue.data = &keyUsage; michael@0: bitStringValue.len = 1; michael@0: michael@0: return (CERT_EncodeAndAddBitStrExtension michael@0: (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue, michael@0: isCriticalExt)); michael@0: michael@0: } michael@0: michael@0: michael@0: static CERTOidSequence * michael@0: CreateOidSequence(void) michael@0: { michael@0: CERTOidSequence *rv = (CERTOidSequence *)NULL; michael@0: PLArenaPool *arena = (PLArenaPool *)NULL; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if( (PLArenaPool *)NULL == arena ) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv = (CERTOidSequence *)PORT_ArenaZNew(arena, CERTOidSequence); michael@0: if( (CERTOidSequence *)NULL == rv ) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv->oids = (SECItem **)PORT_ArenaZNew(arena, SECItem *); michael@0: if( (SECItem **)NULL == rv->oids ) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv->arena = arena; michael@0: return rv; michael@0: michael@0: loser: michael@0: if( (PLArenaPool *)NULL != arena ) { michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: michael@0: return (CERTOidSequence *)NULL; michael@0: } michael@0: michael@0: static void michael@0: DestroyOidSequence(CERTOidSequence *os) michael@0: { michael@0: if (os->arena) { michael@0: PORT_FreeArena(os->arena, PR_FALSE); michael@0: } michael@0: } michael@0: michael@0: static SECStatus michael@0: AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag) michael@0: { michael@0: SECItem **oids; michael@0: PRUint32 count = 0; michael@0: SECOidData *od; michael@0: michael@0: od = SECOID_FindOIDByTag(oidTag); michael@0: if( (SECOidData *)NULL == od ) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) { michael@0: if (*oids == &od->oid) { michael@0: /* We already have this oid */ michael@0: return SECSuccess; michael@0: } michael@0: count++; michael@0: } michael@0: michael@0: /* ArenaZRealloc */ michael@0: michael@0: { michael@0: PRUint32 i; michael@0: michael@0: oids = (SECItem **)PORT_ArenaZNewArray(os->arena, SECItem *, count + 2); michael@0: if( (SECItem **)NULL == oids ) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: for( i = 0; i < count; i++ ) { michael@0: oids[i] = os->oids[i]; michael@0: } michael@0: michael@0: /* ArenaZFree(os->oids); */ michael@0: } michael@0: michael@0: os->oids = oids; michael@0: os->oids[count] = &od->oid; michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) michael@0: michael@0: const SEC_ASN1Template CERT_OidSeqTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, offsetof(CERTOidSequence, oids), michael@0: SEC_ASN1_SUB(SEC_ObjectIDTemplate) } michael@0: }; michael@0: michael@0: michael@0: static SECItem * michael@0: EncodeOidSequence(CERTOidSequence *os) michael@0: { michael@0: SECItem *rv; michael@0: michael@0: rv = (SECItem *)PORT_ArenaZNew(os->arena, SECItem); michael@0: if( (SECItem *)NULL == rv ) { michael@0: goto loser; michael@0: } michael@0: michael@0: if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) { michael@0: goto loser; michael@0: } michael@0: michael@0: return rv; michael@0: michael@0: loser: michael@0: return (SECItem *)NULL; michael@0: } michael@0: michael@0: static const char * const michael@0: extKeyUsageKeyWordArray[] = { "serverAuth", michael@0: "clientAuth", michael@0: "codeSigning", michael@0: "emailProtection", michael@0: "timeStamp", michael@0: "ocspResponder", michael@0: "stepUp", michael@0: "msTrustListSigning", michael@0: NULL}; michael@0: michael@0: static SECStatus michael@0: AddExtKeyUsage (void *extHandle, const char *userSuppliedValue) michael@0: { michael@0: char buffer[5]; michael@0: int value; michael@0: CERTOidSequence *os; michael@0: SECStatus rv; michael@0: SECItem *item; michael@0: PRBool isCriticalExt = PR_FALSE; michael@0: char *nextPos = (char*)userSuppliedValue; michael@0: michael@0: os = CreateOidSequence(); michael@0: if( (CERTOidSequence *)NULL == os ) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: while (1) { michael@0: if (!userSuppliedValue) { michael@0: if (PrintChoicesAndGetAnswer( michael@0: "\t\t0 - Server Auth\n" michael@0: "\t\t1 - Client Auth\n" michael@0: "\t\t2 - Code Signing\n" michael@0: "\t\t3 - Email Protection\n" michael@0: "\t\t4 - Timestamp\n" michael@0: "\t\t5 - OCSP Responder\n" michael@0: "\t\t6 - Step-up\n" michael@0: "\t\t7 - Microsoft Trust List Signing\n" michael@0: "\t\tOther to finish\n", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: value = PORT_Atoi(buffer); michael@0: michael@0: if (value == 0) { michael@0: /* Checking that zero value of variable 'value' michael@0: * corresponds to '0' input made by user */ michael@0: char *chPtr = strchr(buffer, '0'); michael@0: if (chPtr == NULL) { michael@0: continue; michael@0: } michael@0: } michael@0: } else { michael@0: if (parseNextCmdInput(extKeyUsageKeyWordArray, &value, &nextPos, michael@0: &isCriticalExt) == SECFailure) { michael@0: return SECFailure; michael@0: } michael@0: } michael@0: michael@0: switch( value ) { michael@0: case 0: michael@0: rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH); michael@0: break; michael@0: case 1: michael@0: rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH); michael@0: break; michael@0: case 2: michael@0: rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN); michael@0: break; michael@0: case 3: michael@0: rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT); michael@0: break; michael@0: case 4: michael@0: rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP); michael@0: break; michael@0: case 5: michael@0: rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER); michael@0: break; michael@0: case 6: michael@0: rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED); michael@0: break; michael@0: case 7: michael@0: rv = AddOidToSequence(os, SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING); michael@0: break; michael@0: default: michael@0: goto endloop; michael@0: } michael@0: michael@0: if (userSuppliedValue && !nextPos) michael@0: break; michael@0: if( SECSuccess != rv ) michael@0: goto loser; michael@0: } michael@0: michael@0: endloop: michael@0: item = EncodeOidSequence(os); michael@0: michael@0: if (!userSuppliedValue) { michael@0: isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); michael@0: } michael@0: michael@0: rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item, michael@0: isCriticalExt, PR_TRUE); michael@0: /*FALLTHROUGH*/ michael@0: loser: michael@0: DestroyOidSequence(os); michael@0: return rv; michael@0: } michael@0: michael@0: static const char * const michael@0: nsCertTypeKeyWordArray[] = { "sslClient", michael@0: "sslServer", michael@0: "smime", michael@0: "objectSigning", michael@0: "Not!Used", michael@0: "sslCA", michael@0: "smimeCA", michael@0: "objectSigningCA", michael@0: NULL }; michael@0: michael@0: static SECStatus michael@0: AddNscpCertType (void *extHandle, const char *userSuppliedValue) michael@0: { michael@0: SECItem bitStringValue; michael@0: unsigned char keyUsage = 0x0; michael@0: char buffer[5]; michael@0: int value; michael@0: char *nextPos = (char*)userSuppliedValue; michael@0: PRBool isCriticalExt = PR_FALSE; michael@0: michael@0: if (!userSuppliedValue) { michael@0: while (1) { michael@0: if (PrintChoicesAndGetAnswer( michael@0: "\t\t0 - SSL Client\n" michael@0: "\t\t1 - SSL Server\n" michael@0: "\t\t2 - S/MIME\n" michael@0: "\t\t3 - Object Signing\n" michael@0: "\t\t4 - Reserved for future use\n" michael@0: "\t\t5 - SSL CA\n" michael@0: "\t\t6 - S/MIME CA\n" michael@0: "\t\t7 - Object Signing CA\n" michael@0: "\t\tOther to finish\n", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: return SECFailure; michael@0: } michael@0: value = PORT_Atoi (buffer); michael@0: if (value < 0 || value > 7) michael@0: break; michael@0: if (value == 0) { michael@0: /* Checking that zero value of variable 'value' michael@0: * corresponds to '0' input made by user */ michael@0: char *chPtr = strchr(buffer, '0'); michael@0: if (chPtr == NULL) { michael@0: continue; michael@0: } michael@0: } michael@0: keyUsage |= (0x80 >> value); michael@0: } michael@0: isCriticalExt = GetYesNo("Is this a critical extension [y/N]?"); michael@0: } else { michael@0: while (1) { michael@0: if (parseNextCmdInput(nsCertTypeKeyWordArray, &value, &nextPos, michael@0: &isCriticalExt) == SECFailure) { michael@0: return SECFailure; michael@0: } michael@0: keyUsage |= (0x80 >> value); michael@0: if (!nextPos) michael@0: break; michael@0: } michael@0: } michael@0: michael@0: bitStringValue.data = &keyUsage; michael@0: bitStringValue.len = 1; michael@0: michael@0: return (CERT_EncodeAndAddBitStrExtension michael@0: (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue, michael@0: isCriticalExt)); michael@0: michael@0: } michael@0: michael@0: SECStatus michael@0: GetOidFromString(PLArenaPool *arena, SECItem *to, michael@0: const char *from, size_t fromLen) michael@0: { michael@0: SECStatus rv; michael@0: SECOidTag tag; michael@0: SECOidData *coid; michael@0: michael@0: /* try dotted form first */ michael@0: rv = SEC_StringToOID(arena, to, from, fromLen); michael@0: if (rv == SECSuccess) { michael@0: return rv; michael@0: } michael@0: michael@0: /* Check to see if it matches a name in our oid table. michael@0: * SECOID_FindOIDByTag returns NULL if tag is out of bounds. michael@0: */ michael@0: tag = SEC_OID_UNKNOWN; michael@0: coid = SECOID_FindOIDByTag(tag); michael@0: for ( ; coid; coid = SECOID_FindOIDByTag(++tag)) { michael@0: if (PORT_Strncasecmp(from, coid->desc, fromLen) == 0) { michael@0: break; michael@0: } michael@0: } michael@0: if (coid == NULL) { michael@0: /* none found */ michael@0: return SECFailure; michael@0: } michael@0: return SECITEM_CopyItem(arena, to, &coid->oid); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddSubjectAltNames(PLArenaPool *arena, CERTGeneralName **existingListp, michael@0: const char *constNames, CERTGeneralNameType type) michael@0: { michael@0: CERTGeneralName *nameList = NULL; michael@0: CERTGeneralName *current = NULL; michael@0: PRCList *prev = NULL; michael@0: char *cp, *nextName = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: PRBool readTypeFromName = (PRBool) (type == 0); michael@0: char *names = NULL; michael@0: michael@0: if (constNames) michael@0: names = PORT_Strdup(constNames); michael@0: michael@0: if (names == NULL) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: /* michael@0: * walk down the comma separated list of names. NOTE: there is michael@0: * no sanity checks to see if the email address look like michael@0: * email addresses. michael@0: * michael@0: * Each name may optionally be prefixed with a type: string. michael@0: * If it isn't, the type from the previous name will be used. michael@0: * If there wasn't a previous name yet, the type given michael@0: * as a parameter to this function will be used. michael@0: * If the type value is zero (undefined), we'll fail. michael@0: */ michael@0: for (cp=names; cp; cp=nextName) { michael@0: int len; michael@0: char *oidString; michael@0: char *nextComma; michael@0: CERTName *name; michael@0: PRStatus status; michael@0: unsigned char *data; michael@0: PRNetAddr addr; michael@0: michael@0: nextName = NULL; michael@0: if (*cp == ',') { michael@0: cp++; michael@0: } michael@0: nextComma = PORT_Strchr(cp, ','); michael@0: if (nextComma) { michael@0: *nextComma = 0; michael@0: nextName = nextComma+1; michael@0: } michael@0: if ((*cp) == 0) { michael@0: continue; michael@0: } michael@0: if (readTypeFromName) { michael@0: char *save=cp; michael@0: /* Because we already replaced nextComma with end-of-string, michael@0: * a found colon belongs to the current name */ michael@0: cp = PORT_Strchr(cp, ':'); michael@0: if (cp) { michael@0: *cp = 0; michael@0: cp++; michael@0: type = CERT_GetGeneralNameTypeFromString(save); michael@0: if (*cp == 0) { michael@0: continue; michael@0: } michael@0: } else { michael@0: if (type == 0) { michael@0: /* no type known yet */ michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: cp = save; michael@0: } michael@0: } michael@0: michael@0: current = PORT_ArenaZNew(arena, CERTGeneralName); michael@0: if (!current) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: michael@0: current->type = type; michael@0: switch (type) { michael@0: /* string types */ michael@0: case certRFC822Name: michael@0: case certDNSName: michael@0: case certURI: michael@0: current->name.other.data = michael@0: (unsigned char *) PORT_ArenaStrdup(arena,cp); michael@0: current->name.other.len = PORT_Strlen(cp); michael@0: break; michael@0: /* unformated data types */ michael@0: case certX400Address: michael@0: case certEDIPartyName: michael@0: /* turn a string into a data and len */ michael@0: rv = SECFailure; /* punt on these for now */ michael@0: fprintf(stderr,"EDI Party Name and X.400 Address not supported\n"); michael@0: break; michael@0: case certDirectoryName: michael@0: /* certDirectoryName */ michael@0: name = CERT_AsciiToName(cp); michael@0: if (name == NULL) { michael@0: rv = SECFailure; michael@0: fprintf(stderr, "Invalid Directory Name (\"%s\")\n", cp); michael@0: break; michael@0: } michael@0: rv = CERT_CopyName(arena,¤t->name.directoryName,name); michael@0: CERT_DestroyName(name); michael@0: break; michael@0: /* types that require more processing */ michael@0: case certIPAddress: michael@0: /* convert the string to an ip address */ michael@0: status = PR_StringToNetAddr(cp, &addr); michael@0: if (status != PR_SUCCESS) { michael@0: rv = SECFailure; michael@0: fprintf(stderr, "Invalid IP Address (\"%s\")\n", cp); michael@0: break; michael@0: } michael@0: michael@0: if (PR_NetAddrFamily(&addr) == PR_AF_INET) { michael@0: len = sizeof(addr.inet.ip); michael@0: data = (unsigned char *)&addr.inet.ip; michael@0: } else if (PR_NetAddrFamily(&addr) == PR_AF_INET6) { michael@0: len = sizeof(addr.ipv6.ip); michael@0: data = (unsigned char *)&addr.ipv6.ip; michael@0: } else { michael@0: fprintf(stderr, "Invalid IP Family\n"); michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: current->name.other.data = PORT_ArenaAlloc(arena, len); michael@0: if (current->name.other.data == NULL) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: current->name.other.len = len; michael@0: PORT_Memcpy(current->name.other.data,data, len); michael@0: break; michael@0: case certRegisterID: michael@0: rv = GetOidFromString(arena, ¤t->name.other, cp, strlen(cp)); michael@0: break; michael@0: case certOtherName: michael@0: oidString = cp; michael@0: cp = PORT_Strchr(cp,';'); michael@0: if (cp == NULL) { michael@0: rv = SECFailure; michael@0: fprintf(stderr, "missing name in other name\n"); michael@0: break; michael@0: } michael@0: *cp++ = 0; michael@0: current->name.OthName.name.data = michael@0: (unsigned char *) PORT_ArenaStrdup(arena,cp); michael@0: if (current->name.OthName.name.data == NULL) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: current->name.OthName.name.len = PORT_Strlen(cp); michael@0: rv = GetOidFromString(arena, ¤t->name.OthName.oid, michael@0: oidString, strlen(oidString)); michael@0: break; michael@0: default: michael@0: rv = SECFailure; michael@0: fprintf(stderr, "Missing or invalid Subject Alternate Name type\n"); michael@0: break; michael@0: } michael@0: if (rv == SECFailure) { michael@0: break; michael@0: } michael@0: michael@0: if (prev) { michael@0: current->l.prev = prev; michael@0: prev->next = &(current->l); michael@0: } else { michael@0: nameList = current; michael@0: } michael@0: prev = &(current->l); michael@0: } michael@0: PORT_Free(names); michael@0: /* at this point nameList points to the head of a doubly linked, michael@0: * but not yet circular, list and current points to its tail. */ michael@0: if (rv == SECSuccess && nameList) { michael@0: if (*existingListp != NULL) { michael@0: PRCList *existingprev; michael@0: /* add nameList to the end of the existing list */ michael@0: existingprev = (*existingListp)->l.prev; michael@0: (*existingListp)->l.prev = &(current->l); michael@0: nameList->l.prev = existingprev; michael@0: existingprev->next = &(nameList->l); michael@0: current->l.next = &((*existingListp)->l); michael@0: } michael@0: else { michael@0: /* make nameList circular and set it as the new existingList */ michael@0: nameList->l.prev = prev; michael@0: current->l.next = &(nameList->l); michael@0: *existingListp = nameList; michael@0: } michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: static SECStatus michael@0: AddEmailSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, michael@0: const char *emailAddrs) michael@0: { michael@0: return AddSubjectAltNames(arena, existingListp, emailAddrs, michael@0: certRFC822Name); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddDNSSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, michael@0: const char *dnsNames) michael@0: { michael@0: return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddGeneralSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp, michael@0: const char *altNames) michael@0: { michael@0: return AddSubjectAltNames(arena, existingListp, altNames, 0); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddBasicConstraint(void *extHandle) michael@0: { michael@0: CERTBasicConstraints basicConstraint; michael@0: SECStatus rv; michael@0: char buffer[10]; michael@0: PRBool yesNoAns; michael@0: michael@0: do { michael@0: basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; michael@0: basicConstraint.isCA = GetYesNo ("Is this a CA certificate [y/N]?"); michael@0: michael@0: buffer[0] = '\0'; michael@0: if (PrintChoicesAndGetAnswer("Enter the path length constraint, " michael@0: "enter to skip [<0 for unlimited path]:", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: if (PORT_Strlen (buffer) > 0) michael@0: basicConstraint.pathLenConstraint = PORT_Atoi (buffer); michael@0: michael@0: yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(NULL, extHandle, michael@0: &basicConstraint, yesNoAns, SEC_OID_X509_BASIC_CONSTRAINTS, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeBasicConstraintValue); michael@0: } while (0); michael@0: michael@0: return (rv); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddNameConstraints(void *extHandle) michael@0: { michael@0: PLArenaPool *arena = NULL; michael@0: CERTNameConstraints *constraints = NULL; michael@0: michael@0: CERTNameConstraint *current = NULL; michael@0: CERTNameConstraint *last_permited = NULL; michael@0: CERTNameConstraint *last_excluded = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: michael@0: char buffer[512]; michael@0: int intValue = 0; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena) { michael@0: constraints = PORT_ArenaZNew(arena, CERTNameConstraints); michael@0: } michael@0: michael@0: if (!arena || ! constraints) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: constraints->permited = constraints->excluded = NULL; michael@0: michael@0: do { michael@0: current = PORT_ArenaZNew(arena, CERTNameConstraint); michael@0: if (!current) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: (void) SEC_ASN1EncodeInteger(arena, ¤t->min, 0); michael@0: michael@0: if (!GetGeneralName(arena, ¤t->name, PR_TRUE)) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: PrintChoicesAndGetAnswer("Type of Name Constraint?\n" michael@0: "\t1 - permitted\n\t2 - excluded\n\tAny" michael@0: "other number to finish\n\tChoice", michael@0: buffer, sizeof(buffer)); michael@0: intValue = PORT_Atoi(buffer); michael@0: switch (intValue) { michael@0: case 1: michael@0: if (constraints->permited == NULL) { michael@0: constraints->permited = last_permited = current; michael@0: } michael@0: last_permited->l.next = &(current->l); michael@0: current->l.prev = &(last_permited->l); michael@0: last_permited = current; michael@0: break; michael@0: case 2: michael@0: if (constraints->excluded == NULL) { michael@0: constraints->excluded = last_excluded = current; michael@0: } michael@0: last_excluded->l.next = &(current->l); michael@0: current->l.prev = &(last_excluded->l); michael@0: last_excluded = current; michael@0: break; michael@0: } michael@0: michael@0: PR_snprintf(buffer, sizeof(buffer), "Add another entry to the" michael@0: " Name Constraint Extension [y/N]"); michael@0: michael@0: if (GetYesNo (buffer) == 0) { michael@0: break; michael@0: } michael@0: michael@0: } while (1); michael@0: michael@0: if (rv == SECSuccess) { michael@0: int oidIdent = SEC_OID_X509_NAME_CONSTRAINTS; michael@0: michael@0: PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); michael@0: michael@0: if (constraints->permited != NULL) { michael@0: last_permited->l.next = &(constraints->permited->l); michael@0: constraints->permited->l.prev = &(last_permited->l); michael@0: } michael@0: if (constraints->excluded != NULL) { michael@0: last_excluded->l.next = &(constraints->excluded->l); michael@0: constraints->excluded->l.prev = &(last_excluded->l); michael@0: } michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, constraints, michael@0: yesNoAns, oidIdent, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeNameConstraintsExtension); michael@0: } michael@0: if (arena) michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return (rv); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddAuthKeyID (void *extHandle) michael@0: { michael@0: CERTAuthKeyID *authKeyID = NULL; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: PRBool yesNoAns; michael@0: michael@0: do { michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: if (GetYesNo ("Enter value for the authKeyID extension [y/N]?") == 0) michael@0: break; michael@0: michael@0: authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID); michael@0: if (authKeyID == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: rv = GetString (arena, "Enter value for the key identifier fields," michael@0: "enter to omit:", &authKeyID->keyID); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: SECU_SECItemHexStringToBinary(&authKeyID->keyID); michael@0: michael@0: authKeyID->authCertIssuer = CreateGeneralName (arena); michael@0: if (authKeyID->authCertIssuer == NULL && michael@0: SECFailure == PORT_GetError ()) michael@0: break; michael@0: michael@0: michael@0: rv = GetString (arena, "Enter value for the authCertSerial field, " michael@0: "enter to omit:", &authKeyID->authCertSerialNumber); michael@0: michael@0: yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, michael@0: authKeyID, yesNoAns, SEC_OID_X509_AUTH_KEY_ID, michael@0: (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID); michael@0: if (rv) michael@0: break; michael@0: michael@0: } while (0); michael@0: if (arena) michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: return (rv); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddSubjKeyID (void *extHandle) michael@0: { michael@0: SECItem keyID; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: PRBool yesNoAns; michael@0: michael@0: do { michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: printf("Adding Subject Key ID extension.\n"); michael@0: michael@0: rv = GetString (arena, "Enter value for the key identifier fields," michael@0: "enter to omit:", &keyID); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: SECU_SECItemHexStringToBinary(&keyID); michael@0: michael@0: yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, michael@0: &keyID, yesNoAns, SEC_OID_X509_SUBJECT_KEY_ID, michael@0: (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeSubjectKeyID); michael@0: if (rv) michael@0: break; michael@0: michael@0: } while (0); michael@0: if (arena) michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: return (rv); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddCrlDistPoint(void *extHandle) michael@0: { michael@0: PLArenaPool *arena = NULL; michael@0: CERTCrlDistributionPoints *crlDistPoints = NULL; michael@0: CRLDistributionPoint *current; michael@0: SECStatus rv = SECSuccess; michael@0: int count = 0, intValue; michael@0: char buffer[512]; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) michael@0: return (SECFailure); michael@0: michael@0: do { michael@0: current = NULL; michael@0: michael@0: current = PORT_ArenaZNew(arena, CRLDistributionPoint); michael@0: if (current == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: /* Get the distributionPointName fields - this field is optional */ michael@0: if (PrintChoicesAndGetAnswer( michael@0: "Enter the type of the distribution point name:\n" michael@0: "\t1 - Full Name\n\t2 - Relative Name\n\tAny other " michael@0: "number to finish\n\t\tChoice: ", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: intValue = PORT_Atoi (buffer); michael@0: switch (intValue) { michael@0: case generalName: michael@0: current->distPointType = intValue; michael@0: current->distPoint.fullName = CreateGeneralName (arena); michael@0: rv = PORT_GetError(); michael@0: break; michael@0: michael@0: case relativeDistinguishedName: { michael@0: CERTName *name; michael@0: michael@0: current->distPointType = intValue; michael@0: puts ("Enter the relative name: "); michael@0: fflush (stdout); michael@0: if (Gets_s (buffer, sizeof(buffer)) == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: /* For simplicity, use CERT_AsciiToName to converse from a string michael@0: to NAME, but we only interest in the first RDN */ michael@0: name = CERT_AsciiToName (buffer); michael@0: if (!name) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: rv = CERT_CopyRDN (arena, ¤t->distPoint.relativeName, michael@0: name->rdns[0]); michael@0: CERT_DestroyName (name); michael@0: break; michael@0: } michael@0: } michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: /* Get the reason flags */ michael@0: if (PrintChoicesAndGetAnswer( michael@0: "\nSelect one of the following for the reason flags\n" michael@0: "\t0 - unused\n\t1 - keyCompromise\n" michael@0: "\t2 - caCompromise\n\t3 - affiliationChanged\n" michael@0: "\t4 - superseded\n\t5 - cessationOfOperation\n" michael@0: "\t6 - certificateHold\n" michael@0: "\tAny other number to finish\t\tChoice: ", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: intValue = PORT_Atoi (buffer); michael@0: if (intValue == 0) { michael@0: /* Checking that zero value of variable 'value' michael@0: * corresponds to '0' input made by user */ michael@0: char *chPtr = strchr(buffer, '0'); michael@0: if (chPtr == NULL) { michael@0: intValue = -1; michael@0: } michael@0: } michael@0: if (intValue >= 0 && intValue <8) { michael@0: current->reasons.data = PORT_ArenaAlloc (arena, sizeof(char)); michael@0: if (current->reasons.data == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: *current->reasons.data = (char)(0x80 >> intValue); michael@0: current->reasons.len = 1; michael@0: } michael@0: puts ("Enter value for the CRL Issuer name:\n"); michael@0: current->crlIssuer = CreateGeneralName (arena); michael@0: if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure) michael@0: break; michael@0: michael@0: if (crlDistPoints == NULL) { michael@0: crlDistPoints = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); michael@0: if (crlDistPoints == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: } michael@0: michael@0: crlDistPoints->distPoints = michael@0: PORT_ArenaGrow (arena, crlDistPoints->distPoints, michael@0: sizeof (*crlDistPoints->distPoints) * count, michael@0: sizeof (*crlDistPoints->distPoints) *(count + 1)); michael@0: if (crlDistPoints->distPoints == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: crlDistPoints->distPoints[count] = current; michael@0: ++count; michael@0: if (GetYesNo("Enter another value for the CRLDistributionPoint " michael@0: "extension [y/N]?") == 0) { michael@0: /* Add null to the end to mark end of data */ michael@0: crlDistPoints->distPoints = michael@0: PORT_ArenaGrow(arena, crlDistPoints->distPoints, michael@0: sizeof (*crlDistPoints->distPoints) * count, michael@0: sizeof (*crlDistPoints->distPoints) *(count + 1)); michael@0: crlDistPoints->distPoints[count] = NULL; michael@0: break; michael@0: } michael@0: michael@0: michael@0: } while (1); michael@0: michael@0: if (rv == SECSuccess) { michael@0: PRBool yesNoAns = GetYesNo ("Is this a critical extension [y/N]?"); michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, michael@0: crlDistPoints, yesNoAns, SEC_OID_X509_CRL_DIST_POINTS, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCRLDistributionPoints); michael@0: } michael@0: if (arena) michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: return (rv); michael@0: } michael@0: michael@0: michael@0: michael@0: static SECStatus michael@0: AddPolicyConstraints(void *extHandle) michael@0: { michael@0: CERTCertificatePolicyConstraints *policyConstr; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: SECItem *item, *dummy; michael@0: char buffer[512]; michael@0: int value; michael@0: PRBool yesNoAns; michael@0: PRBool skipExt = PR_TRUE; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: policyConstr = PORT_ArenaZNew(arena, CERTCertificatePolicyConstraints); michael@0: if (policyConstr == NULL) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: goto loser; michael@0: } michael@0: michael@0: if (PrintChoicesAndGetAnswer("for requireExplicitPolicy enter the number " michael@0: "of certs in path\nbefore explicit policy is required\n" michael@0: "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) { michael@0: goto loser; michael@0: } michael@0: michael@0: if (PORT_Strlen(buffer)) { michael@0: value = PORT_Atoi(buffer); michael@0: if (value < 0) { michael@0: goto loser; michael@0: } michael@0: item = &policyConstr->explicitPolicySkipCerts; michael@0: dummy = SEC_ASN1EncodeInteger(arena, item, value); michael@0: if (!dummy) { michael@0: goto loser; michael@0: } michael@0: skipExt = PR_FALSE; michael@0: } michael@0: michael@0: if (PrintChoicesAndGetAnswer("for inihibitPolicyMapping enter " michael@0: "the number of certs in path\n" michael@0: "after which policy mapping is not allowed\n" michael@0: "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) { michael@0: goto loser; michael@0: } michael@0: michael@0: if (PORT_Strlen(buffer)) { michael@0: value = PORT_Atoi(buffer); michael@0: if (value < 0) { michael@0: goto loser; michael@0: } michael@0: item = &policyConstr->inhibitMappingSkipCerts; michael@0: dummy = SEC_ASN1EncodeInteger(arena, item, value); michael@0: if (!dummy) { michael@0: goto loser; michael@0: } michael@0: skipExt = PR_FALSE; michael@0: } michael@0: michael@0: michael@0: if (!skipExt) { michael@0: yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, policyConstr, michael@0: yesNoAns, SEC_OID_X509_POLICY_CONSTRAINTS, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyConstraintsExtension); michael@0: } else { michael@0: fprintf(stdout, "Policy Constraint extensions must contain " michael@0: "at least one policy field\n"); michael@0: rv = SECFailure; michael@0: } michael@0: michael@0: loser: michael@0: if (arena) { michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: } michael@0: return (rv); michael@0: } michael@0: michael@0: michael@0: static SECStatus michael@0: AddInhibitAnyPolicy(void *extHandle) michael@0: { michael@0: CERTCertificateInhibitAny certInhibitAny; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: SECItem *item, *dummy; michael@0: char buffer[10]; michael@0: int value; michael@0: PRBool yesNoAns; michael@0: michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: if (PrintChoicesAndGetAnswer("Enter the number of certs in the path " michael@0: "permitted to use anyPolicy.\n" michael@0: "(press Enter for 0)", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: goto loser; michael@0: } michael@0: michael@0: item = &certInhibitAny.inhibitAnySkipCerts; michael@0: value = PORT_Atoi(buffer); michael@0: if (value < 0) { michael@0: goto loser; michael@0: } michael@0: dummy = SEC_ASN1EncodeInteger(arena, item, value); michael@0: if (!dummy) { michael@0: goto loser; michael@0: } michael@0: michael@0: yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &certInhibitAny, michael@0: yesNoAns, SEC_OID_X509_INHIBIT_ANY_POLICY, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInhibitAnyExtension); michael@0: loser: michael@0: if (arena) { michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: } michael@0: return (rv); michael@0: } michael@0: michael@0: michael@0: static SECStatus michael@0: AddPolicyMappings(void *extHandle) michael@0: { michael@0: CERTPolicyMap **policyMapArr = NULL; michael@0: CERTPolicyMap *current; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: int count = 0; michael@0: char buffer[512]; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: do { michael@0: if (PrintChoicesAndGetAnswer("Enter an Object Identifier (dotted " michael@0: "decimal format) for Issuer Domain Policy", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: current = PORT_ArenaZNew(arena, CERTPolicyMap); michael@0: if (current == NULL) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: rv = SEC_StringToOID(arena, ¤t->issuerDomainPolicy, buffer, 0); michael@0: if (rv == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: if (PrintChoicesAndGetAnswer("Enter an Object Identifier for " michael@0: "Subject Domain Policy", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: rv = SEC_StringToOID(arena, ¤t->subjectDomainPolicy, buffer, 0); michael@0: if (rv == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: if (policyMapArr == NULL) { michael@0: policyMapArr = PORT_ArenaZNew(arena, CERTPolicyMap *); michael@0: if (policyMapArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: } michael@0: michael@0: policyMapArr = PORT_ArenaGrow(arena, policyMapArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: if (policyMapArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: policyMapArr[count] = current; michael@0: ++count; michael@0: michael@0: if (!GetYesNo("Enter another Policy Mapping [y/N]")) { michael@0: /* Add null to the end to mark end of data */ michael@0: policyMapArr = PORT_ArenaGrow (arena, policyMapArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: if (policyMapArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: policyMapArr[count] = NULL; michael@0: break; michael@0: } michael@0: michael@0: } while (1); michael@0: michael@0: if (rv == SECSuccess) { michael@0: CERTCertificatePolicyMappings mappings; michael@0: PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); michael@0: michael@0: mappings.arena = arena; michael@0: mappings.policyMaps = policyMapArr; michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &mappings, michael@0: yesNoAns, SEC_OID_X509_POLICY_MAPPINGS, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyMappingExtension); michael@0: } michael@0: if (arena) michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: return (rv); michael@0: } michael@0: michael@0: enum PoliciQualifierEnum { michael@0: cpsPointer = 1, michael@0: userNotice = 2 michael@0: }; michael@0: michael@0: michael@0: static CERTPolicyQualifier ** michael@0: RequestPolicyQualifiers(PLArenaPool *arena, SECItem *policyID) michael@0: { michael@0: CERTPolicyQualifier **policyQualifArr = NULL; michael@0: CERTPolicyQualifier *current; michael@0: SECStatus rv = SECSuccess; michael@0: int count = 0; michael@0: char buffer[512]; michael@0: void *mark; michael@0: SECOidData *oid = NULL; michael@0: int intValue = 0; michael@0: int inCount = 0; michael@0: michael@0: PORT_Assert(arena); michael@0: mark = PORT_ArenaMark(arena); michael@0: do { michael@0: current = PORT_ArenaZNew(arena, CERTPolicyQualifier); michael@0: if (current == NULL) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: /* Get the accessMethod fields */ michael@0: SECU_PrintObjectID(stdout, policyID, michael@0: "Choose the type of qualifier for policy" , 0); michael@0: michael@0: if (PrintChoicesAndGetAnswer( michael@0: "\t1 - CPS Pointer qualifier\n" michael@0: "\t2 - User notice qualifier\n" michael@0: "\tAny other number to finish\n" michael@0: "\t\tChoice: ", buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: intValue = PORT_Atoi(buffer); michael@0: switch (intValue) { michael@0: case cpsPointer: { michael@0: SECItem input; michael@0: michael@0: oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CPS_POINTER_QUALIFIER); michael@0: if (PrintChoicesAndGetAnswer("Enter CPS pointer URI: ", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: input.len = PORT_Strlen(buffer); michael@0: input.data = (void*)PORT_ArenaStrdup(arena, buffer); michael@0: if (input.data == NULL || michael@0: SEC_ASN1EncodeItem(arena, ¤t->qualifierValue, &input, michael@0: SEC_ASN1_GET(SEC_IA5StringTemplate)) == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: break; michael@0: } michael@0: case userNotice: { michael@0: SECItem **noticeNumArr; michael@0: CERTUserNotice *notice = PORT_ArenaZNew(arena, CERTUserNotice); michael@0: if (!notice) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: oid = SECOID_FindOIDByTag(SEC_OID_PKIX_USER_NOTICE_QUALIFIER); michael@0: michael@0: if (GetYesNo("\t add a User Notice reference? [y/N]")) { michael@0: michael@0: if (PrintChoicesAndGetAnswer("Enter user organization string: ", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: notice->noticeReference.organization.type = siAsciiString; michael@0: notice->noticeReference.organization.len = michael@0: PORT_Strlen(buffer); michael@0: notice->noticeReference.organization.data = michael@0: (void*)PORT_ArenaStrdup(arena, buffer); michael@0: michael@0: michael@0: noticeNumArr = PORT_ArenaZNewArray(arena, SECItem *, 2); michael@0: if (!noticeNumArr) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: do { michael@0: SECItem *noticeNum; michael@0: michael@0: noticeNum = PORT_ArenaZNew(arena, SECItem); michael@0: michael@0: if (PrintChoicesAndGetAnswer( michael@0: "Enter User Notice reference number " michael@0: "(or -1 to quit): ", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: intValue = PORT_Atoi(buffer); michael@0: if (noticeNum == NULL) { michael@0: if (intValue < 0) { michael@0: fprintf(stdout, "a noticeReference must have at " michael@0: "least one reference number\n"); michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: } else { michael@0: if (intValue >= 0) { michael@0: noticeNumArr = PORT_ArenaGrow(arena, noticeNumArr, michael@0: sizeof (current) * inCount, michael@0: sizeof (current) *(inCount + 1)); michael@0: if (noticeNumArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: if (!SEC_ASN1EncodeInteger(arena, noticeNum, intValue)) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: noticeNumArr[inCount++] = noticeNum; michael@0: noticeNumArr[inCount] = NULL; michael@0: michael@0: } while (1); michael@0: if (rv == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: notice->noticeReference.noticeNumbers = noticeNumArr; michael@0: rv = CERT_EncodeNoticeReference(arena, ¬ice->noticeReference, michael@0: ¬ice->derNoticeReference); michael@0: if (rv == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: } michael@0: if (GetYesNo("\t EnterUser Notice explicit text? [y/N]")) { michael@0: /* Getting only 200 bytes - RFC limitation */ michael@0: if (PrintChoicesAndGetAnswer( michael@0: "\t", buffer, 200) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: notice->displayText.type = siAsciiString; michael@0: notice->displayText.len = PORT_Strlen(buffer); michael@0: notice->displayText.data = michael@0: (void*)PORT_ArenaStrdup(arena, buffer); michael@0: if (notice->displayText.data == NULL) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: } michael@0: michael@0: rv = CERT_EncodeUserNotice(arena, notice, ¤t->qualifierValue); michael@0: if (rv == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: break; michael@0: } michael@0: } michael@0: if (rv == SECFailure || oid == NULL || michael@0: SECITEM_CopyItem(arena, ¤t->qualifierID, &oid->oid) michael@0: == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: if (!policyQualifArr) { michael@0: policyQualifArr = PORT_ArenaZNew(arena, CERTPolicyQualifier *); michael@0: } else { michael@0: policyQualifArr = PORT_ArenaGrow (arena, policyQualifArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: } michael@0: if (policyQualifArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: policyQualifArr[count] = current; michael@0: ++count; michael@0: michael@0: if (!GetYesNo ("Enter another policy qualifier [y/N]")) { michael@0: /* Add null to the end to mark end of data */ michael@0: policyQualifArr = PORT_ArenaGrow(arena, policyQualifArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: if (policyQualifArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: policyQualifArr[count] = NULL; michael@0: break; michael@0: } michael@0: michael@0: } while (1); michael@0: michael@0: if (rv != SECSuccess) { michael@0: PORT_ArenaRelease (arena, mark); michael@0: policyQualifArr = NULL; michael@0: } michael@0: return (policyQualifArr); michael@0: } michael@0: michael@0: static SECStatus michael@0: AddCertPolicies(void *extHandle) michael@0: { michael@0: CERTPolicyInfo **certPoliciesArr = NULL; michael@0: CERTPolicyInfo *current; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: int count = 0; michael@0: char buffer[512]; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: do { michael@0: current = PORT_ArenaZNew(arena, CERTPolicyInfo); michael@0: if (current == NULL) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: if (PrintChoicesAndGetAnswer("Enter a CertPolicy Object Identifier " michael@0: "(dotted decimal format)\n" michael@0: "or \"any\" for AnyPolicy:", michael@0: buffer, sizeof(buffer)) == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: if (strncmp(buffer, "any", 3) == 0) { michael@0: /* use string version of X509_CERTIFICATE_POLICIES.anyPolicy */ michael@0: strcpy(buffer, "OID.2.5.29.32.0"); michael@0: } michael@0: rv = SEC_StringToOID(arena, ¤t->policyID, buffer, 0); michael@0: michael@0: if (rv == SECFailure) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: current->policyQualifiers = michael@0: RequestPolicyQualifiers(arena, ¤t->policyID); michael@0: michael@0: if (!certPoliciesArr) { michael@0: certPoliciesArr = PORT_ArenaZNew(arena, CERTPolicyInfo *); michael@0: } else { michael@0: certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: } michael@0: if (certPoliciesArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: certPoliciesArr[count] = current; michael@0: ++count; michael@0: michael@0: if (!GetYesNo ("Enter another PolicyInformation field [y/N]?")) { michael@0: /* Add null to the end to mark end of data */ michael@0: certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: if (certPoliciesArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: certPoliciesArr[count] = NULL; michael@0: break; michael@0: } michael@0: michael@0: } while (1); michael@0: michael@0: if (rv == SECSuccess) { michael@0: CERTCertificatePolicies policies; michael@0: PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); michael@0: michael@0: policies.arena = arena; michael@0: policies.policyInfos = certPoliciesArr; michael@0: michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &policies, michael@0: yesNoAns, SEC_OID_X509_CERTIFICATE_POLICIES, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCertPoliciesExtension); michael@0: } michael@0: if (arena) michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return (rv); michael@0: } michael@0: michael@0: enum AuthInfoAccessTypesEnum { michael@0: caIssuers = 1, michael@0: ocsp = 2 michael@0: }; michael@0: michael@0: enum SubjInfoAccessTypesEnum { michael@0: caRepository = 1, michael@0: timeStamping = 2 michael@0: }; michael@0: michael@0: /* Encode and add an AIA or SIA extension */ michael@0: static SECStatus michael@0: AddInfoAccess(void *extHandle, PRBool addSIAExt, PRBool isCACert) michael@0: { michael@0: CERTAuthInfoAccess **infoAccArr = NULL; michael@0: CERTAuthInfoAccess *current; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: int count = 0; michael@0: char buffer[512]; michael@0: SECOidData *oid = NULL; michael@0: int intValue = 0; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if ( !arena ) { michael@0: SECU_PrintError(progName, "out of memory"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: do { michael@0: current = NULL; michael@0: current = PORT_ArenaZNew(arena, CERTAuthInfoAccess); michael@0: if (current == NULL) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: /* Get the accessMethod fields */ michael@0: if (addSIAExt) { michael@0: if (isCACert) { michael@0: puts("Adding \"CA Repository\" access method type for " michael@0: "Subject Information Access extension:\n"); michael@0: intValue = caRepository; michael@0: } else { michael@0: puts("Adding \"Time Stamping Services\" access method type for " michael@0: "Subject Information Access extension:\n"); michael@0: intValue = timeStamping; michael@0: } michael@0: } else { michael@0: PrintChoicesAndGetAnswer("Enter access method type " michael@0: "for Authority Information Access extension:\n" michael@0: "\t1 - CA Issuers\n\t2 - OCSP\n\tAny" michael@0: "other number to finish\n\tChoice", michael@0: buffer, sizeof(buffer)); michael@0: intValue = PORT_Atoi(buffer); michael@0: } michael@0: if (addSIAExt) { michael@0: switch (intValue) { michael@0: case caRepository: michael@0: oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_REPOSITORY); michael@0: break; michael@0: michael@0: case timeStamping: michael@0: oid = SECOID_FindOIDByTag(SEC_OID_PKIX_TIMESTAMPING); michael@0: break; michael@0: } michael@0: } else { michael@0: switch (intValue) { michael@0: case caIssuers: michael@0: oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_ISSUERS); michael@0: break; michael@0: michael@0: case ocsp: michael@0: oid = SECOID_FindOIDByTag(SEC_OID_PKIX_OCSP); michael@0: break; michael@0: } michael@0: } michael@0: if (oid == NULL || michael@0: SECITEM_CopyItem(arena, ¤t->method, &oid->oid) michael@0: == SECFailure) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: current->location = CreateGeneralName(arena); michael@0: if (!current->location) { michael@0: GEN_BREAK(SECFailure); michael@0: } michael@0: michael@0: if (infoAccArr == NULL) { michael@0: infoAccArr = PORT_ArenaZNew(arena, CERTAuthInfoAccess *); michael@0: } else { michael@0: infoAccArr = PORT_ArenaGrow(arena, infoAccArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: } michael@0: if (infoAccArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: michael@0: infoAccArr[count] = current; michael@0: ++count; michael@0: michael@0: PR_snprintf(buffer, sizeof(buffer), "Add another location to the %s" michael@0: " Information Access extension [y/N]", michael@0: (addSIAExt) ? "Subject" : "Authority"); michael@0: michael@0: if (GetYesNo (buffer) == 0) { michael@0: /* Add null to the end to mark end of data */ michael@0: infoAccArr = PORT_ArenaGrow(arena, infoAccArr, michael@0: sizeof (current) * count, michael@0: sizeof (current) *(count + 1)); michael@0: if (infoAccArr == NULL) { michael@0: GEN_BREAK (SECFailure); michael@0: } michael@0: infoAccArr[count] = NULL; michael@0: break; michael@0: } michael@0: michael@0: } while (1); michael@0: michael@0: if (rv == SECSuccess) { michael@0: int oidIdent = SEC_OID_X509_AUTH_INFO_ACCESS; michael@0: michael@0: PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?"); michael@0: michael@0: if (addSIAExt) { michael@0: oidIdent = SEC_OID_X509_SUBJECT_INFO_ACCESS; michael@0: } michael@0: rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, infoAccArr, michael@0: yesNoAns, oidIdent, michael@0: (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInfoAccessExtension); michael@0: } michael@0: if (arena) michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return (rv); michael@0: } michael@0: michael@0: /* Example of valid input: michael@0: * 1.2.3.4:critical:/tmp/abc,5.6.7.8:not-critical:/tmp/xyz michael@0: */ michael@0: static SECStatus michael@0: parseNextGenericExt(const char *nextExtension, const char **oid, int *oidLen, michael@0: const char **crit, int *critLen, michael@0: const char **filename, int *filenameLen, michael@0: const char **next) michael@0: { michael@0: const char *nextColon; michael@0: const char *nextComma; michael@0: const char *iter = nextExtension; michael@0: michael@0: if (!iter || !*iter) michael@0: return SECFailure; michael@0: michael@0: /* Require colons at earlier positions than nextComma (or end of string ) */ michael@0: nextComma = strchr(iter, ','); michael@0: michael@0: *oid = iter; michael@0: nextColon = strchr(iter, ':'); michael@0: if (!nextColon || (nextComma && nextColon > nextComma)) michael@0: return SECFailure; michael@0: *oidLen = (nextColon - *oid); michael@0: michael@0: if (!*oidLen) michael@0: return SECFailure; michael@0: michael@0: iter = nextColon; michael@0: ++iter; michael@0: michael@0: *crit = iter; michael@0: nextColon = strchr(iter, ':'); michael@0: if (!nextColon || (nextComma && nextColon > nextComma)) michael@0: return SECFailure; michael@0: *critLen = (nextColon - *crit); michael@0: michael@0: if (!*critLen) michael@0: return SECFailure; michael@0: michael@0: iter = nextColon; michael@0: ++iter; michael@0: michael@0: *filename = iter; michael@0: if (nextComma) { michael@0: *filenameLen = (nextComma - *filename); michael@0: iter = nextComma; michael@0: ++iter; michael@0: *next = iter; michael@0: } else { michael@0: *filenameLen = strlen(*filename); michael@0: *next = NULL; michael@0: } michael@0: michael@0: if (!*filenameLen) michael@0: return SECFailure; michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames, michael@0: certutilExtnList extList, const char *extGeneric) michael@0: { michael@0: SECStatus rv = SECSuccess; michael@0: char *errstring = NULL; michael@0: const char *nextExtension = NULL; michael@0: michael@0: do { michael@0: /* Add key usage extension */ michael@0: if (extList[ext_keyUsage].activated) { michael@0: rv = AddKeyUsage(extHandle, extList[ext_keyUsage].arg); michael@0: if (rv) { michael@0: errstring = "KeyUsage"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: /* Add extended key usage extension */ michael@0: if (extList[ext_extKeyUsage].activated) { michael@0: rv = AddExtKeyUsage(extHandle, extList[ext_extKeyUsage].arg); michael@0: if (rv) { michael@0: errstring = "ExtendedKeyUsage"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: /* Add basic constraint extension */ michael@0: if (extList[ext_basicConstraint].activated) { michael@0: rv = AddBasicConstraint(extHandle); michael@0: if (rv) { michael@0: errstring = "BasicConstraint"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: /* Add name constraints extension */ michael@0: if (extList[ext_nameConstraints].activated) { michael@0: rv = AddNameConstraints(extHandle); michael@0: if (rv) { michael@0: errstring = "NameConstraints"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_authorityKeyID].activated) { michael@0: rv = AddAuthKeyID(extHandle); michael@0: if (rv) { michael@0: errstring = "AuthorityKeyID"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_subjectKeyID].activated) { michael@0: rv = AddSubjKeyID(extHandle); michael@0: if (rv) { michael@0: errstring = "SubjectKeyID"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_CRLDistPts].activated) { michael@0: rv = AddCrlDistPoint(extHandle); michael@0: if (rv) { michael@0: errstring = "CRLDistPoints"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_NSCertType].activated) { michael@0: rv = AddNscpCertType(extHandle, extList[ext_NSCertType].arg); michael@0: if (rv) { michael@0: errstring = "NSCertType"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_authInfoAcc].activated || michael@0: extList[ext_subjInfoAcc].activated) { michael@0: rv = AddInfoAccess(extHandle, extList[ext_subjInfoAcc].activated, michael@0: extList[ext_basicConstraint].activated); michael@0: if (rv) { michael@0: errstring = "InformationAccess"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_certPolicies].activated) { michael@0: rv = AddCertPolicies(extHandle); michael@0: if (rv) { michael@0: errstring = "Policies"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_policyMappings].activated) { michael@0: rv = AddPolicyMappings(extHandle); michael@0: if (rv) { michael@0: errstring = "PolicyMappings"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_policyConstr].activated) { michael@0: rv = AddPolicyConstraints(extHandle); michael@0: if (rv) { michael@0: errstring = "PolicyConstraints"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (extList[ext_inhibitAnyPolicy].activated) { michael@0: rv = AddInhibitAnyPolicy(extHandle); michael@0: if (rv) { michael@0: errstring = "InhibitAnyPolicy"; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (emailAddrs || dnsNames || extList[ext_subjectAltName].activated) { michael@0: PLArenaPool *arena; michael@0: CERTGeneralName *namelist = NULL; michael@0: SECItem item = { 0, NULL, 0 }; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: michael@0: rv = SECSuccess; michael@0: michael@0: if (emailAddrs) { michael@0: rv |= AddEmailSubjectAlt(arena, &namelist, emailAddrs); michael@0: } michael@0: michael@0: if (dnsNames) { michael@0: rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames); michael@0: } michael@0: michael@0: if (extList[ext_subjectAltName].activated) { michael@0: rv |= AddGeneralSubjectAlt(arena, &namelist, michael@0: extList[ext_subjectAltName].arg); michael@0: } michael@0: michael@0: if (rv == SECSuccess) { michael@0: rv = CERT_EncodeAltNameExtension(arena, namelist, &item); michael@0: if (rv == SECSuccess) { michael@0: rv = CERT_AddExtension(extHandle, michael@0: SEC_OID_X509_SUBJECT_ALT_NAME, michael@0: &item, PR_FALSE, PR_TRUE); michael@0: } michael@0: } michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: if (rv) { michael@0: errstring = "SubjectAltName"; michael@0: break; michael@0: } michael@0: } michael@0: } while (0); michael@0: michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "Problem creating %s extension", errstring); michael@0: } michael@0: michael@0: nextExtension = extGeneric; michael@0: while (nextExtension && *nextExtension) { michael@0: SECItem oid_item, value; michael@0: PRBool isCritical; michael@0: const char *oid, *crit, *filename, *next; michael@0: int oidLen, critLen, filenameLen; michael@0: PRFileDesc *inFile = NULL; michael@0: char *zeroTerminatedFilename = NULL; michael@0: michael@0: rv = parseNextGenericExt(nextExtension, &oid, &oidLen, &crit, &critLen, michael@0: &filename, &filenameLen, &next); michael@0: if (rv!= SECSuccess) { michael@0: SECU_PrintError(progName, michael@0: "error parsing generic extension parameter %s", michael@0: nextExtension); michael@0: break; michael@0: } michael@0: oid_item.data = NULL; michael@0: oid_item.len = 0; michael@0: rv = GetOidFromString(NULL, &oid_item, oid, oidLen); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "malformed extension OID %s", nextExtension); michael@0: break; michael@0: } michael@0: if (!strncmp("critical", crit, critLen)) { michael@0: isCritical = PR_TRUE; michael@0: } else if (!strncmp("not-critical", crit, critLen)) { michael@0: isCritical = PR_FALSE; michael@0: } else { michael@0: rv = SECFailure; michael@0: SECU_PrintError(progName, "expected 'critical' or 'not-critical'"); michael@0: break; michael@0: } michael@0: zeroTerminatedFilename = PL_strndup(filename, filenameLen); michael@0: if (!zeroTerminatedFilename) { michael@0: rv = SECFailure; michael@0: SECU_PrintError(progName, "out of memory"); michael@0: break; michael@0: } michael@0: rv = SECFailure; michael@0: inFile = PR_Open(zeroTerminatedFilename, PR_RDONLY, 0); michael@0: if (inFile) { michael@0: rv = SECU_ReadDERFromFile(&value, inFile, PR_FALSE, PR_FALSE); michael@0: PR_Close(inFile); michael@0: inFile = NULL; michael@0: } michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "unable to read file %s", michael@0: zeroTerminatedFilename); michael@0: } michael@0: PL_strfree(zeroTerminatedFilename); michael@0: if (rv != SECSuccess) { michael@0: break; michael@0: } michael@0: rv = CERT_AddExtensionByOID(extHandle, &oid_item, &value, isCritical, michael@0: PR_FALSE /*copyData*/); michael@0: if (rv != SECSuccess) { michael@0: SECITEM_FreeItem(&oid_item, PR_FALSE); michael@0: SECITEM_FreeItem(&value, PR_FALSE); michael@0: SECU_PrintError(progName, "failed to add extension %s", nextExtension); michael@0: break; michael@0: } michael@0: nextExtension = next; michael@0: } michael@0: michael@0: return rv; michael@0: }