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