Blame SOURCES/certext.c

b76ddc
/*
b76ddc
   Copyright 2005 Red Hat, Inc.
b76ddc
b76ddc
   This program is free software; you can redistribute it and/or modify
b76ddc
   it under the terms of the GNU General Public License as published by
b76ddc
   the Free Software Foundation; either version 2 of the License, or
b76ddc
   (at your option) any later version.
b76ddc
  
b76ddc
   This program is distributed in the hope that it will be useful,
b76ddc
   but WITHOUT ANY WARRANTY; without even the implied warranty of
b76ddc
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
b76ddc
   GNU General Public License for more details.
b76ddc
  
b76ddc
   You should have received a copy of the GNU General Public License
b76ddc
   along with this program; if not, write to the Free Software
b76ddc
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
b76ddc
   
b76ddc
   In addition, as a special exception, Red Hat, Inc. gives permission
b76ddc
   to link the code of this program with the OpenSSL library (or with
b76ddc
   modified versions of OpenSSL that use the same license as OpenSSL),
b76ddc
   and distribute linked combinations including the two. You must obey
b76ddc
   the GNU General Public License in all respects for all of the code
b76ddc
   used other than OpenSSL. If you modify this file, you may extend
b76ddc
   this exception to your version of the file, but you are not
b76ddc
   obligated to do so. If you do not wish to do so, delete this
b76ddc
   exception statement from your version.
b76ddc
b76ddc
*/
b76ddc
b76ddc
/* ***** BEGIN LICENSE BLOCK *****
b76ddc
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
b76ddc
 *
b76ddc
 * The contents of this file are subject to the Mozilla Public License Version
b76ddc
 * 1.1 (the "License"); you may not use this file except in compliance with
b76ddc
 * the License. You may obtain a copy of the License at
b76ddc
 * http://www.mozilla.org/MPL/
b76ddc
 *
b76ddc
 * Software distributed under the License is distributed on an "AS IS" basis,
b76ddc
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
b76ddc
 * for the specific language governing rights and limitations under the
b76ddc
 * License.
b76ddc
 *
b76ddc
 * The Original Code is the Netscape security libraries.
b76ddc
 *
b76ddc
 * The Initial Developer of the Original Code is
b76ddc
 * Netscape Communications Corporation.
b76ddc
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
b76ddc
 * the Initial Developer. All Rights Reserved.
b76ddc
 *
b76ddc
 * Contributor(s):
b76ddc
 *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
b76ddc
 *
b76ddc
 * Alternatively, the contents of this file may be used under the terms of
b76ddc
 * either the GNU General Public License Version 2 or later (the "GPL"), or
b76ddc
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
b76ddc
 * in which case the provisions of the GPL or the LGPL are applicable instead
b76ddc
 * of those above. If you wish to allow use of your version of this file only
b76ddc
 * under the terms of either the GPL or the LGPL, and not to allow others to
b76ddc
 * use your version of this file under the terms of the MPL, indicate your
b76ddc
 * decision by deleting the provisions above and replace them with the notice
b76ddc
 * and other provisions required by the GPL or the LGPL. If you do not delete
b76ddc
 * the provisions above, a recipient may use your version of this file under
b76ddc
 * the terms of any one of the MPL, the GPL or the LGPL.
b76ddc
 *
b76ddc
 * ***** END LICENSE BLOCK ***** */
b76ddc
b76ddc
/*
b76ddc
** certext.c
b76ddc
**
b76ddc
** part of certutil for managing certificates extensions
b76ddc
**
b76ddc
*/
b76ddc
#include <stdio.h>
b76ddc
#include <string.h>
b76ddc
#include <stdlib.h>
b76ddc
b76ddc
#include "secutil.h"
b76ddc
b76ddc
#include <unistd.h>
b76ddc
b76ddc
#include <cert.h>
b76ddc
#include <prprf.h>
b76ddc
#include <certt.h>
b76ddc
b76ddc
#include "keyutil.h"
b76ddc
b76ddc
#define GEN_BREAK(e) rv=e; break;
b76ddc
b76ddc
/* CERT_EncodeSubjectKeyID is a private function decleared in <xconst.h> */
b76ddc
b76ddc
/* Begin From NSS's xconst.c */
b76ddc
static const SEC_ASN1Template CERTSubjectKeyIDTemplate[] = {
b76ddc
    { SEC_ASN1_OCTET_STRING }
b76ddc
};
b76ddc
b76ddc
SECStatus 
b76ddc
CERT_EncodeSubjectKeyID(PRArenaPool *arena, const SECItem* srcString,
b76ddc
                        SECItem *encodedValue)
b76ddc
{
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
b76ddc
    if (!srcString) {
b76ddc
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
    if (SEC_ASN1EncodeItem (arena, encodedValue, srcString,
b76ddc
                CERTSubjectKeyIDTemplate) == NULL) {
b76ddc
        rv = SECFailure;
b76ddc
    }
b76ddc
    
b76ddc
    return(rv);
b76ddc
}
b76ddc
/* End From xconst.c */
b76ddc
b76ddc
b76ddc
/* From oidstring.c */
b76ddc
/* if to->data is not NULL, and to->len is large enough to hold the result,
b76ddc
 * then the resultant OID will be copyed into to->data, and to->len will be
b76ddc
 * changed to show the actual OID length.
b76ddc
 * Otherwise, memory for the OID will be allocated (from the caller's 
b76ddc
 * PLArenaPool, if pool is non-NULL) and to->data will receive the address
b76ddc
 * of the allocated data, and to->len will receive the OID length.
b76ddc
 * The original value of to->data is not freed when a new buffer is allocated.
b76ddc
 * 
b76ddc
 * The input string may begin with "OID." and this still be ignored.
b76ddc
 * The length of the input string is given in len.  If len == 0, then 
b76ddc
 * len will be computed as strlen(from), meaning it must be NUL terminated.
b76ddc
 * It is an error if from == NULL, or if *from == '\0'.
b76ddc
 */
b76ddc
b76ddc
SECStatus
b76ddc
SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len)
b76ddc
{
b76ddc
    /*PRUint32 result_len = 0;*/
b76ddc
    PRUint32 decimal_numbers = 0;
b76ddc
    PRUint32 result_bytes = 0;
b76ddc
    SECStatus rv;
b76ddc
    PRUint8 result[1024];
b76ddc
b76ddc
    static const PRUint32 max_decimal = (0xffffffff / 10);
b76ddc
    static const char OIDstring[] = {"OID."};
b76ddc
b76ddc
    if (!from || !to) {
b76ddc
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
b76ddc
    return SECFailure;
b76ddc
    }
b76ddc
    if (!len) {
b76ddc
        len = PL_strlen(from);
b76ddc
    }
b76ddc
    if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
b76ddc
        from += 4; /* skip leading "OID." if present */
b76ddc
        len  -= 4;
b76ddc
    }
