tor-browser

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

crlgen.c (47861B)


      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 ** crlgen.c
      7 **
      8 ** utility for managing certificates revocation lists generation
      9 **
     10 */
     11 
     12 #include <stdio.h>
     13 #include <math.h>
     14 
     15 #include "nspr.h"
     16 #include "plgetopt.h"
     17 #include "nss.h"
     18 #include "secutil.h"
     19 #include "cert.h"
     20 #include "certi.h"
     21 #include "certdb.h"
     22 #include "pk11func.h"
     23 #include "crlgen.h"
     24 
     25 /* Destroys extHandle and data. data was create on heap.
     26 * extHandle creaded by CERT_StartCRLEntryExtensions. entry
     27 * was allocated on arena.*/
     28 static void
     29 destroyEntryData(CRLGENEntryData *data)
     30 {
     31    if (!data)
     32        return;
     33    PORT_Assert(data->entry);
     34    if (data->extHandle)
     35        CERT_FinishExtensions(data->extHandle);
     36    PORT_Free(data);
     37 }
     38 
     39 /* Prints error messages along with line number */
     40 void
     41 crlgen_PrintError(int line, char *msg, ...)
     42 {
     43    va_list args;
     44 
     45    va_start(args, msg);
     46 
     47    fprintf(stderr, "crlgen: (line: %d) ", line);
     48    vfprintf(stderr, msg, args);
     49 
     50    va_end(args);
     51 }
     52 /* Finds CRLGENEntryData in hashtable according PRUint64 value
     53 * - certId : cert serial number*/
     54 static CRLGENEntryData *
     55 crlgen_FindEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
     56 {
     57    if (!crlGenData->entryDataHashTable || !certId)
     58        return NULL;
     59    return (CRLGENEntryData *)
     60        PL_HashTableLookup(crlGenData->entryDataHashTable,
     61                           certId);
     62 }
     63 
     64 /* Removes CRLGENEntryData from hashtable according to certId
     65 * - certId : cert serial number*/
     66 static SECStatus
     67 crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
     68 {
     69    CRLGENEntryData *data = NULL;
     70    SECStatus rv = SECSuccess;
     71 
     72    if (!crlGenData->entryDataHashTable) {
     73        return SECSuccess;
     74    }
     75 
     76    data = crlgen_FindEntry(crlGenData, certId);
     77    if (!data) {
     78        return SECSuccess;
     79    }
     80 
     81    if (!PL_HashTableRemove(crlGenData->entryDataHashTable, certId)) {
     82        rv = SECFailure;
     83    }
     84 
     85    destroyEntryData(data);
     86    return rv;
     87 }
     88 
     89 /* Stores CRLGENEntryData in hashtable according to certId
     90 * - certId : cert serial number*/
     91 static CRLGENEntryData *
     92 crlgen_PlaceAnEntry(CRLGENGeneratorData *crlGenData,
     93                    CERTCrlEntry *entry, SECItem *certId)
     94 {
     95    CRLGENEntryData *newData = NULL;
     96 
     97    PORT_Assert(crlGenData && crlGenData->entryDataHashTable &&
     98                entry);
     99    if (!crlGenData || !crlGenData->entryDataHashTable || !entry) {
    100        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    101        return NULL;
    102    }
    103 
    104    newData = PORT_ZNew(CRLGENEntryData);
    105    if (!newData) {
    106        return NULL;
    107    }
    108    newData->entry = entry;
    109    newData->certId = certId;
    110    if (!PL_HashTableAdd(crlGenData->entryDataHashTable,
    111                         newData->certId, newData)) {
    112        crlgen_PrintError(crlGenData->parsedLineNum,
    113                          "Can not add entryData structure\n");
    114        return NULL;
    115    }
    116    return newData;
    117 }
    118 
    119 /* Use this structure to keep pointer when commiting entries extensions */
    120 struct commitData {
    121    int pos;
    122    CERTCrlEntry **entries;
    123 };
    124 
    125 /* HT PL_HashTableEnumerateEntries callback. Sorts hashtable entries of the
    126 * table he. Returns value through arg parameter*/
    127 static PRIntn PR_CALLBACK
    128 crlgen_CommitEntryData(PLHashEntry *he, PRIntn i, void *arg)
    129 {
    130    CRLGENEntryData *data = NULL;
    131 
    132    PORT_Assert(he);
    133    if (!he) {
    134        return HT_ENUMERATE_NEXT;
    135    }
    136    data = (CRLGENEntryData *)he->value;
    137 
    138    PORT_Assert(data);
    139    PORT_Assert(arg);
    140 
    141    if (data) {
    142        struct commitData *dt = (struct commitData *)arg;
    143        dt->entries[dt->pos++] = data->entry;
    144        destroyEntryData(data);
    145    }
    146    return HT_ENUMERATE_NEXT;
    147 }
    148 
    149 /* Copy char * datainto allocated in arena SECItem */
    150 static SECStatus
    151 crlgen_SetString(PLArenaPool *arena, const char *dataIn, SECItem *value)
    152 {
    153    SECItem item;
    154 
    155    PORT_Assert(arena && dataIn);
    156    if (!arena || !dataIn) {
    157        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    158        return SECFailure;
    159    }
    160 
    161    item.data = (void *)dataIn;
    162    item.len = PORT_Strlen(dataIn);
    163 
    164    return SECITEM_CopyItem(arena, value, &item);
    165 }
    166 
    167 /* Creates CERTGeneralName from parsed data for the Authority Key Extension */
    168 static CERTGeneralName *
    169 crlgen_GetGeneralName(PLArenaPool *arena, CRLGENGeneratorData *crlGenData,
    170                      const char *data)
    171 {
    172    CERTGeneralName *namesList = NULL;
    173    CERTGeneralName *current;
    174    CERTGeneralName *tail = NULL;
    175    SECStatus rv = SECSuccess;
    176    const char *nextChunk = NULL;
    177    const char *currData = NULL;
    178    int intValue;
    179    char buffer[512];
    180    void *mark;
    181 
    182    if (!data)
    183        return NULL;
    184    PORT_Assert(arena);
    185    if (!arena) {
    186        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    187        return NULL;
    188    }
    189 
    190    mark = PORT_ArenaMark(arena);
    191 
    192    currData = data;
    193    do {
    194        int nameLen = 0;
    195        char name[128];
    196        const char *sepPrt = NULL;
    197        nextChunk = PORT_Strchr(currData, '|');
    198        if (!nextChunk)
    199            nextChunk = data + strlen(data);
    200        sepPrt = PORT_Strchr(currData, ':');
    201        if (sepPrt == NULL || sepPrt >= nextChunk) {
    202            *buffer = '\0';
    203            sepPrt = nextChunk;
    204        } else {
    205            PORT_Memcpy(buffer, sepPrt + 1,
    206                        (nextChunk - sepPrt - 1));
    207            buffer[nextChunk - sepPrt - 1] = '\0';
    208        }
    209        nameLen = PR_MIN(sepPrt - currData, sizeof(name) - 1);
    210        PORT_Memcpy(name, currData, nameLen);
    211        name[nameLen] = '\0';
    212        currData = nextChunk + 1;
    213 
    214        if (!PORT_Strcmp(name, "otherName"))
    215            intValue = certOtherName;
    216        else if (!PORT_Strcmp(name, "rfc822Name"))
    217            intValue = certRFC822Name;
    218        else if (!PORT_Strcmp(name, "dnsName"))
    219            intValue = certDNSName;
    220        else if (!PORT_Strcmp(name, "x400Address"))
    221            intValue = certX400Address;
    222        else if (!PORT_Strcmp(name, "directoryName"))
    223            intValue = certDirectoryName;
    224        else if (!PORT_Strcmp(name, "ediPartyName"))
    225            intValue = certEDIPartyName;
    226        else if (!PORT_Strcmp(name, "URI"))
    227            intValue = certURI;
    228        else if (!PORT_Strcmp(name, "ipAddress"))
    229            intValue = certIPAddress;
    230        else if (!PORT_Strcmp(name, "registerID"))
    231            intValue = certRegisterID;
    232        else
    233            intValue = -1;
    234 
    235        if (intValue >= certOtherName && intValue <= certRegisterID) {
    236            if (namesList == NULL) {
    237                namesList = current = tail = PORT_ArenaZNew(arena,
    238                                                            CERTGeneralName);
    239            } else {
    240                current = PORT_ArenaZNew(arena, CERTGeneralName);
    241            }
    242            if (current == NULL) {
    243                rv = SECFailure;
    244                break;
    245            }
    246        } else {
    247            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    248            break;
    249        }
    250        current->type = intValue;
    251        switch (current->type) {
    252            case certURI:
    253            case certDNSName:
    254            case certRFC822Name:
    255                current->name.other.data = PORT_ArenaAlloc(arena, strlen(buffer));
    256                if (current->name.other.data == NULL) {
    257                    rv = SECFailure;
    258                    break;
    259                }
    260                PORT_Memcpy(current->name.other.data, buffer,
    261                            current->name.other.len = strlen(buffer));
    262                break;
    263 
    264            case certEDIPartyName:
    265            case certIPAddress:
    266            case certOtherName:
    267            case certRegisterID:
    268            case certX400Address: {
    269 
    270                current->name.other.data = PORT_ArenaAlloc(arena, strlen(buffer) + 2);
    271                if (current->name.other.data == NULL) {
    272                    rv = SECFailure;
    273                    break;
    274                }
    275 
    276                PORT_Memcpy(current->name.other.data + 2, buffer, strlen(buffer));
    277                /* This may not be accurate for all cases.For now, use this tag type */
    278                current->name.other.data[0] = (char)(((current->type - 1) & 0x1f) | 0x80);
    279                current->name.other.data[1] = (char)strlen(buffer);
    280                current->name.other.len = strlen(buffer) + 2;
    281                break;
    282            }
    283 
    284            case certDirectoryName: {
    285                CERTName *directoryName = NULL;
    286 
    287                directoryName = CERT_AsciiToName(buffer);
    288                if (!directoryName) {
    289                    rv = SECFailure;
    290                    break;
    291                }
    292 
    293                rv = CERT_CopyName(arena, &current->name.directoryName, directoryName);
    294                CERT_DestroyName(directoryName);
    295 
    296                break;
    297            }
    298        }
    299        if (rv != SECSuccess)
    300            break;
    301        current->l.next = &(namesList->l);
    302        current->l.prev = &(tail->l);
    303        tail->l.next = &(current->l);
    304        tail = current;
    305 
    306    } while (nextChunk != data + strlen(data));
    307 
    308    if (rv != SECSuccess) {
    309        PORT_ArenaRelease(arena, mark);
    310        namesList = NULL;
    311    }
    312    return (namesList);
    313 }
    314 
    315 /* Creates CERTGeneralName from parsed data for the Authority Key Extension */
    316 static CERTGeneralName *
    317 crlgen_DistinguishedName(PLArenaPool *arena, CRLGENGeneratorData *crlGenData,
    318                         const char *data)
    319 {
    320    CERTName *directoryName = NULL;
    321    CERTGeneralName *current;
    322    SECStatus rv = SECFailure;
    323    void *mark;
    324 
    325    if (!data)
    326        return NULL;
    327    PORT_Assert(arena);
    328    if (!arena) {
    329        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    330        return NULL;
    331    }
    332 
    333    mark = PORT_ArenaMark(arena);
    334 
    335    current = PORT_ArenaZNew(arena, CERTGeneralName);
    336    if (current == NULL) {
    337        goto loser;
    338    }
    339    current->type = certDirectoryName;
    340    current->l.next = &current->l;
    341    current->l.prev = &current->l;
    342 
    343    directoryName = CERT_AsciiToName((char *)data);
    344    if (!directoryName) {
    345        goto loser;
    346    }
    347 
    348    rv = CERT_CopyName(arena, &current->name.directoryName, directoryName);
    349    CERT_DestroyName(directoryName);
    350 
    351 loser:
    352    if (rv != SECSuccess) {
    353        PORT_SetError(rv);
    354        PORT_ArenaRelease(arena, mark);
    355        current = NULL;
    356    }
    357    return (current);
    358 }
    359 
    360 /* Adding Authority Key ID extension to extension handle. */
    361 static SECStatus
    362 crlgen_AddAuthKeyID(CRLGENGeneratorData *crlGenData,
    363                    const char **dataArr)
    364 {
    365    void *extHandle = NULL;
    366    CERTAuthKeyID *authKeyID = NULL;
    367    PLArenaPool *arena = NULL;
    368    SECStatus rv = SECSuccess;
    369 
    370    PORT_Assert(dataArr && crlGenData);
    371    if (!crlGenData || !dataArr) {
    372        return SECFailure;
    373    }
    374 
    375    extHandle = crlGenData->crlExtHandle;
    376 
    377    if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
    378        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    379        crlgen_PrintError(crlGenData->parsedLineNum,
    380                          "insufficient number of parameters.\n");
    381        return SECFailure;
    382    }
    383 
    384    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    385    if (!arena) {
    386        return SECFailure;
    387    }
    388 
    389    authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID);
    390    if (authKeyID == NULL) {
    391        rv = SECFailure;
    392        goto loser;
    393    }
    394 
    395    if (dataArr[3] == NULL) {
    396        rv = crlgen_SetString(arena, dataArr[2], &authKeyID->keyID);
    397        if (rv != SECSuccess)
    398            goto loser;
    399    } else {
    400        rv = crlgen_SetString(arena, dataArr[3],
    401                              &authKeyID->authCertSerialNumber);
    402        if (rv != SECSuccess)
    403            goto loser;
    404 
    405        authKeyID->authCertIssuer =
    406            crlgen_DistinguishedName(arena, crlGenData, dataArr[2]);
    407        if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError()) {
    408            crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
    409            rv = SECFailure;
    410            goto loser;
    411        }
    412    }
    413 
    414    rv =
    415        SECU_EncodeAndAddExtensionValue(arena, extHandle, authKeyID,
    416                                        (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
    417                                        SEC_OID_X509_AUTH_KEY_ID,
    418                                        EXTEN_EXT_VALUE_ENCODER_CERT_EncodeAuthKeyID);
    419 loser:
    420    if (arena)
    421        PORT_FreeArena(arena, PR_FALSE);
    422    return rv;
    423 }
    424 
    425 /* Creates and add Subject Alternative Names extension */
    426 static SECStatus
    427 crlgen_AddIssuerAltNames(CRLGENGeneratorData *crlGenData,
    428                         const char **dataArr)
    429 {
    430    CERTGeneralName *nameList = NULL;
    431    PLArenaPool *arena = NULL;
    432    void *extHandle = NULL;
    433    SECStatus rv = SECSuccess;
    434 
    435    PORT_Assert(dataArr && crlGenData);
    436    if (!crlGenData || !dataArr) {
    437        return SECFailure;
    438    }
    439 
    440    if (!dataArr || !dataArr[0] || !dataArr[1] || !dataArr[2]) {
    441        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    442        crlgen_PrintError(crlGenData->parsedLineNum,
    443                          "insufficient number of arguments.\n");
    444        return SECFailure;
    445    }
    446 
    447    PORT_Assert(dataArr && crlGenData);
    448    if (!crlGenData || !dataArr) {
    449        return SECFailure;
    450    }
    451 
    452    extHandle = crlGenData->crlExtHandle;
    453 
    454    if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
    455        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    456        crlgen_PrintError(crlGenData->parsedLineNum,
    457                          "insufficient number of parameters.\n");
    458        return SECFailure;
    459    }
    460 
    461    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    462    if (!arena) {
    463        return SECFailure;
    464    }
    465 
    466    nameList = crlgen_GetGeneralName(arena, crlGenData, dataArr[2]);
    467    if (nameList == NULL) {
    468        crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
    469        rv = SECFailure;
    470        goto loser;
    471    }
    472 
    473    rv =
    474        SECU_EncodeAndAddExtensionValue(arena, extHandle, nameList,
    475                                        (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
    476                                        SEC_OID_X509_ISSUER_ALT_NAME,
    477                                        EXTEN_EXT_VALUE_ENCODER_CERT_EncodeAltNameExtension);
    478 loser:
    479    if (arena)
    480        PORT_FreeArena(arena, PR_FALSE);
    481    return rv;
    482 }
    483 
    484 /* Creates and adds CRLNumber extension to extension handle.
    485 * Since, this is CRL extension, extension handle is the one
    486 * related to CRL extensions */
    487 static SECStatus
    488 crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
    489 {
    490    PLArenaPool *arena = NULL;
    491    SECItem encodedItem;
    492    void *dummy;
    493    SECStatus rv = SECFailure;
    494    int code = 0;
    495 
    496    PORT_Assert(dataArr && crlGenData);
    497    if (!crlGenData || !dataArr) {
    498        goto loser;
    499    }
    500 
    501    if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
    502        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    503        crlgen_PrintError(crlGenData->parsedLineNum,
    504                          "insufficient number of arguments.\n");
    505        goto loser;
    506    }
    507 
    508    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    509    if (arena == NULL) {
    510        goto loser;
    511    }
    512 
    513    code = atoi(dataArr[2]);
    514    if (code == 0 && *dataArr[2] != '0') {
    515        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    516        goto loser;
    517    }
    518 
    519    dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
    520    if (!dummy) {
    521        rv = SECFailure;
    522        goto loser;
    523    }
    524 
    525    rv = CERT_AddExtension(crlGenData->crlExtHandle, SEC_OID_X509_CRL_NUMBER,
    526                           &encodedItem,
    527                           (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
    528                           PR_TRUE);
    529 
    530 loser:
    531    if (arena)
    532        PORT_FreeArena(arena, PR_FALSE);
    533    return rv;
    534 }
    535 
    536 /* Creates Cert Revocation Reason code extension. Encodes it and
    537 * returns as SECItem structure */
    538 static SECItem *
    539 crlgen_CreateReasonCode(PLArenaPool *arena, const char **dataArr,
    540                        int *extCode)
    541 {
    542    SECItem *encodedItem;
    543    void *dummy;
    544    void *mark = NULL;
    545    int code = 0;
    546 
    547    PORT_Assert(arena && dataArr);
    548    if (!arena || !dataArr) {
    549        goto loser;
    550    }
    551 
    552    mark = PORT_ArenaMark(arena);
    553 
    554    encodedItem = PORT_ArenaZNew(arena, SECItem);
    555    if (encodedItem == NULL) {
    556        goto loser;
    557    }
    558 
    559    if (dataArr[2] == NULL) {
    560        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    561        goto loser;
    562    }
    563 
    564    code = atoi(dataArr[2]);
    565    /* aACompromise(10) is the last possible of the values
    566     * for the Reason Core Extension */
    567    if ((code == 0 && *dataArr[2] != '0') || code > 10) {
    568 
    569        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    570        goto loser;
    571    }
    572 
    573    dummy = SEC_ASN1EncodeInteger(arena, encodedItem, code);
    574    if (!dummy) {
    575        goto loser;
    576    }
    577 
    578    *extCode = SEC_OID_X509_REASON_CODE;
    579    return encodedItem;
    580 
    581 loser:
    582    if (mark) {
    583        PORT_ArenaRelease(arena, mark);
    584    }
    585    return NULL;
    586 }
    587 
    588 /* Creates Cert Invalidity Date extension. Encodes it and
    589 * returns as SECItem structure */
    590 static SECItem *
    591 crlgen_CreateInvalidityDate(PLArenaPool *arena, const char **dataArr,
    592                            int *extCode)
    593 {
    594    SECItem *encodedItem;
    595    int length = 0;
    596    void *mark = NULL;
    597 
    598    PORT_Assert(arena && dataArr);
    599    if (!arena || !dataArr) {
    600        goto loser;
    601    }
    602 
    603    mark = PORT_ArenaMark(arena);
    604 
    605    encodedItem = PORT_ArenaZNew(arena, SECItem);
    606    if (encodedItem == NULL) {
    607        goto loser;
    608    }
    609 
    610    length = PORT_Strlen(dataArr[2]);
    611 
    612    encodedItem->type = siGeneralizedTime;
    613    encodedItem->data = PORT_ArenaAlloc(arena, length);
    614    if (!encodedItem->data) {
    615        goto loser;
    616    }
    617 
    618    PORT_Memcpy(encodedItem->data, dataArr[2], (encodedItem->len = length) * sizeof(char));
    619 
    620    *extCode = SEC_OID_X509_INVALID_DATE;
    621    return encodedItem;
    622 
    623 loser:
    624    if (mark) {
    625        PORT_ArenaRelease(arena, mark);
    626    }
    627    return NULL;
    628 }
    629 
    630 /* Creates(by calling extCreator function) and adds extension to a set
    631 * of already added certs. Uses values of rangeFrom and rangeTo from
    632 * CRLGENCrlGenCtl structure for identifying the inclusive set of certs */
    633 static SECStatus
    634 crlgen_AddEntryExtension(CRLGENGeneratorData *crlGenData,
    635                         const char **dataArr, char *extName,
    636                         SECItem *(*extCreator)(PLArenaPool *arena,
    637                                                const char **dataArr,
    638                                                int *extCode))
    639 {
    640    PRUint64 i = 0;
    641    SECStatus rv = SECFailure;
    642    int extCode = 0;
    643    PRUint64 lastRange;
    644    SECItem *ext = NULL;
    645    PLArenaPool *arena = NULL;
    646 
    647    PORT_Assert(crlGenData && dataArr);
    648    if (!crlGenData || !dataArr) {
    649        goto loser;
    650    }
    651 
    652    if (!dataArr[0] || !dataArr[1]) {
    653        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    654        crlgen_PrintError(crlGenData->parsedLineNum,
    655                          "insufficient number of arguments.\n");
    656    }
    657 
    658    lastRange = crlGenData->rangeTo - crlGenData->rangeFrom + 1;
    659 
    660    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    661    if (arena == NULL) {
    662        goto loser;
    663    }
    664 
    665    ext = extCreator(arena, dataArr, &extCode);
    666    if (ext == NULL) {
    667        crlgen_PrintError(crlGenData->parsedLineNum,
    668                          "got error while creating extension: %s\n",
    669                          extName);
    670        goto loser;
    671    }
    672 
    673    for (i = 0; i < lastRange; i++) {
    674        CRLGENEntryData *extData = NULL;
    675        void *extHandle = NULL;
    676        SECItem *certIdItem =
    677            SEC_ASN1EncodeInteger(arena, NULL,
    678                                  crlGenData->rangeFrom + i);
    679        if (!certIdItem) {
    680            rv = SECFailure;
    681            goto loser;
    682        }
    683 
    684        extData = crlgen_FindEntry(crlGenData, certIdItem);
    685        if (!extData) {
    686            crlgen_PrintError(crlGenData->parsedLineNum,
    687                              "can not add extension: crl entry "
    688                              "(serial number: %d) is not in the list yet.\n",
    689                              crlGenData->rangeFrom + i);
    690            continue;
    691        }
    692 
    693        extHandle = extData->extHandle;
    694        if (extHandle == NULL) {
    695            extHandle = extData->extHandle =
    696                CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
    697                                             (CERTCrlEntry *)extData->entry);
    698        }
    699        rv = CERT_AddExtension(extHandle, extCode, ext,
    700                               (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
    701                               PR_TRUE);
    702        if (rv == SECFailure) {
    703            goto loser;
    704        }
    705    }
    706 
    707 loser:
    708    if (arena)
    709        PORT_FreeArena(arena, PR_FALSE);
    710    return rv;
    711 }
    712 
    713 /* Commits all added entries and their's extensions into CRL. */
    714 SECStatus
    715 CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData *crlGenData)
    716 {
    717    int size = 0;
    718    CERTCrl *crl;
    719    PLArenaPool *arena;
    720    SECStatus rv = SECSuccess;
    721    void *mark;
    722 
    723    PORT_Assert(crlGenData && crlGenData->signCrl && crlGenData->signCrl->arena);
    724    if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
    725        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    726        return SECFailure;
    727    }
    728 
    729    arena = crlGenData->signCrl->arena;
    730    crl = &crlGenData->signCrl->crl;
    731 
    732    mark = PORT_ArenaMark(arena);
    733 
    734    if (crlGenData->crlExtHandle)
    735        CERT_FinishExtensions(crlGenData->crlExtHandle);
    736 
    737    size = crlGenData->entryDataHashTable->nentries;
    738    crl->entries = NULL;
    739    if (size) {
    740        crl->entries = PORT_ArenaZNewArray(arena, CERTCrlEntry *, size + 1);
    741        if (!crl->entries) {
    742            rv = SECFailure;
    743        } else {
    744            struct commitData dt;
    745            dt.entries = crl->entries;
    746            dt.pos = 0;
    747            PL_HashTableEnumerateEntries(crlGenData->entryDataHashTable,
    748                                         &crlgen_CommitEntryData, &dt);
    749            /* Last should be NULL */
    750            crl->entries[size] = NULL;
    751        }
    752    }
    753 
    754    if (rv != SECSuccess)
    755        PORT_ArenaRelease(arena, mark);
    756    return rv;
    757 }
    758 
    759 /* Initializes extHandle with data from extensions array */
    760 static SECStatus
    761 crlgen_InitExtensionHandle(void *extHandle,
    762                           CERTCertExtension **extensions)
    763 {
    764    CERTCertExtension *extension = NULL;
    765 
    766    if (!extensions)
    767        return SECSuccess;
    768 
    769    PORT_Assert(extHandle != NULL);
    770    if (!extHandle) {
    771        return SECFailure;
    772    }
    773 
    774    extension = *extensions;
    775    while (extension) {
    776        SECOidTag oidTag = SECOID_FindOIDTag(&extension->id);
    777        /* shell we skip unknown extensions? */
    778        CERT_AddExtension(extHandle, oidTag, &extension->value,
    779                          (extension->critical.len != 0) ? PR_TRUE : PR_FALSE,
    780                          PR_FALSE);
    781        extension = *(++extensions);
    782    }
    783    return SECSuccess;
    784 }
    785 
    786 /* Used for initialization of extension handles for crl and certs
    787 * extensions from existing CRL data then modifying existing CRL.*/
    788 SECStatus
    789 CRLGEN_ExtHandleInit(CRLGENGeneratorData *crlGenData)
    790 {
    791    CERTCrl *crl = NULL;
    792    PRUint64 maxSN = 0;
    793 
    794    PORT_Assert(crlGenData && crlGenData->signCrl &&
    795                crlGenData->entryDataHashTable);
    796    if (!crlGenData || !crlGenData->signCrl ||
    797        !crlGenData->entryDataHashTable) {
    798        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    799        return SECFailure;
    800    }
    801 
    802    crl = &crlGenData->signCrl->crl;
    803    crlGenData->crlExtHandle = CERT_StartCRLExtensions(crl);
    804    crlgen_InitExtensionHandle(crlGenData->crlExtHandle,
    805                               crl->extensions);
    806    crl->extensions = NULL;
    807 
    808    if (crl->entries) {
    809        CERTCrlEntry **entry = crl->entries;
    810        while (*entry) {
    811            PRUint64 sn = DER_GetInteger(&(*entry)->serialNumber);
    812            CRLGENEntryData *extData =
    813                crlgen_PlaceAnEntry(crlGenData, *entry, &(*entry)->serialNumber);
    814            if ((*entry)->extensions) {
    815                extData->extHandle =
    816                    CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
    817                                                 (CERTCrlEntry *)extData->entry);
    818                if (crlgen_InitExtensionHandle(extData->extHandle,
    819                                               (*entry)->extensions) == SECFailure)
    820                    return SECFailure;
    821            }
    822            (*entry)->extensions = NULL;
    823            entry++;
    824            maxSN = PR_MAX(maxSN, sn);
    825        }
    826    }
    827 
    828    crlGenData->rangeFrom = crlGenData->rangeTo = maxSN + 1;
    829    return SECSuccess;
    830 }
    831 
    832 /*****************************************************************************
    833 * Parser trigger functions start here
    834 */
    835 
    836 /* Sets new internal range value for add/rm certs.*/
    837 static SECStatus
    838 crlgen_SetNewRangeField(CRLGENGeneratorData *crlGenData, char *value)
    839 {
    840    long rangeFrom = 0, rangeTo = 0;
    841    char *dashPos = NULL;
    842 
    843    PORT_Assert(crlGenData);
    844    if (!crlGenData) {
    845        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    846        return SECFailure;
    847    }
    848 
    849    if (value == NULL) {
    850        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    851        crlgen_PrintError(crlGenData->parsedLineNum,
    852                          "insufficient number of arguments.\n");
    853        return SECFailure;
    854    }
    855 
    856    if ((dashPos = strchr(value, '-')) != NULL) {
    857        char *rangeToS, *rangeFromS = value;
    858        *dashPos = '\0';
    859        rangeFrom = atoi(rangeFromS);
    860        *dashPos = '-';
    861 
    862        rangeToS = (char *)(dashPos + 1);
    863        rangeTo = atol(rangeToS);
    864    } else {
    865        rangeFrom = atol(value);
    866        rangeTo = rangeFrom;
    867    }
    868 
    869    if (rangeFrom < 1 || rangeTo < rangeFrom) {
    870        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    871        crlgen_PrintError(crlGenData->parsedLineNum,
    872                          "bad cert id range: %s.\n", value);
    873        return SECFailure;
    874    }
    875 
    876    crlGenData->rangeFrom = rangeFrom;
    877    crlGenData->rangeTo = rangeTo;
    878 
    879    return SECSuccess;
    880 }
    881 
    882 /* Changes issuer subject field in CRL. By default this data is taken from
    883 * issuer cert subject field.Not yet implemented */
    884 static SECStatus
    885 crlgen_SetIssuerField(CRLGENGeneratorData *crlGenData, char *value)
    886 {
    887    crlgen_PrintError(crlGenData->parsedLineNum,
    888                      "Can not change CRL issuer field.\n");
    889    return SECFailure;
    890 }
    891 
    892 /* Encode and sets CRL thisUpdate and nextUpdate time fields*/
    893 static SECStatus
    894 crlgen_SetTimeField(CRLGENGeneratorData *crlGenData, char *value,
    895                    PRBool setThisUpdate)
    896 {
    897    CERTSignedCrl *signCrl;
    898    PLArenaPool *arena;
    899    CERTCrl *crl;
    900    int length = 0;
    901    SECItem *timeDest = NULL;
    902 
    903    PORT_Assert(crlGenData && crlGenData->signCrl &&
    904                crlGenData->signCrl->arena);
    905    if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
    906        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    907        return SECFailure;
    908    }
    909 
    910    signCrl = crlGenData->signCrl;
    911    arena = signCrl->arena;
    912    crl = &signCrl->crl;
    913 
    914    if (value == NULL) {
    915        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    916        crlgen_PrintError(crlGenData->parsedLineNum,
    917                          "insufficient number of arguments.\n");
    918        return SECFailure;
    919    }
    920    length = PORT_Strlen(value);
    921 
    922    if (setThisUpdate == PR_TRUE) {
    923        timeDest = &crl->lastUpdate;
    924    } else {
    925        timeDest = &crl->nextUpdate;
    926    }
    927 
    928    timeDest->type = siGeneralizedTime;
    929    timeDest->data = PORT_ArenaAlloc(arena, length);
    930    if (!timeDest->data) {
    931        return SECFailure;
    932    }
    933    PORT_Memcpy(timeDest->data, value, length);
    934    timeDest->len = length;
    935 
    936    return SECSuccess;
    937 }
    938 
    939 /* Adds new extension into CRL or added cert handles */
    940 static SECStatus
    941 crlgen_AddExtension(CRLGENGeneratorData *crlGenData, const char **extData)
    942 {
    943    PORT_Assert(crlGenData && crlGenData->crlExtHandle);
    944    if (!crlGenData || !crlGenData->crlExtHandle) {
    945        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    946        return SECFailure;
    947    }
    948 
    949    if (extData == NULL || *extData == NULL) {
    950        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    951        crlgen_PrintError(crlGenData->parsedLineNum,
    952                          "insufficient number of arguments.\n");
    953        return SECFailure;
    954    }
    955    if (!PORT_Strcmp(*extData, "authKeyId"))
    956        return crlgen_AddAuthKeyID(crlGenData, extData);
    957    else if (!PORT_Strcmp(*extData, "issuerAltNames"))
    958        return crlgen_AddIssuerAltNames(crlGenData, extData);
    959    else if (!PORT_Strcmp(*extData, "crlNumber"))
    960        return crlgen_AddCrlNumber(crlGenData, extData);
    961    else if (!PORT_Strcmp(*extData, "reasonCode"))
    962        return crlgen_AddEntryExtension(crlGenData, extData, "reasonCode",
    963                                        crlgen_CreateReasonCode);
    964    else if (!PORT_Strcmp(*extData, "invalidityDate"))
    965        return crlgen_AddEntryExtension(crlGenData, extData, "invalidityDate",
    966                                        crlgen_CreateInvalidityDate);
    967    else {
    968        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    969        crlgen_PrintError(crlGenData->parsedLineNum,
    970                          "insufficient number of arguments.\n");
    971        return SECFailure;
    972    }
    973 }
    974 
    975 /* Created CRLGENEntryData for cert with serial number certId and
    976 * adds it to entryDataHashTable. certId can be a single cert serial
    977 * number or an inclusive rage of certs */
    978 static SECStatus
    979 crlgen_AddCert(CRLGENGeneratorData *crlGenData,
    980               char *certId, char *revocationDate)
    981 {
    982    CERTSignedCrl *signCrl;
    983    SECItem *certIdItem;
    984    PLArenaPool *arena;
    985    PRUint64 rangeFrom = 0, rangeTo = 0, i = 0;
    986    int timeValLength = -1;
    987    SECStatus rv = SECFailure;
    988    void *mark;
    989 
    990    PORT_Assert(crlGenData && crlGenData->signCrl &&
    991                crlGenData->signCrl->arena);
    992    if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
    993        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    994        return SECFailure;
    995    }
    996 
    997    signCrl = crlGenData->signCrl;
    998    arena = signCrl->arena;
    999 
   1000    if (!certId || !revocationDate) {
   1001        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1002        crlgen_PrintError(crlGenData->parsedLineNum,
   1003                          "insufficient number of arguments.\n");
   1004        return SECFailure;
   1005    }
   1006 
   1007    timeValLength = strlen(revocationDate);
   1008 
   1009    if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
   1010        certId) {
   1011        return SECFailure;
   1012    }
   1013    rangeFrom = crlGenData->rangeFrom;
   1014    rangeTo = crlGenData->rangeTo;
   1015 
   1016    for (i = 0; i < rangeTo - rangeFrom + 1; i++) {
   1017        CERTCrlEntry *entry;
   1018        mark = PORT_ArenaMark(arena);
   1019        entry = PORT_ArenaZNew(arena, CERTCrlEntry);
   1020        if (entry == NULL) {
   1021            goto loser;
   1022        }
   1023 
   1024        certIdItem = SEC_ASN1EncodeInteger(arena, &entry->serialNumber,
   1025                                           rangeFrom + i);
   1026        if (!certIdItem) {
   1027            goto loser;
   1028        }
   1029 
   1030        if (crlgen_FindEntry(crlGenData, certIdItem)) {
   1031            crlgen_PrintError(crlGenData->parsedLineNum,
   1032                              "entry already exists. Use \"range\" "
   1033                              "and \"rmcert\" before adding a new one with the "
   1034                              "same serial number %ld\n",
   1035                              rangeFrom + i);
   1036            goto loser;
   1037        }
   1038 
   1039        entry->serialNumber.type = siBuffer;
   1040 
   1041        entry->revocationDate.type = siGeneralizedTime;
   1042 
   1043        entry->revocationDate.data =
   1044            PORT_ArenaAlloc(arena, timeValLength);
   1045        if (entry->revocationDate.data == NULL) {
   1046            goto loser;
   1047        }
   1048 
   1049        PORT_Memcpy(entry->revocationDate.data, revocationDate,
   1050                    timeValLength * sizeof(char));
   1051        entry->revocationDate.len = timeValLength;
   1052 
   1053        entry->extensions = NULL;
   1054        if (!crlgen_PlaceAnEntry(crlGenData, entry, certIdItem)) {
   1055            goto loser;
   1056        }
   1057        mark = NULL;
   1058    }
   1059 
   1060    rv = SECSuccess;
   1061 loser:
   1062    if (mark) {
   1063        PORT_ArenaRelease(arena, mark);
   1064    }
   1065    return rv;
   1066 }
   1067 
   1068 /* Removes certs from entryDataHashTable which have certId serial number.
   1069 * certId can have value of a range of certs */
   1070 static SECStatus
   1071 crlgen_RmCert(CRLGENGeneratorData *crlGenData, char *certId)
   1072 {
   1073    PRUint64 i = 0;
   1074 
   1075    PORT_Assert(crlGenData && certId);
   1076    if (!crlGenData || !certId) {
   1077        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1078        return SECFailure;
   1079    }
   1080 
   1081    if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
   1082        certId) {
   1083        return SECFailure;
   1084    }
   1085 
   1086    for (i = 0; i < crlGenData->rangeTo - crlGenData->rangeFrom + 1; i++) {
   1087        SECItem *certIdItem = SEC_ASN1EncodeInteger(NULL, NULL,
   1088                                                    crlGenData->rangeFrom + i);
   1089        if (certIdItem) {
   1090            CRLGENEntryData *extData =
   1091                crlgen_FindEntry(crlGenData, certIdItem);
   1092            if (!extData) {
   1093                printf("Cert with id %s is not in the list\n", certId);
   1094            } else {
   1095                crlgen_RmEntry(crlGenData, certIdItem);
   1096            }
   1097            SECITEM_FreeItem(certIdItem, PR_TRUE);
   1098        }
   1099    }
   1100 
   1101    return SECSuccess;
   1102 }
   1103 
   1104 /*************************************************************************
   1105 * Lex Parser Helper functions are used to store parsed information
   1106 * in context related structures. Context(or state) is identified base on
   1107 * a type of a instruction parser currently is going through. New context
   1108 * is identified by first token in a line. It can be addcert context,
   1109 * addext context, etc. */
   1110 
   1111 /* Updates CRL field depending on current context */
   1112 static SECStatus
   1113 crlgen_updateCrlFn_field(CRLGENGeneratorData *crlGenData, void *str)
   1114 {
   1115    CRLGENCrlField *fieldStr = (CRLGENCrlField *)str;
   1116 
   1117    PORT_Assert(crlGenData);
   1118    if (!crlGenData) {
   1119        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1120        return SECFailure;
   1121    }
   1122 
   1123    switch (crlGenData->contextId) {
   1124        case CRLGEN_ISSUER_CONTEXT:
   1125            crlgen_SetIssuerField(crlGenData, fieldStr->value);
   1126            break;
   1127        case CRLGEN_UPDATE_CONTEXT:
   1128            return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_TRUE);
   1129            break;
   1130        case CRLGEN_NEXT_UPDATE_CONTEXT:
   1131            return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_FALSE);
   1132            break;
   1133        case CRLGEN_CHANGE_RANGE_CONTEXT:
   1134            return crlgen_SetNewRangeField(crlGenData, fieldStr->value);
   1135            break;
   1136        default:
   1137            crlgen_PrintError(crlGenData->parsedLineNum,
   1138                              "syntax error (unknow token type: %d)\n",
   1139                              crlGenData->contextId);
   1140            PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1141            return SECFailure;
   1142    }
   1143    return SECSuccess;
   1144 }
   1145 
   1146 /* Sets parsed data for CRL field update into temporary structure */
   1147 static SECStatus
   1148 crlgen_setNextDataFn_field(CRLGENGeneratorData *crlGenData, void *str,
   1149                           void *data, unsigned short dtype)
   1150 {
   1151    CRLGENCrlField *fieldStr = (CRLGENCrlField *)str;
   1152 
   1153    PORT_Assert(crlGenData);
   1154    if (!crlGenData) {
   1155        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1156        return SECFailure;
   1157    }
   1158 
   1159    switch (crlGenData->contextId) {
   1160        case CRLGEN_CHANGE_RANGE_CONTEXT:
   1161            if (dtype != CRLGEN_TYPE_DIGIT && dtype != CRLGEN_TYPE_DIGIT_RANGE) {
   1162                crlgen_PrintError(crlGenData->parsedLineNum,
   1163                                  "range value should have "
   1164                                  "numeric or numeric range values.\n");
   1165                return SECFailure;
   1166            }
   1167            break;
   1168        case CRLGEN_NEXT_UPDATE_CONTEXT:
   1169        case CRLGEN_UPDATE_CONTEXT:
   1170            if (dtype != CRLGEN_TYPE_ZDATE) {
   1171                crlgen_PrintError(crlGenData->parsedLineNum,
   1172                                  "bad formated date. Should be "
   1173                                  "YYYYMMDDHHMMSSZ.\n");
   1174                return SECFailure;
   1175            }
   1176            break;
   1177        default:
   1178            PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1179            crlgen_PrintError(crlGenData->parsedLineNum,
   1180                              "syntax error (unknow token type: %d).\n",
   1181                              crlGenData->contextId, data);
   1182            return SECFailure;
   1183    }
   1184    fieldStr->value = PORT_Strdup(data);
   1185    if (!fieldStr->value) {
   1186        return SECFailure;
   1187    }
   1188    return SECSuccess;
   1189 }
   1190 
   1191 /* Triggers cert entries update depending on current context */
   1192 static SECStatus
   1193 crlgen_updateCrlFn_cert(CRLGENGeneratorData *crlGenData, void *str)
   1194 {
   1195    CRLGENCertEntry *certStr = (CRLGENCertEntry *)str;
   1196 
   1197    PORT_Assert(crlGenData);
   1198    if (!crlGenData) {
   1199        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1200        return SECFailure;
   1201    }
   1202 
   1203    switch (crlGenData->contextId) {
   1204        case CRLGEN_ADD_CERT_CONTEXT:
   1205            return crlgen_AddCert(crlGenData, certStr->certId,
   1206                                  certStr->revocationTime);
   1207        case CRLGEN_RM_CERT_CONTEXT:
   1208            return crlgen_RmCert(crlGenData, certStr->certId);
   1209        default:
   1210            PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1211            crlgen_PrintError(crlGenData->parsedLineNum,
   1212                              "syntax error (unknow token type: %d).\n",
   1213                              crlGenData->contextId);
   1214            return SECFailure;
   1215    }
   1216 }
   1217 
   1218 /* Sets parsed data for CRL entries update into temporary structure */
   1219 static SECStatus
   1220 crlgen_setNextDataFn_cert(CRLGENGeneratorData *crlGenData, void *str,
   1221                          void *data, unsigned short dtype)
   1222 {
   1223    CRLGENCertEntry *certStr = (CRLGENCertEntry *)str;
   1224 
   1225    PORT_Assert(crlGenData);
   1226    if (!crlGenData) {
   1227        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1228        return SECFailure;
   1229    }
   1230 
   1231    switch (dtype) {
   1232        case CRLGEN_TYPE_DIGIT:
   1233        case CRLGEN_TYPE_DIGIT_RANGE:
   1234            certStr->certId = PORT_Strdup(data);
   1235            if (!certStr->certId) {
   1236                return SECFailure;
   1237            }
   1238            break;
   1239        case CRLGEN_TYPE_DATE:
   1240        case CRLGEN_TYPE_ZDATE:
   1241            certStr->revocationTime = PORT_Strdup(data);
   1242            if (!certStr->revocationTime) {
   1243                return SECFailure;
   1244            }
   1245            break;
   1246        default:
   1247            PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1248            crlgen_PrintError(crlGenData->parsedLineNum,
   1249                              "syntax error (unknow token type: %d).\n",
   1250                              crlGenData->contextId);
   1251            return SECFailure;
   1252    }
   1253    return SECSuccess;
   1254 }
   1255 
   1256 /* Triggers cert entries/crl extension update */
   1257 static SECStatus
   1258 crlgen_updateCrlFn_extension(CRLGENGeneratorData *crlGenData, void *str)
   1259 {
   1260    CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry *)str;
   1261 
   1262    return crlgen_AddExtension(crlGenData, (const char **)extStr->extData);
   1263 }
   1264 
   1265 /* Defines maximum number of fields extension may have */
   1266 #define MAX_EXT_DATA_LENGTH 10
   1267 
   1268 /* Sets parsed extension data for CRL entries/CRL extensions update
   1269 * into temporary structure */
   1270 static SECStatus
   1271 crlgen_setNextDataFn_extension(CRLGENGeneratorData *crlGenData, void *str,
   1272                               void *data, unsigned short dtype)
   1273 {
   1274    CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry *)str;
   1275 
   1276    PORT_Assert(crlGenData);
   1277    if (!crlGenData) {
   1278        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1279        return SECFailure;
   1280    }
   1281 
   1282    if (extStr->extData == NULL) {
   1283        extStr->extData = PORT_ZNewArray(char *, MAX_EXT_DATA_LENGTH);
   1284        if (!extStr->extData) {
   1285            return SECFailure;
   1286        }
   1287    }
   1288    if (extStr->nextUpdatedData >= MAX_EXT_DATA_LENGTH) {
   1289        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1290        crlgen_PrintError(crlGenData->parsedLineNum,
   1291                          "number of fields in extension "
   1292                          "exceeded maximum allowed data length: %d.\n",
   1293                          MAX_EXT_DATA_LENGTH);
   1294        return SECFailure;
   1295    }
   1296    extStr->extData[extStr->nextUpdatedData] = PORT_Strdup(data);
   1297    if (!extStr->extData[extStr->nextUpdatedData]) {
   1298        return SECFailure;
   1299    }
   1300    extStr->nextUpdatedData += 1;
   1301 
   1302    return SECSuccess;
   1303 }
   1304 
   1305 /****************************************************************************************
   1306 * Top level functions are triggered directly by parser.
   1307 */
   1308 
   1309 /*
   1310 * crl generation script parser recreates a temporary data staructure
   1311 * for each line it is going through. This function cleans temp structure.
   1312 */
   1313 void
   1314 crlgen_destroyTempData(CRLGENGeneratorData *crlGenData)
   1315 {
   1316    if (crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
   1317        switch (crlGenData->contextId) {
   1318            case CRLGEN_ISSUER_CONTEXT:
   1319            case CRLGEN_UPDATE_CONTEXT:
   1320            case CRLGEN_NEXT_UPDATE_CONTEXT:
   1321            case CRLGEN_CHANGE_RANGE_CONTEXT:
   1322                if (crlGenData->crlField->value)
   1323                    PORT_Free(crlGenData->crlField->value);
   1324                PORT_Free(crlGenData->crlField);
   1325                break;
   1326            case CRLGEN_ADD_CERT_CONTEXT:
   1327            case CRLGEN_RM_CERT_CONTEXT:
   1328                if (crlGenData->certEntry->certId)
   1329                    PORT_Free(crlGenData->certEntry->certId);
   1330                if (crlGenData->certEntry->revocationTime)
   1331                    PORT_Free(crlGenData->certEntry->revocationTime);
   1332                PORT_Free(crlGenData->certEntry);
   1333                break;
   1334            case CRLGEN_ADD_EXTENSION_CONTEXT:
   1335                if (crlGenData->extensionEntry->extData) {
   1336                    int i = 0;
   1337                    for (; i < crlGenData->extensionEntry->nextUpdatedData; i++)
   1338                        PORT_Free(*(crlGenData->extensionEntry->extData + i));
   1339                    PORT_Free(crlGenData->extensionEntry->extData);
   1340                }
   1341                PORT_Free(crlGenData->extensionEntry);
   1342                break;
   1343        }
   1344        crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
   1345    }
   1346 }
   1347 
   1348 SECStatus
   1349 crlgen_updateCrl(CRLGENGeneratorData *crlGenData)
   1350 {
   1351    SECStatus rv = SECSuccess;
   1352 
   1353    PORT_Assert(crlGenData);
   1354    if (!crlGenData) {
   1355        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1356        return SECFailure;
   1357    }
   1358 
   1359    switch (crlGenData->contextId) {
   1360        case CRLGEN_ISSUER_CONTEXT:
   1361        case CRLGEN_UPDATE_CONTEXT:
   1362        case CRLGEN_NEXT_UPDATE_CONTEXT:
   1363        case CRLGEN_CHANGE_RANGE_CONTEXT:
   1364            rv = crlGenData->crlField->updateCrlFn(crlGenData, crlGenData->crlField);
   1365            break;
   1366        case CRLGEN_RM_CERT_CONTEXT:
   1367        case CRLGEN_ADD_CERT_CONTEXT:
   1368            rv = crlGenData->certEntry->updateCrlFn(crlGenData, crlGenData->certEntry);
   1369            break;
   1370        case CRLGEN_ADD_EXTENSION_CONTEXT:
   1371            rv = crlGenData->extensionEntry->updateCrlFn(crlGenData, crlGenData->extensionEntry);
   1372            break;
   1373        case CRLGEN_UNKNOWN_CONTEXT:
   1374            break;
   1375        default:
   1376            crlgen_PrintError(crlGenData->parsedLineNum,
   1377                              "unknown lang context type code: %d.\n",
   1378                              crlGenData->contextId);
   1379            PORT_Assert(0);
   1380            return SECFailure;
   1381    }
   1382    /* Clrean structures after crl update */
   1383    crlgen_destroyTempData(crlGenData);
   1384 
   1385    crlGenData->parsedLineNum += 1;
   1386 
   1387    return rv;
   1388 }
   1389 
   1390 SECStatus
   1391 crlgen_setNextData(CRLGENGeneratorData *crlGenData, void *data,
   1392                   unsigned short dtype)
   1393 {
   1394    SECStatus rv = SECSuccess;
   1395 
   1396    PORT_Assert(crlGenData);
   1397    if (!crlGenData) {
   1398        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1399        return SECFailure;
   1400    }
   1401 
   1402    switch (crlGenData->contextId) {
   1403        case CRLGEN_ISSUER_CONTEXT:
   1404        case CRLGEN_UPDATE_CONTEXT:
   1405        case CRLGEN_NEXT_UPDATE_CONTEXT:
   1406        case CRLGEN_CHANGE_RANGE_CONTEXT:
   1407            rv = crlGenData->crlField->setNextDataFn(crlGenData, crlGenData->crlField,
   1408                                                     data, dtype);
   1409            break;
   1410        case CRLGEN_ADD_CERT_CONTEXT:
   1411        case CRLGEN_RM_CERT_CONTEXT:
   1412            rv = crlGenData->certEntry->setNextDataFn(crlGenData, crlGenData->certEntry,
   1413                                                      data, dtype);
   1414            break;
   1415        case CRLGEN_ADD_EXTENSION_CONTEXT:
   1416            rv =
   1417                crlGenData->extensionEntry->setNextDataFn(crlGenData, crlGenData->extensionEntry, data, dtype);
   1418            break;
   1419        case CRLGEN_UNKNOWN_CONTEXT:
   1420            break;
   1421        default:
   1422            crlgen_PrintError(crlGenData->parsedLineNum,
   1423                              "unknown context type: %d.\n",
   1424                              crlGenData->contextId);
   1425            PORT_Assert(0);
   1426            return SECFailure;
   1427    }
   1428    return rv;
   1429 }
   1430 
   1431 SECStatus
   1432 crlgen_createNewLangStruct(CRLGENGeneratorData *crlGenData,
   1433                           unsigned structType)
   1434 {
   1435    PORT_Assert(crlGenData &&
   1436                crlGenData->contextId == CRLGEN_UNKNOWN_CONTEXT);
   1437    if (!crlGenData ||
   1438        crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
   1439        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1440        return SECFailure;
   1441    }
   1442 
   1443    switch (structType) {
   1444        case CRLGEN_ISSUER_CONTEXT:
   1445        case CRLGEN_UPDATE_CONTEXT:
   1446        case CRLGEN_NEXT_UPDATE_CONTEXT:
   1447        case CRLGEN_CHANGE_RANGE_CONTEXT:
   1448            crlGenData->crlField = PORT_New(CRLGENCrlField);
   1449            if (!crlGenData->crlField) {
   1450                return SECFailure;
   1451            }
   1452            crlGenData->contextId = structType;
   1453            crlGenData->crlField->value = NULL;
   1454            crlGenData->crlField->updateCrlFn = &crlgen_updateCrlFn_field;
   1455            crlGenData->crlField->setNextDataFn = &crlgen_setNextDataFn_field;
   1456            break;
   1457        case CRLGEN_RM_CERT_CONTEXT:
   1458        case CRLGEN_ADD_CERT_CONTEXT:
   1459            crlGenData->certEntry = PORT_New(CRLGENCertEntry);
   1460            if (!crlGenData->certEntry) {
   1461                return SECFailure;
   1462            }
   1463            crlGenData->contextId = structType;
   1464            crlGenData->certEntry->certId = 0;
   1465            crlGenData->certEntry->revocationTime = NULL;
   1466            crlGenData->certEntry->updateCrlFn = &crlgen_updateCrlFn_cert;
   1467            crlGenData->certEntry->setNextDataFn = &crlgen_setNextDataFn_cert;
   1468            break;
   1469        case CRLGEN_ADD_EXTENSION_CONTEXT:
   1470            crlGenData->extensionEntry = PORT_New(CRLGENExtensionEntry);
   1471            if (!crlGenData->extensionEntry) {
   1472                return SECFailure;
   1473            }
   1474            crlGenData->contextId = structType;
   1475            crlGenData->extensionEntry->extData = NULL;
   1476            crlGenData->extensionEntry->nextUpdatedData = 0;
   1477            crlGenData->extensionEntry->updateCrlFn =
   1478                &crlgen_updateCrlFn_extension;
   1479            crlGenData->extensionEntry->setNextDataFn =
   1480                &crlgen_setNextDataFn_extension;
   1481            break;
   1482        case CRLGEN_UNKNOWN_CONTEXT:
   1483            break;
   1484        default:
   1485            crlgen_PrintError(crlGenData->parsedLineNum,
   1486                              "unknown context type: %d.\n", structType);
   1487            PORT_Assert(0);
   1488            return SECFailure;
   1489    }
   1490    return SECSuccess;
   1491 }
   1492 
   1493 /* Parser initialization function */
   1494 CRLGENGeneratorData *
   1495 CRLGEN_InitCrlGeneration(CERTSignedCrl *signCrl, PRFileDesc *src)
   1496 {
   1497    CRLGENGeneratorData *crlGenData = NULL;
   1498 
   1499    PORT_Assert(signCrl && src);
   1500    if (!signCrl || !src) {
   1501        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1502        return NULL;
   1503    }
   1504 
   1505    crlGenData = PORT_ZNew(CRLGENGeneratorData);
   1506    if (!crlGenData) {
   1507        return NULL;
   1508    }
   1509 
   1510    crlGenData->entryDataHashTable =
   1511        PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
   1512                        PL_CompareValues, NULL, NULL);
   1513    if (!crlGenData->entryDataHashTable) {
   1514        PORT_Free(crlGenData);
   1515        return NULL;
   1516    }
   1517 
   1518    crlGenData->src = src;
   1519    crlGenData->parsedLineNum = 1;
   1520    crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
   1521    crlGenData->signCrl = signCrl;
   1522    crlGenData->rangeFrom = 0;
   1523    crlGenData->rangeTo = 0;
   1524    crlGenData->crlExtHandle = NULL;
   1525 
   1526    PORT_SetError(0);
   1527 
   1528    return crlGenData;
   1529 }
   1530 
   1531 void
   1532 CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData *crlGenData)
   1533 {
   1534    if (!crlGenData)
   1535        return;
   1536    if (crlGenData->src)
   1537        PR_Close(crlGenData->src);
   1538    PL_HashTableDestroy(crlGenData->entryDataHashTable);
   1539    PORT_Free(crlGenData);
   1540 }