tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

certext.c (73874B)


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