b76ddc
    if (!len) {
b76ddc
bad_data:
b76ddc
        PORT_SetError(SEC_ERROR_BAD_DATA);
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
    do {
b76ddc
        PRUint32 decimal = 0;
b76ddc
            while (len > 0 && isdigit(*from)) {
b76ddc
            PRUint32 addend = (*from++ - '0');
b76ddc
            --len;
b76ddc
            if (decimal > max_decimal)  /* overflow */
b76ddc
            goto bad_data;
b76ddc
            decimal = (decimal * 10) + addend;
b76ddc
            if (decimal < addend)   /* overflow */
b76ddc
            goto bad_data;
b76ddc
        }
b76ddc
        if (len != 0 && *from != '.') {
b76ddc
            goto bad_data;
b76ddc
        }
b76ddc
        if (decimal_numbers == 0) {
b76ddc
            if (decimal > 2)
b76ddc
                goto bad_data;
b76ddc
            result[0] = decimal * 40;
b76ddc
            result_bytes = 1;
b76ddc
        } else if (decimal_numbers == 1) {
b76ddc
            if (decimal > 40)
b76ddc
                goto bad_data;
b76ddc
            result[0] += decimal;
b76ddc
        } else {
b76ddc
            /* encode the decimal number,  */
b76ddc
            PRUint8 * rp;
b76ddc
            PRUint32 num_bytes = 0;
b76ddc
            PRUint32 tmp = decimal;
b76ddc
            while (tmp) {
b76ddc
                num_bytes++;
b76ddc
                tmp >>= 7;
b76ddc
            }
b76ddc
            if (!num_bytes )
b76ddc
                ++num_bytes;  /* use one byte for a zero value */
b76ddc
            if (num_bytes + result_bytes > sizeof result)
b76ddc
                goto bad_data;
b76ddc
            tmp = num_bytes;
b76ddc
            rp = result + result_bytes - 1;
b76ddc
            rp[tmp] = (PRUint8)(decimal & 0x7f);
b76ddc
            decimal >>= 7;
b76ddc
            while (--tmp > 0) {
b76ddc
                rp[tmp] = (PRUint8)(decimal | 0x80);
b76ddc
                decimal >>= 7;
b76ddc
            }
b76ddc
            result_bytes += num_bytes;
b76ddc
        }
b76ddc
        ++decimal_numbers;
b76ddc
        if (len > 0) { /* skip trailing '.' */
b76ddc
            ++from;
b76ddc
            --len;
b76ddc
        }
b76ddc
    } while (len > 0);
b76ddc
    /* now result contains result_bytes of data */
b76ddc
    if (to->data && to->len >= result_bytes) {
b76ddc
        PORT_Memcpy(to->data, result, to->len = result_bytes);
b76ddc
        rv = SECSuccess;
b76ddc
    } else {
b76ddc
        SECItem result_item = {siBuffer, NULL, 0 };
b76ddc
        result_item.data = result;
b76ddc
        result_item.len  = result_bytes;
b76ddc
        rv = SECITEM_CopyItem(pool, to, &result_item);
b76ddc
    }
b76ddc
    return rv;
b76ddc
}
b76ddc
b76ddc
static char *
b76ddc
Gets_s(char *buff, size_t size) {
b76ddc
    char *str;
b76ddc
    
b76ddc
    if (buff == NULL || size < 1) {
b76ddc
        PORT_Assert(0);
b76ddc
        return NULL;
b76ddc
    }
b76ddc
    if ((str = fgets(buff, size, stdin)) != NULL) {
b76ddc
        int len = PORT_Strlen(str);
b76ddc
        /*
b76ddc
         * fgets() automatically converts native text file
b76ddc
         * line endings to '\n'.  As defensive programming
b76ddc
         * (just in case fgets has a bug or we put stdin in
b76ddc
         * binary mode by mistake), we handle three native 
b76ddc
         * text file line endings here:
b76ddc
         *   '\n'      Unix (including Linux and Mac OS X)
b76ddc
         *   '\r''\n'  DOS/Windows & OS/2
b76ddc
         *   '\r'      Mac OS Classic
b76ddc
         * len can not be less then 1, since in case with
b76ddc
         * empty string it has at least '\n' in the buffer
b76ddc
         */
b76ddc
        if (buff[len - 1] == '\n' || buff[len - 1] == '\r') {
b76ddc
            buff[len - 1] = '\0';
b76ddc
            if (len > 1 && buff[len - 2] == '\r')
b76ddc
                buff[len - 2] = '\0';
b76ddc
        }
b76ddc
    } else {
b76ddc
        buff[0] = '\0';
b76ddc
    }
b76ddc
    return str;
b76ddc
}
b76ddc
b76ddc
b76ddc
static SECStatus
b76ddc
PrintChoicesAndGetAnswer(char* str, char* rBuff, int rSize)
b76ddc
{
b76ddc
    fprintf(stdout, str);
b76ddc
    fprintf(stdout, " > ");
b76ddc
    fflush (stdout);
b76ddc
    if (Gets_s(rBuff, rSize) == NULL) {
b76ddc
        PORT_SetError(SEC_ERROR_INPUT_LEN);
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
    return SECSuccess;
b76ddc
}
b76ddc
b76ddc
static CERTGeneralName *
b76ddc
GetGeneralName (PRArenaPool *arena)
b76ddc
{
b76ddc
    CERTGeneralName *namesList = NULL;
b76ddc
    CERTGeneralName *current;
b76ddc
    CERTGeneralName *tail = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    int intValue;
b76ddc
    char buffer[512];
b76ddc
    void *mark;
b76ddc
b76ddc
    PORT_Assert (arena);
b76ddc
    mark = PORT_ArenaMark (arena);
b76ddc
    do {
b76ddc
        if (PrintChoicesAndGetAnswer(
b76ddc
        "\nSelect one of the following general name type: \n"
b76ddc
        "\t2 - rfc822Name\n"
b76ddc
        "\t3 - dnsName\n"
b76ddc
        "\t5 - directoryName\n"
b76ddc
        "\t7 - uniformResourceidentifier\n"
b76ddc
        "\t8 - ipAddress\n"
b76ddc
        "\t9 - registerID\n"
b76ddc
        "\tAny other number to finish\n"
b76ddc
        "\t\tChoice:", buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
        intValue = PORT_Atoi (buffer);
b76ddc
        /*
b76ddc
         * Should use ZAlloc instead of Alloc to avoid problem with garbage
b76ddc
         * initialized pointers in CERT_CopyName
b76ddc
         */
b76ddc
        switch (intValue) {
b76ddc
        case certRFC822Name:
b76ddc
        case certDNSName:
b76ddc
        case certDirectoryName:
b76ddc
        case certURI:
b76ddc
        case certIPAddress:
b76ddc
        case certRegisterID:
b76ddc
        break;
b76ddc
        default:
b76ddc
        intValue = 0;   /* force a break for anything else */
b76ddc
        }
b76ddc
b76ddc
        if (intValue == 0)
b76ddc
            break;
b76ddc
    
b76ddc
        if (namesList == NULL) {
b76ddc
            namesList = current = tail =
b76ddc
            PORT_ArenaZNew(arena, CERTGeneralName);
b76ddc
        } else {
b76ddc
            current = PORT_ArenaZNew(arena, CERTGeneralName);
b76ddc
        }
b76ddc
        if (current == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        current->type = intValue;
b76ddc
        puts ("\nEnter data:");
b76ddc
        fflush (stdout);
b76ddc
        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
b76ddc
            PORT_SetError(SEC_ERROR_INPUT_LEN);
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
        switch (current->type) {
b76ddc
        case certURI:
b76ddc
        case certDNSName:
b76ddc
        case certRFC822Name:
b76ddc
            current->name.other.data =
b76ddc
                PORT_ArenaAlloc (arena, strlen (buffer));
b76ddc
            if (current->name.other.data == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            PORT_Memcpy(current->name.other.data, buffer,
b76ddc
                        current->name.other.len = strlen(buffer));
b76ddc
            break;
b76ddc
b76ddc
        case certEDIPartyName:
b76ddc
        case certIPAddress:
b76ddc
        case certOtherName:
b76ddc
        case certRegisterID:
b76ddc
        case certX400Address: {
b76ddc
b76ddc
            current->name.other.data =
b76ddc
                PORT_ArenaAlloc (arena, strlen (buffer) + 2);
b76ddc
            if (current->name.other.data == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            
b76ddc
            PORT_Memcpy (current->name.other.data + 2, buffer,
b76ddc
                         strlen (buffer));
b76ddc
            /* This may not be accurate for all cases.  For now,
b76ddc
             * use this tag type */
b76ddc
            current->name.other.data[0] =
b76ddc
                (char)(((current->type - 1) & 0x1f)| 0x80);
b76ddc
            current->name.other.data[1] = (char)strlen (buffer);
b76ddc
            current->name.other.len = strlen (buffer) + 2;
b76ddc
            break;
b76ddc
        }
b76ddc
b76ddc
        case certDirectoryName: {
b76ddc
                CERTName *directoryName = NULL;
b76ddc
                
b76ddc
                directoryName = CERT_AsciiToName (buffer);
b76ddc
                if (!directoryName) {
b76ddc
                    fprintf(stderr, "certutil: improperly formatted name: "
b76ddc
                            "\"%s\"\n", buffer);
b76ddc
                    break;
b76ddc
                }
b76ddc
                
b76ddc
                rv = CERT_CopyName (arena, &current->name.directoryName,
b76ddc
                                    directoryName);
b76ddc
                CERT_DestroyName (directoryName);
b76ddc
                
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
        if (rv != SECSuccess)
b76ddc
            break;
b76ddc
        current->l.next = &(namesList->l);
b76ddc
        current->l.prev = &(tail->l);
b76ddc
        tail->l.next = &(current->l);
b76ddc
        tail = current;
b76ddc
        
b76ddc
    } while (1);
b76ddc
b76ddc
    if (rv != SECSuccess) {
b76ddc
        PORT_ArenaRelease (arena, mark);
b76ddc
        namesList = NULL;
b76ddc
    }
b76ddc
    return (namesList);
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
GetString(PRArenaPool *arena, char *prompt, SECItem *value)
b76ddc
{
b76ddc
    char buffer[251];
b76ddc
    char *buffPrt;
b76ddc
b76ddc
    buffer[0] = '\0';
b76ddc
    value->data = NULL;
b76ddc
    value->len = 0;
b76ddc
    
b76ddc
    puts (prompt);
b76ddc
    buffPrt = Gets_s (buffer, sizeof(buffer));
b76ddc
    /* returned NULL here treated the same way as empty string */
b76ddc
    if (buffPrt && strlen (buffer) > 0) {
b76ddc
        value->data = PORT_ArenaAlloc (arena, strlen (buffer));
b76ddc
        if (value->data == NULL) {
b76ddc
            PORT_SetError (SEC_ERROR_NO_MEMORY);
b76ddc
            return (SECFailure);
b76ddc
        }
b76ddc
        PORT_Memcpy (value->data, buffer, value->len = strlen(buffer));
b76ddc
    }
b76ddc
    return (SECSuccess);
b76ddc
}
b76ddc
b76ddc
static PRBool 
b76ddc
GetYesNo(char *prompt) 
b76ddc
{
b76ddc
    char buf[3];
b76ddc
    char *buffPrt;
b76ddc
b76ddc
    buf[0] = 'n';
b76ddc
    puts(prompt);
b76ddc
    buffPrt = Gets_s(buf, sizeof(buf));
b76ddc
    return (buffPrt && (buf[0] == 'y' || buf[0] == 'Y')) ? PR_TRUE : PR_FALSE;
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddKeyUsage (void *extHandle)
b76ddc
{
b76ddc
    SECItem bitStringValue;
b76ddc
    unsigned char keyUsage = 0x0;
b76ddc
    char buffer[5];
b76ddc
    int value;
b76ddc
    PRBool yesNoAns;
b76ddc
b76ddc
    while (1) {
b76ddc
        if (PrintChoicesAndGetAnswer(
b76ddc
                "\t\t0 - Digital Signature\n"
b76ddc
                "\t\t1 - Non-repudiation\n"
b76ddc
                "\t\t2 - Key encipherment\n"
b76ddc
                "\t\t3 - Data encipherment\n"   
b76ddc
                "\t\t4 - Key agreement\n"
b76ddc
                "\t\t5 - Cert signing key\n"   
b76ddc
                "\t\t6 - CRL signing key\n"
b76ddc
                "\t\tOther to finish\n",
b76ddc
                buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            return SECFailure;
b76ddc
        }
b76ddc
        value = PORT_Atoi (buffer);
b76ddc
        if (value < 0 || value > 6)
b76ddc
            break;
b76ddc
        if (value == 0) {
b76ddc
            /* Checking that zero value of variable 'value'
b76ddc
             * corresponds to '0' input made by user */
b76ddc
            char *chPtr = strchr(buffer, '0');
b76ddc
            if (chPtr == NULL) {
b76ddc
                continue;
b76ddc
            }
b76ddc
        }
b76ddc
        keyUsage |= (0x80 >> value);
b76ddc
    }
b76ddc
b76ddc
    bitStringValue.data = &keyUsage;
b76ddc
    bitStringValue.len = 1;
b76ddc
    yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
b76ddc
    return (CERT_EncodeAndAddBitStrExtension
b76ddc
            (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
b76ddc
             yesNoAns));
b76ddc
b76ddc
}
b76ddc
b76ddc
b76ddc
static CERTOidSequence *
b76ddc
CreateOidSequence(void)
b76ddc
{
b76ddc
    CERTOidSequence *rv = (CERTOidSequence *)NULL;
b76ddc
    PRArenaPool *arena = (PRArenaPool *)NULL;
b76ddc
b76ddc
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
    if( (PRArenaPool *)NULL == arena ) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    rv = (CERTOidSequence *)PORT_ArenaZNew(arena, CERTOidSequence);
b76ddc
    if( (CERTOidSequence *)NULL == rv ) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    rv->oids = (SECItem **)PORT_ArenaZNew(arena, SECItem *);
b76ddc
    if( (SECItem **)NULL == rv->oids ) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    rv->arena = arena;
b76ddc
    return rv;
b76ddc
b76ddc
loser:
b76ddc
    if( (PRArenaPool *)NULL != arena ) {
b76ddc
        PORT_FreeArena(arena, PR_FALSE);
b76ddc
    }
b76ddc
b76ddc
    return (CERTOidSequence *)NULL;
b76ddc
}
b76ddc
b76ddc
static void
b76ddc
DestroyOidSequence(CERTOidSequence *os)
b76ddc
{
b76ddc
    if (os->arena) {
b76ddc
        PORT_FreeArena(os->arena, PR_FALSE);
b76ddc
    }
b76ddc
}
b76ddc
b76ddc
static SECStatus
b76ddc
AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
b76ddc
{
b76ddc
    SECItem **oids;
b76ddc
    PRUint32 count = 0;
b76ddc
    SECOidData *od;
b76ddc
b76ddc
    od = SECOID_FindOIDByTag(oidTag);
b76ddc
    if( (SECOidData *)NULL == od ) {
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
b76ddc
    for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
b76ddc
        count++;
b76ddc
    }
b76ddc
b76ddc
    /* ArenaZRealloc */
b76ddc
b76ddc
    {
b76ddc
        PRUint32 i;
b76ddc
b76ddc
        oids = (SECItem **)PORT_ArenaZNewArray(os->arena, SECItem *, count + 2);
b76ddc
        if( (SECItem **)NULL == oids ) {
b76ddc
            return SECFailure;
b76ddc
        }
b76ddc
    
b76ddc
        for( i = 0; i < count; i++ ) {
b76ddc
            oids[i] = os->oids[i];
b76ddc
        }
b76ddc
b76ddc
        /* ArenaZFree(os->oids); */
b76ddc
    }
b76ddc
b76ddc
    os->oids = oids;
b76ddc
    os->oids[count] = &od->oid;
b76ddc
b76ddc
    return SECSuccess;
b76ddc
}
b76ddc
b76ddc
SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
b76ddc
b76ddc
const SEC_ASN1Template CERT_OidSeqTemplate[] = {
b76ddc
    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, offsetof(CERTOidSequence, oids),
b76ddc
      SEC_ASN1_SUB(SEC_ObjectIDTemplate) }
b76ddc
};
b76ddc
b76ddc
b76ddc
static SECItem *
b76ddc
EncodeOidSequence(CERTOidSequence *os)
b76ddc
{
b76ddc
    SECItem *rv;
b76ddc
b76ddc
    rv = (SECItem *)PORT_ArenaZNew(os->arena, SECItem);
b76ddc
    if( (SECItem *)NULL == rv ) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    return rv;
b76ddc
b76ddc
loser:
b76ddc
    return (SECItem *)NULL;
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddExtKeyUsage (void *extHandle)
b76ddc
{
b76ddc
    char buffer[5];
b76ddc
    int value;
b76ddc
    CERTOidSequence *os;
b76ddc
    SECStatus rv;
b76ddc
    SECItem *item;
b76ddc
    PRBool yesNoAns;
b76ddc
b76ddc
    os = CreateOidSequence();
b76ddc
    if( (CERTOidSequence *)NULL == os ) {
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
b76ddc
    while (1) {
b76ddc
        if (PrintChoicesAndGetAnswer(
b76ddc
                "\t\t0 - Server Auth\n"
b76ddc
                "\t\t1 - Client Auth\n"
b76ddc
                "\t\t2 - Code Signing\n"
b76ddc
                "\t\t3 - Email Protection\n"
b76ddc
                "\t\t4 - Timestamp\n"
b76ddc
                "\t\t5 - OCSP Responder\n"
b76ddc
                "\t\t6 - Step-up\n"
b76ddc
                "\t\tOther to finish\n",
b76ddc
                buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
        value = PORT_Atoi(buffer);
b76ddc
b76ddc
        if (value == 0) {
b76ddc
            /* Checking that zero value of variable 'value'
b76ddc
             * corresponds to '0' input made by user */
b76ddc
            char *chPtr = strchr(buffer, '0');
b76ddc
            if (chPtr == NULL) {
b76ddc
                continue;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        switch( value ) {
b76ddc
        case 0:
b76ddc
            rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH);
b76ddc
            break;
b76ddc
        case 1:
b76ddc
            rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH);
b76ddc
            break;
b76ddc
        case 2:
b76ddc
            rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN);
b76ddc
            break;
b76ddc
        case 3:
b76ddc
            rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT);
b76ddc
            break;
b76ddc
        case 4:
b76ddc
            rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP);
b76ddc
            break;
b76ddc
        case 5:
b76ddc
            rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
b76ddc
            break;
b76ddc
        case 6:
b76ddc
            rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED);
b76ddc
            break;
b76ddc
        default:
b76ddc
            goto endloop;
b76ddc
        }
b76ddc
b76ddc
        if( SECSuccess != rv ) goto loser;
b76ddc
    }
b76ddc
b76ddc
endloop:
b76ddc
    item = EncodeOidSequence(os);
b76ddc
b76ddc
    yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
b76ddc
    rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item,
b76ddc
                           yesNoAns, PR_TRUE);
b76ddc
    /*FALLTHROUGH*/
b76ddc
loser:
b76ddc
    DestroyOidSequence(os);
b76ddc
    return rv;
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddNscpCertType (void *extHandle)
b76ddc
{
b76ddc
    SECItem bitStringValue;
b76ddc
    unsigned char keyUsage = 0x0;
b76ddc
    char buffer[5];
b76ddc
    int value;
b76ddc
    PRBool yesNoAns;
b76ddc
b76ddc
    while (1) {
b76ddc
        if (PrintChoicesAndGetAnswer(
b76ddc
                "\t\t0 - SSL Client\n"
b76ddc
                "\t\t1 - SSL Server\n"
b76ddc
                "\t\t2 - S/MIME\n"
b76ddc
                "\t\t3 - Object Signing\n"   
b76ddc
                "\t\t4 - Reserved for future use\n"
b76ddc
                "\t\t5 - SSL CA\n"   
b76ddc
                "\t\t6 - S/MIME CA\n"
b76ddc
                "\t\t7 - Object Signing CA\n"
b76ddc
                "\t\tOther to finish\n",
b76ddc
                buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            return SECFailure;
b76ddc
        }
b76ddc
        value = PORT_Atoi (buffer);
b76ddc
        if (value < 0 || value > 7)
b76ddc
            break;
b76ddc
        if (value == 0) {
b76ddc
            /* Checking that zero value of variable 'value'
b76ddc
             * corresponds to '0' input made by user */
b76ddc
            char *chPtr = strchr(buffer, '0');
b76ddc
            if (chPtr == NULL) {
b76ddc
                continue;
b76ddc
            }
b76ddc
        }
b76ddc
        keyUsage |= (0x80 >> value);
b76ddc
    }
b76ddc
b76ddc
    bitStringValue.data = &keyUsage;
b76ddc
    bitStringValue.len = 1;
b76ddc
    yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
b76ddc
    return (CERT_EncodeAndAddBitStrExtension
b76ddc
            (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue,
b76ddc
             yesNoAns));
b76ddc
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddSubjectAltNames(PRArenaPool *arena, CERTGeneralName **existingListp,
b76ddc
                   const char *names, CERTGeneralNameType type)
b76ddc
{
b76ddc
    CERTGeneralName *nameList = NULL;
b76ddc
    CERTGeneralName *current = NULL;
b76ddc
    PRCList *prev = NULL;
b76ddc
    const char *cp;
b76ddc
    char *tbuf;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
b76ddc
b76ddc
    /*
b76ddc
     * walk down the comma separated list of names. NOTE: there is
b76ddc
     * no sanity checks to see if the email address look like
b76ddc
     * email addresses.
b76ddc
     */
b76ddc
    for (cp=names; cp; cp = PORT_Strchr(cp,',')) {
b76ddc
        int len;
b76ddc
        char *end;
b76ddc
b76ddc
        if (*cp == ',') {
b76ddc
            cp++;
b76ddc
        }
b76ddc
        end = PORT_Strchr(cp,',');
b76ddc
        len = end ? end-cp : PORT_Strlen(cp);
b76ddc
        if (len <= 0) {
b76ddc
            continue;
b76ddc
        }
b76ddc
        tbuf = PORT_ArenaAlloc(arena,len+1);
b76ddc
        PORT_Memcpy(tbuf,cp,len);
b76ddc
        tbuf[len] = 0;
b76ddc
        current = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName));
b76ddc
        if (!current) {
b76ddc
            rv = SECFailure;
b76ddc
            break;
b76ddc
        }
b76ddc
        if (prev) {
b76ddc
            current->l.prev = prev;
b76ddc
            prev->next = &(current->l);
b76ddc
        } else {
b76ddc
            nameList = current;
b76ddc
        }
b76ddc
        current->type = type;
b76ddc
        current->name.other.data = (unsigned char *)tbuf;
b76ddc
        current->name.other.len = PORT_Strlen(tbuf);
b76ddc
        prev = &(current->l);
b76ddc
    }
b76ddc
    /* at this point nameList points to the head of a doubly linked,
b76ddc
     * but not yet circular, list and current points to its tail. */
b76ddc
    if (rv == SECSuccess && nameList) {
b76ddc
        if (*existingListp != NULL) {
b76ddc
            PRCList *existingprev;
b76ddc
            /* add nameList to the end of the existing list */
b76ddc
            existingprev = (*existingListp)->l.prev;
b76ddc
            (*existingListp)->l.prev = &(current->l);
b76ddc
            nameList->l.prev = existingprev;
b76ddc
            existingprev->next = &(nameList->l);
b76ddc
            current->l.next = &((*existingListp)->l);
b76ddc
        }
b76ddc
        else {
b76ddc
            /* make nameList circular and set it as the new existingList */
b76ddc
            nameList->l.prev = prev;
b76ddc
            current->l.next = &(nameList->l);
b76ddc
            *existingListp = nameList;
b76ddc
        }
b76ddc
    }
b76ddc
    return rv;
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddEmailSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp,
b76ddc
                   const char *emailAddrs)
b76ddc
{
b76ddc
    return AddSubjectAltNames(arena, existingListp, emailAddrs, 
b76ddc
                              certRFC822Name);
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddDNSSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp,
b76ddc
                 const char *dnsNames)
b76ddc
{
b76ddc
    return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName);
b76ddc
}
b76ddc
b76ddc
b76ddc
static SECStatus 
b76ddc
AddBasicConstraint(void *extHandle)
b76ddc
{
b76ddc
    CERTBasicConstraints basicConstraint;    
b76ddc
    SECStatus rv;
b76ddc
    char buffer[10];
b76ddc
    PRBool yesNoAns;
b76ddc
b76ddc
    do {
b76ddc
        basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
b76ddc
        basicConstraint.isCA = GetYesNo ("Is this a CA certificate [y/N]?");
b76ddc
b76ddc
        buffer[0] = '\0';
b76ddc
        if (PrintChoicesAndGetAnswer("Enter the path length constraint, "
b76ddc
                                     "enter to skip [<0 for unlimited path]:",
b76ddc
                                     buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
        if (PORT_Strlen (buffer) > 0)
b76ddc
            basicConstraint.pathLenConstraint = PORT_Atoi (buffer);
b76ddc
b76ddc
        yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
b76ddc
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(NULL, extHandle,
b76ddc
         &basicConstraint, yesNoAns, SEC_OID_X509_BASIC_CONSTRAINTS,
b76ddc
         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeBasicConstraintValue);
b76ddc
    } while (0);
b76ddc
b76ddc
    return (rv);
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddAuthKeyID (void *extHandle)
b76ddc
{
b76ddc
    CERTAuthKeyID *authKeyID = NULL;    
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    PRBool yesNoAns;
b76ddc
b76ddc
    do {
b76ddc
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
        if ( !arena ) {
b76ddc
            SECU_PrintError(progName, "out of memory");
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        if (GetYesNo ("Enter value for the authKeyID extension [y/N]?") == 0)
b76ddc
            break;
b76ddc
b76ddc
        authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID);
b76ddc
        if (authKeyID == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        rv = GetString (arena, "Enter value for the key identifier fields,"
b76ddc
                        "enter to omit:", &authKeyID->keyID);
b76ddc
        if (rv != SECSuccess)
b76ddc
            break;
b76ddc
b76ddc
        SECU_SECItemHexStringToBinary(&authKeyID->keyID);
b76ddc
b76ddc
        authKeyID->authCertIssuer = GetGeneralName (arena);
b76ddc
        if (authKeyID->authCertIssuer == NULL && 
b76ddc
            SECFailure == PORT_GetError ())
b76ddc
            break;
b76ddc
b76ddc
b76ddc
        rv = GetString (arena, "Enter value for the authCertSerial field, "
b76ddc
                        "enter to omit:", &authKeyID->authCertSerialNumber);
b76ddc
b76ddc
        yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
b76ddc
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle,
b76ddc
             authKeyID, yesNoAns, SEC_OID_X509_AUTH_KEY_ID, 
b76ddc
             (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID);
b76ddc
        if (rv)
b76ddc
            break;
b76ddc
b76ddc
    } while (0);
b76ddc
    if (arena)
b76ddc
        PORT_FreeArena (arena, PR_FALSE);
b76ddc
    return (rv);
b76ddc
}   
b76ddc
    
b76ddc
static SECStatus 
b76ddc
AddSubjKeyID (void *extHandle)
b76ddc
{
b76ddc
    SECItem keyID;
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    PRBool yesNoAns;
b76ddc
b76ddc
    do {
b76ddc
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
        if ( !arena ) {
b76ddc
            SECU_PrintError(progName, "out of memory");
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
        printf("Adding Subject Key ID extension.\n");
b76ddc
b76ddc
        rv = GetString (arena, "Enter value for the key identifier fields,"
b76ddc
                        "enter to omit:", &keyID);
b76ddc
        if (rv != SECSuccess)
b76ddc
            break;
b76ddc
b76ddc
        SECU_SECItemHexStringToBinary(&keyID);
b76ddc
b76ddc
        yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
b76ddc
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle,
b76ddc
             &keyID, yesNoAns, SEC_OID_X509_SUBJECT_KEY_ID, 
b76ddc
             (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeSubjectKeyID);
b76ddc
        if (rv)
b76ddc
            break;
b76ddc
b76ddc
    } while (0);
b76ddc
    if (arena)
b76ddc
        PORT_FreeArena (arena, PR_FALSE);
b76ddc
    return (rv);
b76ddc
}   
b76ddc
b76ddc
static SECStatus 
b76ddc
AddCrlDistPoint(void *extHandle)
b76ddc
{
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    CERTCrlDistributionPoints *crlDistPoints = NULL;
b76ddc
    CRLDistributionPoint *current;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    int count = 0, intValue;
b76ddc
    char buffer[512];
b76ddc
b76ddc
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
    if ( !arena )
b76ddc
        return (SECFailure);
b76ddc
b76ddc
    do {
b76ddc
        current = NULL;
b76ddc
b76ddc
        current = PORT_ArenaZNew(arena, CRLDistributionPoint);
b76ddc
        if (current == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }   
b76ddc
b76ddc
        /* Get the distributionPointName fields - this field is optional */
b76ddc
        if (PrintChoicesAndGetAnswer(
b76ddc
                "Enter the type of the distribution point name:\n"
b76ddc
                "\t1 - Full Name\n\t2 - Relative Name\n\tAny other "
b76ddc
                "number to finish\n\t\tChoice: ",
b76ddc
                buffer, sizeof(buffer)) == SECFailure) {
b76ddc
        GEN_BREAK (SECFailure);
b76ddc
    }
b76ddc
        intValue = PORT_Atoi (buffer);
b76ddc
        switch (intValue) {
b76ddc
        case generalName:
b76ddc
            current->distPointType = intValue;
b76ddc
            current->distPoint.fullName = GetGeneralName (arena);
b76ddc
            rv = PORT_GetError();
b76ddc
            break;
b76ddc
b76ddc
        case relativeDistinguishedName: {
b76ddc
            CERTName *name;
b76ddc
b76ddc
            current->distPointType = intValue;
b76ddc
            puts ("Enter the relative name: ");
b76ddc
            fflush (stdout);
b76ddc
            if (Gets_s (buffer, sizeof(buffer)) == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            /* For simplicity, use CERT_AsciiToName to converse from a string
b76ddc
               to NAME, but we only interest in the first RDN */
b76ddc
            name = CERT_AsciiToName (buffer);
b76ddc
            if (!name) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            rv = CERT_CopyRDN (arena, &current->distPoint.relativeName,
b76ddc
                               name->rdns[0]);
b76ddc
            CERT_DestroyName (name);
b76ddc
            break;
b76ddc
          }
b76ddc
        }
b76ddc
        if (rv != SECSuccess)
b76ddc
            break;
b76ddc
b76ddc
        /* Get the reason flags */
b76ddc
        if (PrintChoicesAndGetAnswer(
b76ddc
                "\nSelect one of the following for the reason flags\n"
b76ddc
                "\t0 - unused\n\t1 - keyCompromise\n"
b76ddc
                "\t2 - caCompromise\n\t3 - affiliationChanged\n"
b76ddc
                "\t4 - superseded\n\t5 - cessationOfOperation\n"
b76ddc
                "\t6 - certificateHold\n"
b76ddc
                "\tAny other number to finish\t\tChoice: ",
b76ddc
                buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
        intValue = PORT_Atoi (buffer);
b76ddc
        if (intValue == 0) {
b76ddc
            /* Checking that zero value of variable 'value'
b76ddc
             * corresponds to '0' input made by user */
b76ddc
            char *chPtr = strchr(buffer, '0');
b76ddc
            if (chPtr == NULL) {
b76ddc
                intValue = -1;
b76ddc
            }
b76ddc
        }
b76ddc
        if (intValue >= 0 && intValue <8) {
b76ddc
            current->reasons.data = PORT_ArenaAlloc (arena, sizeof(char));
b76ddc
            if (current->reasons.data == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            *current->reasons.data = (char)(0x80 >> intValue);
b76ddc
            current->reasons.len = 1;
b76ddc
        }
b76ddc
        puts ("Enter value for the CRL Issuer name:\n");
b76ddc
        current->crlIssuer = GetGeneralName (arena);
b76ddc
        if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure)
b76ddc
            break;
b76ddc
b76ddc
        if (crlDistPoints == NULL) {
b76ddc
            crlDistPoints = PORT_ArenaZNew(arena, CERTCrlDistributionPoints);
b76ddc
            if (crlDistPoints == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        crlDistPoints->distPoints =
b76ddc
            PORT_ArenaGrow (arena, crlDistPoints->distPoints,
b76ddc
                            sizeof (*crlDistPoints->distPoints) * count,
b76ddc
                            sizeof (*crlDistPoints->distPoints) *(count + 1));
b76ddc
        if (crlDistPoints->distPoints == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        crlDistPoints->distPoints[count] = current;
b76ddc
        ++count;
b76ddc
        if (GetYesNo("Enter another value for the CRLDistributionPoint "
b76ddc
                      "extension [y/N]?") == 0) {
b76ddc
            /* Add null to the end to mark end of data */
b76ddc
            crlDistPoints->distPoints =
b76ddc
                PORT_ArenaGrow(arena, crlDistPoints->distPoints,
b76ddc
               sizeof (*crlDistPoints->distPoints) * count,
b76ddc
               sizeof (*crlDistPoints->distPoints) *(count + 1));
b76ddc
            crlDistPoints->distPoints[count] = NULL;    
b76ddc
            break;
b76ddc
        }
b76ddc
b76ddc
b76ddc
    } while (1);
b76ddc
    
b76ddc
    if (rv == SECSuccess) {
b76ddc
        PRBool yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
b76ddc
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle,
b76ddc
         crlDistPoints, yesNoAns, SEC_OID_X509_CRL_DIST_POINTS,
b76ddc
         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCRLDistributionPoints);
b76ddc
    }
b76ddc
    if (arena)
b76ddc
        PORT_FreeArena (arena, PR_FALSE);
b76ddc
    return (rv);
b76ddc
}
b76ddc
b76ddc
b76ddc
b76ddc
static SECStatus 
b76ddc
AddPolicyConstraints(void *extHandle)
b76ddc
{
b76ddc
    CERTCertificatePolicyConstraints *policyConstr;
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    SECItem *item, *dummy;
b76ddc
    char buffer[512];
b76ddc
    int value;
b76ddc
    PRBool yesNoAns;
b76ddc
    PRBool skipExt = PR_TRUE;
b76ddc
b76ddc
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
    if ( !arena ) {
b76ddc
        SECU_PrintError(progName, "out of memory");
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
b76ddc
    policyConstr = PORT_ArenaZNew(arena, CERTCertificatePolicyConstraints);
b76ddc
    if (policyConstr == NULL) {
b76ddc
        SECU_PrintError(progName, "out of memory");
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    if (PrintChoicesAndGetAnswer("for requireExplicitPolicy enter the number "
b76ddc
               "of certs in path\nbefore explicit policy is required\n"
b76ddc
               "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    if (PORT_Strlen(buffer)) {
b76ddc
        value = PORT_Atoi(buffer);
b76ddc
    if (value < 0) {
b76ddc
            goto loser;
b76ddc
        }
b76ddc
        item = &policyConstr->explicitPolicySkipCerts;
b76ddc
        dummy = SEC_ASN1EncodeInteger(arena, item, value);
b76ddc
        if (!dummy) {
b76ddc
            goto loser;
b76ddc
        }
b76ddc
        skipExt = PR_FALSE;
b76ddc
    }
b76ddc
b76ddc
    if (PrintChoicesAndGetAnswer("for inihibitPolicyMapping enter "
b76ddc
               "the number of certs in path\n"
b76ddc
           "after which policy mapping is not allowed\n"
b76ddc
               "(press Enter to omit)", buffer, sizeof(buffer)) == SECFailure) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    if (PORT_Strlen(buffer)) {
b76ddc
        value = PORT_Atoi(buffer);
b76ddc
    if (value < 0) {
b76ddc
            goto loser;
b76ddc
        }
b76ddc
        item = &policyConstr->inhibitMappingSkipCerts;
b76ddc
        dummy = SEC_ASN1EncodeInteger(arena, item, value);
b76ddc
        if (!dummy) {
b76ddc
            goto loser;
b76ddc
        }
b76ddc
        skipExt = PR_FALSE;
b76ddc
    }
b76ddc
 
b76ddc
    
b76ddc
    if (!skipExt) {
b76ddc
        yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, policyConstr,
b76ddc
         yesNoAns, SEC_OID_X509_POLICY_CONSTRAINTS,
b76ddc
         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyConstraintsExtension);
b76ddc
    } else {
b76ddc
        fprintf(stdout, "Policy Constraint extensions must contain "
b76ddc
                        "at least one policy field\n");
b76ddc
        rv = SECFailure;
b76ddc
    }
b76ddc
   
b76ddc
loser:
b76ddc
    if (arena) {
b76ddc
        PORT_FreeArena (arena, PR_FALSE);
b76ddc
    }
b76ddc
    return (rv);
b76ddc
}
b76ddc
b76ddc
b76ddc
static SECStatus 
b76ddc
AddInhibitAnyPolicy(void *extHandle)
b76ddc
{
b76ddc
    CERTCertificateInhibitAny certInhibitAny;
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    SECItem *item, *dummy;
b76ddc
    char buffer[10];
b76ddc
    int value;
b76ddc
    PRBool yesNoAns;
b76ddc
    
b76ddc
b76ddc
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
    if ( !arena ) {
b76ddc
        SECU_PrintError(progName, "out of memory");
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
b76ddc
    if (PrintChoicesAndGetAnswer("Enter the number of certs in the path "
b76ddc
                                 "permitted to use anyPolicy.\n"
b76ddc
                                 "(press Enter for 0)",
b76ddc
                                 buffer, sizeof(buffer)) == SECFailure) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
b76ddc
    item = &certInhibitAny.inhibitAnySkipCerts;
b76ddc
    value = PORT_Atoi(buffer);
b76ddc
    if (value < 0) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
    dummy = SEC_ASN1EncodeInteger(arena, item, value);
b76ddc
    if (!dummy) {
b76ddc
        goto loser;
b76ddc
    }
b76ddc
    
b76ddc
    yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
    
b76ddc
    rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &certInhibitAny,
b76ddc
         yesNoAns, SEC_OID_X509_INHIBIT_ANY_POLICY,
b76ddc
         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInhibitAnyExtension);
b76ddc
loser:
b76ddc
    if (arena) {
b76ddc
        PORT_FreeArena (arena, PR_FALSE);
b76ddc
    }
b76ddc
    return (rv);
b76ddc
}
b76ddc
b76ddc
b76ddc
static SECStatus 
b76ddc
AddPolicyMappings(void *extHandle)
b76ddc
{
b76ddc
    CERTPolicyMap **policyMapArr = NULL;
b76ddc
    CERTPolicyMap *current;
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    int count = 0;
b76ddc
    char buffer[512];
b76ddc
    
b76ddc
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
    if ( !arena ) {
b76ddc
        SECU_PrintError(progName, "out of memory");
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
b76ddc
    do {
b76ddc
        if (PrintChoicesAndGetAnswer("Enter an Object Identifier (dotted "
b76ddc
                                     "decimal format) for Issuer Domain Policy",
b76ddc
                                     buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        current = PORT_ArenaZNew(arena, CERTPolicyMap);
b76ddc
        if (current == NULL) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
b76ddc
        rv = SEC_StringToOID(arena, &current->issuerDomainPolicy, buffer, 0);
b76ddc
        if (rv == SECFailure) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
b76ddc
        if (PrintChoicesAndGetAnswer("Enter an Object Identifier for "
b76ddc
                                     "Subject Domain Policy",
b76ddc
                                     buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        rv = SEC_StringToOID(arena, &current->subjectDomainPolicy, buffer, 0);
b76ddc
        if (rv == SECFailure) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
b76ddc
        if (policyMapArr == NULL) {
b76ddc
            policyMapArr = PORT_ArenaZNew(arena, CERTPolicyMap *);
b76ddc
            if (policyMapArr == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        policyMapArr = PORT_ArenaGrow(arena, policyMapArr,
b76ddc
                                         sizeof (current) * count,
b76ddc
                                         sizeof (current) *(count + 1));
b76ddc
        if (policyMapArr == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
    
b76ddc
        policyMapArr[count] = current;
b76ddc
        ++count;
b76ddc
        
b76ddc
        if (!GetYesNo("Enter another Policy Mapping [y/N]")) {
b76ddc
            /* Add null to the end to mark end of data */
b76ddc
            policyMapArr = PORT_ArenaGrow (arena, policyMapArr,
b76ddc
                                           sizeof (current) * count,
b76ddc
                                           sizeof (current) *(count + 1));
b76ddc
            if (policyMapArr == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            policyMapArr[count] = NULL;        
b76ddc
            break;
b76ddc
        }
b76ddc
b76ddc
    } while (1);
b76ddc
b76ddc
    if (rv == SECSuccess) {
b76ddc
        CERTCertificatePolicyMappings mappings;
b76ddc
        PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
b76ddc
        mappings.arena = arena;
b76ddc
        mappings.policyMaps = policyMapArr;
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &mappings,
b76ddc
         yesNoAns, SEC_OID_X509_POLICY_MAPPINGS,
b76ddc
         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodePolicyMappingExtension);
b76ddc
    }
b76ddc
    if (arena)
b76ddc
        PORT_FreeArena (arena, PR_FALSE);
b76ddc
    return (rv);
b76ddc
}
b76ddc
b76ddc
enum PoliciQualifierEnum {
b76ddc
    cpsPointer = 1,
b76ddc
    userNotice = 2
b76ddc
};
b76ddc
b76ddc
static CERTPolicyQualifier **
b76ddc
RequestPolicyQualifiers(PRArenaPool *arena, SECItem *policyID)
b76ddc
{
b76ddc
    CERTPolicyQualifier **policyQualifArr = NULL;
b76ddc
    CERTPolicyQualifier *current;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    int count = 0;
b76ddc
    char buffer[512];
b76ddc
    void *mark;
b76ddc
    SECOidData *oid = NULL;
b76ddc
    int intValue = 0;
b76ddc
    int inCount = 0;
b76ddc
b76ddc
    PORT_Assert(arena);
b76ddc
    mark = PORT_ArenaMark(arena);
b76ddc
    do {
b76ddc
        current = PORT_ArenaZNew(arena, CERTPolicyQualifier);
b76ddc
        if (current == NULL) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
b76ddc
        /* Get the accessMethod fields */
b76ddc
        SECU_PrintObjectID(stdout, policyID,
b76ddc
                           "Choose the type of qualifier for policy" , 0);
b76ddc
b76ddc
        if (PrintChoicesAndGetAnswer(
b76ddc
                "\t1 - CPS Pointer qualifier\n"
b76ddc
                "\t2 - User notice qualifier\n"
b76ddc
                "\tAny other number to finish\n"
b76ddc
                "\t\tChoice: ", buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
        intValue = PORT_Atoi(buffer);
b76ddc
        switch (intValue) {
b76ddc
        case cpsPointer: {
b76ddc
            SECItem input;
b76ddc
b76ddc
            oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CPS_POINTER_QUALIFIER);
b76ddc
            if (PrintChoicesAndGetAnswer("Enter CPS pointer URI: ",
b76ddc
                     buffer, sizeof(buffer)) == SECFailure) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            input.len = PORT_Strlen(buffer);
b76ddc
            input.data = (void*)PORT_ArenaStrdup(arena, buffer);
b76ddc
            if (input.data == NULL ||
b76ddc
            SEC_ASN1EncodeItem(arena, &current->qualifierValue, &input,
b76ddc
                   SEC_ASN1_GET(SEC_IA5StringTemplate)) == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            break;
b76ddc
        }
b76ddc
        case userNotice: {
b76ddc
            SECItem **noticeNumArr;
b76ddc
            CERTUserNotice *notice = PORT_ArenaZNew(arena, CERTUserNotice);
b76ddc
            if (!notice) {
b76ddc
                GEN_BREAK(SECFailure);
b76ddc
            }
b76ddc
            
b76ddc
            oid = SECOID_FindOIDByTag(SEC_OID_PKIX_USER_NOTICE_QUALIFIER);
b76ddc
b76ddc
            if (GetYesNo("\t add a User Notice reference? [y/N]")) {
b76ddc
b76ddc
                if (PrintChoicesAndGetAnswer("Enter user organization string: ",
b76ddc
                 buffer, sizeof(buffer)) == SECFailure) {
b76ddc
                    GEN_BREAK (SECFailure);
b76ddc
                }
b76ddc
b76ddc
                notice->noticeReference.organization.type = siAsciiString;
b76ddc
                notice->noticeReference.organization.len =
b76ddc
                    PORT_Strlen(buffer);
b76ddc
                notice->noticeReference.organization.data =
b76ddc
                    (void*)PORT_ArenaStrdup(arena, buffer);
b76ddc
b76ddc
b76ddc
                noticeNumArr = PORT_ArenaZNewArray(arena, SECItem *, 2);
b76ddc
                if (!noticeNumArr) {
b76ddc
                    GEN_BREAK (SECFailure);
b76ddc
                }
b76ddc
                
b76ddc
                do {
b76ddc
                    SECItem *noticeNum;
b76ddc
                    
b76ddc
                    noticeNum = PORT_ArenaZNew(arena, SECItem);
b76ddc
                    
b76ddc
                    if (PrintChoicesAndGetAnswer(
b76ddc
                      "Enter User Notice reference number "
b76ddc
                      "(or -1 to quit): ",
b76ddc
                                      buffer, sizeof(buffer)) == SECFailure) {
b76ddc
                        GEN_BREAK (SECFailure);
b76ddc
                    }
b76ddc
                    
b76ddc
                    intValue = PORT_Atoi(buffer);
b76ddc
                    if (noticeNum == NULL) {
b76ddc
                        if (intValue < 0) {
b76ddc
                            fprintf(stdout, "a noticeReference must have at "
b76ddc
                                    "least one reference number\n");
b76ddc
                            GEN_BREAK (SECFailure);
b76ddc
                        }
b76ddc
                    } else {
b76ddc
                        if (intValue >= 0) {
b76ddc
                            noticeNumArr = PORT_ArenaGrow(arena, noticeNumArr,
b76ddc
                          sizeof (current) * inCount,
b76ddc
                          sizeof (current) *(inCount + 1));
b76ddc
                            if (noticeNumArr == NULL) {
b76ddc
                                GEN_BREAK (SECFailure);
b76ddc
                            }
b76ddc
                        } else {
b76ddc
                            break;
b76ddc
                        }
b76ddc
                    }
b76ddc
                    if (!SEC_ASN1EncodeInteger(arena, noticeNum, intValue)) {
b76ddc
                        GEN_BREAK (SECFailure);
b76ddc
                    }
b76ddc
                    noticeNumArr[inCount++] = noticeNum;
b76ddc
                    noticeNumArr[inCount] = NULL;
b76ddc
                    
b76ddc
                } while (1);
b76ddc
                if (rv == SECFailure) {
b76ddc
                    GEN_BREAK(SECFailure);
b76ddc
                }
b76ddc
                notice->noticeReference.noticeNumbers = noticeNumArr;
b76ddc
                rv = CERT_EncodeNoticeReference(arena, &notice->noticeReference,
b76ddc
                                                &notice->derNoticeReference);
b76ddc
                if (rv == SECFailure) {
b76ddc
                    GEN_BREAK(SECFailure);
b76ddc
                }
b76ddc
            }
b76ddc
            if (GetYesNo("\t EnterUser Notice explicit text? [y/N]")) {
b76ddc
                /* Getting only 200 bytes - RFC limitation */
b76ddc
                if (PrintChoicesAndGetAnswer(
b76ddc
                        "\t", buffer, 200) == SECFailure) {
b76ddc
                        GEN_BREAK (SECFailure);
b76ddc
                }
b76ddc
                notice->displayText.type = siAsciiString;
b76ddc
                notice->displayText.len = PORT_Strlen(buffer);
b76ddc
                notice->displayText.data = 
b76ddc
                                (void*)PORT_ArenaStrdup(arena, buffer);
b76ddc
        if (notice->displayText.data == NULL) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
            }
b76ddc
b76ddc
            rv = CERT_EncodeUserNotice(arena, notice, &current->qualifierValue);
b76ddc
            if (rv == SECFailure) {
b76ddc
                GEN_BREAK(SECFailure);
b76ddc
            }
b76ddc
b76ddc
            break;
b76ddc
        }
b76ddc
        }
b76ddc
        if (rv == SECFailure || oid == NULL ||
b76ddc
            SECITEM_CopyItem(arena, &current->qualifierID, &oid->oid) 
b76ddc
            == SECFailure) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        if (!policyQualifArr) {
b76ddc
            policyQualifArr = PORT_ArenaZNew(arena, CERTPolicyQualifier *);
b76ddc
        } else {
b76ddc
            policyQualifArr = PORT_ArenaGrow (arena, policyQualifArr,
b76ddc
                                         sizeof (current) * count,
b76ddc
                                         sizeof (current) *(count + 1));
b76ddc
        }
b76ddc
        if (policyQualifArr == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
    
b76ddc
        policyQualifArr[count] = current;
b76ddc
        ++count;
b76ddc
b76ddc
        if (!GetYesNo ("Enter another policy qualifier [y/N]")) {
b76ddc
            /* Add null to the end to mark end of data */
b76ddc
            policyQualifArr = PORT_ArenaGrow(arena, policyQualifArr,
b76ddc
                                              sizeof (current) * count,
b76ddc
                                              sizeof (current) *(count + 1));
b76ddc
            if (policyQualifArr == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            policyQualifArr[count] = NULL;        
b76ddc
            break;
b76ddc
        }
b76ddc
b76ddc
    } while (1);
b76ddc
b76ddc
    if (rv != SECSuccess) {
b76ddc
        PORT_ArenaRelease (arena, mark);
b76ddc
        policyQualifArr = NULL;
b76ddc
    }
b76ddc
    return (policyQualifArr);
b76ddc
}
b76ddc
b76ddc
static SECStatus 
b76ddc
AddCertPolicies(void *extHandle)
b76ddc
{
b76ddc
    CERTPolicyInfo **certPoliciesArr = NULL;
b76ddc
    CERTPolicyInfo *current;
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    int count = 0;
b76ddc
    char buffer[512];
b76ddc
b76ddc
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
    if ( !arena ) {
b76ddc
        SECU_PrintError(progName, "out of memory");
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
b76ddc
    do {
b76ddc
        current = PORT_ArenaZNew(arena, CERTPolicyInfo);
b76ddc
        if (current == NULL) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
b76ddc
        if (PrintChoicesAndGetAnswer("Enter a CertPolicy Object Identifier "
b76ddc
                                     "(dotted decimal format)\n"
b76ddc
                                     "or \"any\" for AnyPolicy:",
b76ddc
                                     buffer, sizeof(buffer)) == SECFailure) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
    
b76ddc
        if (strncmp(buffer, "any", 3) == 0) {
b76ddc
            /* use string version of X509_CERTIFICATE_POLICIES.anyPolicy */
b76ddc
            strcpy(buffer, "OID.2.5.29.32.0");
b76ddc
        }
b76ddc
        rv = SEC_StringToOID(arena, &current->policyID, buffer, 0);
b76ddc
b76ddc
        if (rv == SECFailure) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
        
b76ddc
        current->policyQualifiers = 
b76ddc
            RequestPolicyQualifiers(arena, &current->policyID); 
b76ddc
b76ddc
        if (!certPoliciesArr) {
b76ddc
            certPoliciesArr = PORT_ArenaZNew(arena, CERTPolicyInfo *);
b76ddc
        } else {
b76ddc
        certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr,
b76ddc
                                         sizeof (current) * count,
b76ddc
                                         sizeof (current) *(count + 1));
b76ddc
        }
b76ddc
        if (certPoliciesArr == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
    
b76ddc
        certPoliciesArr[count] = current;
b76ddc
        ++count;
b76ddc
        
b76ddc
        if (!GetYesNo ("Enter another PolicyInformation field [y/N]?")) {
b76ddc
            /* Add null to the end to mark end of data */
b76ddc
            certPoliciesArr = PORT_ArenaGrow(arena, certPoliciesArr,
b76ddc
                                              sizeof (current) * count,
b76ddc
                                              sizeof (current) *(count + 1));
b76ddc
            if (certPoliciesArr == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            certPoliciesArr[count] = NULL;        
b76ddc
            break;
b76ddc
        }
b76ddc
b76ddc
    } while (1);
b76ddc
b76ddc
    if (rv == SECSuccess) {
b76ddc
        CERTCertificatePolicies policies;
b76ddc
        PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
b76ddc
        policies.arena = arena;
b76ddc
        policies.policyInfos = certPoliciesArr;
b76ddc
        
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, &policies,
b76ddc
         yesNoAns, SEC_OID_X509_CERTIFICATE_POLICIES,
b76ddc
         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeCertPoliciesExtension);
b76ddc
    }
b76ddc
    if (arena)
b76ddc
    PORT_FreeArena(arena, PR_FALSE);
b76ddc
    return (rv);
b76ddc
}
b76ddc
b76ddc
enum AuthInfoAccessTypesEnum {
b76ddc
    caIssuers = 1,
b76ddc
    ocsp = 2
b76ddc
};
b76ddc
b76ddc
enum SubjInfoAccessTypesEnum {
b76ddc
    caRepository = 1,
b76ddc
    timeStamping = 2
b76ddc
};
b76ddc
b76ddc
/* Encode and add an AIA or SIA extension */
b76ddc
static SECStatus 
b76ddc
AddInfoAccess(void *extHandle, PRBool addSIAExt, PRBool isCACert)
b76ddc
{
b76ddc
    CERTAuthInfoAccess **infoAccArr = NULL;
b76ddc
    CERTAuthInfoAccess *current;
b76ddc
    PRArenaPool *arena = NULL;
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    int count = 0;
b76ddc
    char buffer[512];
b76ddc
    SECOidData *oid = NULL;
b76ddc
    int intValue = 0;
b76ddc
b76ddc
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
    if ( !arena ) {
b76ddc
        SECU_PrintError(progName, "out of memory");
b76ddc
        return SECFailure;
b76ddc
    }
b76ddc
b76ddc
    do {
b76ddc
        current = NULL;
b76ddc
        current = PORT_ArenaZNew(arena, CERTAuthInfoAccess);
b76ddc
        if (current == NULL) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
b76ddc
        /* Get the accessMethod fields */
b76ddc
        if (addSIAExt) {
b76ddc
            if (isCACert) {
b76ddc
                puts("Adding \"CA Repository\" access method type for "
b76ddc
                    "Subject Information Access extension:\n");
b76ddc
                intValue = caRepository;
b76ddc
            } else {
b76ddc
                puts("Adding \"Time Stamping Services\" access method type for "
b76ddc
                    "Subject Information Access extension:\n");
b76ddc
                intValue = timeStamping;
b76ddc
            }
b76ddc
        } else {
b76ddc
            PrintChoicesAndGetAnswer("Enter access method type "
b76ddc
                "for Authority Information Access extension:\n"
b76ddc
                "\t1 - CA Issuers\n\t2 - OCSP\n\tAny"
b76ddc
                "other number to finish\n\tChoice",
b76ddc
                buffer, sizeof(buffer));
b76ddc
            intValue = PORT_Atoi(buffer);
b76ddc
        }
b76ddc
        if (addSIAExt) {
b76ddc
            switch (intValue) {
b76ddc
              case caRepository:
b76ddc
                  oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_REPOSITORY);
b76ddc
                  break;
b76ddc
                  
b76ddc
              case timeStamping:
b76ddc
                  oid = SECOID_FindOIDByTag(SEC_OID_PKIX_TIMESTAMPING);
b76ddc
                  break;
b76ddc
            } 
b76ddc
        } else {
b76ddc
            switch (intValue) {
b76ddc
              case caIssuers:
b76ddc
                  oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_ISSUERS);
b76ddc
                  break;
b76ddc
                  
b76ddc
              case ocsp:
b76ddc
                  oid = SECOID_FindOIDByTag(SEC_OID_PKIX_OCSP);
b76ddc
                  break;
b76ddc
            } 
b76ddc
        }
b76ddc
        if (oid == NULL ||
b76ddc
            SECITEM_CopyItem(arena, &current->method, &oid->oid) 
b76ddc
            == SECFailure) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
b76ddc
        current->location = GetGeneralName(arena);
b76ddc
        if (!current->location) {
b76ddc
            GEN_BREAK(SECFailure);
b76ddc
        }
b76ddc
       
b76ddc
        if (infoAccArr == NULL) {
b76ddc
            infoAccArr = PORT_ArenaZNew(arena, CERTAuthInfoAccess *);
b76ddc
        } else {
b76ddc
            infoAccArr = PORT_ArenaGrow(arena, infoAccArr,
b76ddc
                                     sizeof (current) * count,
b76ddc
                                     sizeof (current) *(count + 1));
b76ddc
        }
b76ddc
        if (infoAccArr == NULL) {
b76ddc
            GEN_BREAK (SECFailure);
b76ddc
        }
b76ddc
    
b76ddc
        infoAccArr[count] = current;
b76ddc
        ++count;
b76ddc
        
b76ddc
        PR_snprintf(buffer, sizeof(buffer), "Add another location to the %s"
b76ddc
                    " Information Access extension [y/N]",
b76ddc
                    (addSIAExt) ? "Subject" : "Authority");
b76ddc
b76ddc
        if (GetYesNo (buffer) == 0) {
b76ddc
            /* Add null to the end to mark end of data */
b76ddc
            infoAccArr = PORT_ArenaGrow(arena, infoAccArr,
b76ddc
                                         sizeof (current) * count,
b76ddc
                                         sizeof (current) *(count + 1));
b76ddc
            if (infoAccArr == NULL) {
b76ddc
                GEN_BREAK (SECFailure);
b76ddc
            }
b76ddc
            infoAccArr[count] = NULL;        
b76ddc
            break;
b76ddc
        }
b76ddc
b76ddc
    } while (1);
b76ddc
b76ddc
    if (rv == SECSuccess) {
b76ddc
        int oidIdent = SEC_OID_X509_AUTH_INFO_ACCESS;
b76ddc
b76ddc
        PRBool yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
b76ddc
        
b76ddc
        if (addSIAExt) {
b76ddc
            oidIdent = SEC_OID_X509_SUBJECT_INFO_ACCESS;
b76ddc
        }
b76ddc
        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, infoAccArr,
b76ddc
         yesNoAns, oidIdent,
b76ddc
         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeInfoAccessExtension);
b76ddc
    }
b76ddc
    if (arena)
b76ddc
        PORT_FreeArena(arena, PR_FALSE);
b76ddc
    return (rv);
b76ddc
}
b76ddc
b76ddc
SECStatus
b76ddc
AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
b76ddc
              certutilExtnList extList)
b76ddc
{
b76ddc
    SECStatus rv = SECSuccess;
b76ddc
    char *errstring = NULL;
b76ddc
    
b76ddc
    do {
b76ddc
        /* Add key usage extension */
b76ddc
        if (extList[ext_keyUsage]) {
b76ddc
            rv = AddKeyUsage(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "KeyUsage";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        /* Add extended key usage extension */
b76ddc
        if (extList[ext_extKeyUsage]) {
b76ddc
            rv = AddExtKeyUsage(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "ExtendedKeyUsage";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        /* Add basic constraint extension */
b76ddc
        if (extList[ext_basicConstraint]) {
b76ddc
            rv = AddBasicConstraint(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "BasicConstraint";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_authorityKeyID]) {
b76ddc
            rv = AddAuthKeyID(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "AuthorityKeyID";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_subjectKeyID]) {
b76ddc
            rv = AddSubjKeyID(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "SubjectKeyID";
b76ddc
                break;
b76ddc
            }
b76ddc
        }    
b76ddc
b76ddc
        if (extList[ext_CRLDistPts]) {
b76ddc
            rv = AddCrlDistPoint(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "CRLDistPoints";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_NSCertType]) {
b76ddc
            rv = AddNscpCertType(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "NSCertType";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_authInfoAcc] || extList[ext_subjInfoAcc]) {
b76ddc
            rv = AddInfoAccess(extHandle, extList[ext_subjInfoAcc],
b76ddc
                           extList[ext_basicConstraint]);
b76ddc
            if (rv) {
b76ddc
                errstring = "InformationAccess";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_certPolicies]) {
b76ddc
            rv = AddCertPolicies(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "Policies";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_policyMappings]) {
b76ddc
            rv = AddPolicyMappings(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "PolicyMappings";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_policyConstr]) {
b76ddc
            rv = AddPolicyConstraints(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "PolicyConstraints";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (extList[ext_inhibitAnyPolicy]) {
b76ddc
            rv = AddInhibitAnyPolicy(extHandle);
b76ddc
            if (rv) {
b76ddc
                errstring = "InhibitAnyPolicy";
b76ddc
                break;
b76ddc
            }
b76ddc
        }
b76ddc
b76ddc
        if (emailAddrs || dnsNames) {
b76ddc
            PRArenaPool *arena;
b76ddc
            CERTGeneralName *namelist = NULL;
b76ddc
            SECItem item = { 0, NULL, 0 };
b76ddc
            
b76ddc
            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
b76ddc
            if (arena == NULL) {
b76ddc
                rv = SECFailure;
b76ddc
                break;
b76ddc
            }
b76ddc
b76ddc
            rv = AddEmailSubjectAlt(arena, &namelist, emailAddrs);
b76ddc
b76ddc
            rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames);
b76ddc
b76ddc
            if (rv == SECSuccess) {
b76ddc
                rv = CERT_EncodeAltNameExtension(arena, namelist, &item);
b76ddc
            if (rv == SECSuccess) {
b76ddc
                    rv = CERT_AddExtension(extHandle,
b76ddc
                                          SEC_OID_X509_SUBJECT_ALT_NAME,
b76ddc
                                          &item, PR_FALSE, PR_TRUE);
b76ddc
        }
b76ddc
            }
b76ddc
        PORT_FreeArena(arena, PR_FALSE);
b76ddc
        if (rv) {
b76ddc
                errstring = "SubjectAltName";
b76ddc
                break;
b76ddc
        }
b76ddc
        }
b76ddc
    } while (0);
b76ddc
    
b76ddc
    if (rv != SECSuccess) {
b76ddc
        SECU_PrintError(progName, "Problem creating %s extension", errstring);
b76ddc
    }
b76ddc
    return rv;
b76ddc
}