summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/crlutil/crlgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/cmd/crlutil/crlgen.c')
-rw-r--r--security/nss/cmd/crlutil/crlgen.c1542
1 files changed, 1542 insertions, 0 deletions
diff --git a/security/nss/cmd/crlutil/crlgen.c b/security/nss/cmd/crlutil/crlgen.c
new file mode 100644
index 000000000..1f9dc4b43
--- /dev/null
+++ b/security/nss/cmd/crlutil/crlgen.c
@@ -0,0 +1,1542 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** crlgen.c
+**
+** utility for managing certificates revocation lists generation
+**
+*/
+
+#include <stdio.h>
+#include <math.h>
+
+#include "nspr.h"
+#include "plgetopt.h"
+#include "nss.h"
+#include "secutil.h"
+#include "cert.h"
+#include "certi.h"
+#include "certdb.h"
+#include "pk11func.h"
+#include "crlgen.h"
+
+/* Destroys extHandle and data. data was create on heap.
+ * extHandle creaded by CERT_StartCRLEntryExtensions. entry
+ * was allocated on arena.*/
+static void
+destroyEntryData(CRLGENEntryData *data)
+{
+ if (!data)
+ return;
+ PORT_Assert(data->entry);
+ if (data->extHandle)
+ CERT_FinishExtensions(data->extHandle);
+ PORT_Free(data);
+}
+
+/* Prints error messages along with line number */
+void
+crlgen_PrintError(int line, char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+
+ fprintf(stderr, "crlgen: (line: %d) ", line);
+ vfprintf(stderr, msg, args);
+
+ va_end(args);
+}
+/* Finds CRLGENEntryData in hashtable according PRUint64 value
+ * - certId : cert serial number*/
+static CRLGENEntryData *
+crlgen_FindEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
+{
+ if (!crlGenData->entryDataHashTable || !certId)
+ return NULL;
+ return (CRLGENEntryData *)
+ PL_HashTableLookup(crlGenData->entryDataHashTable,
+ certId);
+}
+
+/* Removes CRLGENEntryData from hashtable according to certId
+ * - certId : cert serial number*/
+static SECStatus
+crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
+{
+ CRLGENEntryData *data = NULL;
+ SECStatus rv = SECSuccess;
+
+ if (!crlGenData->entryDataHashTable) {
+ return SECSuccess;
+ }
+
+ data = crlgen_FindEntry(crlGenData, certId);
+ if (!data) {
+ return SECSuccess;
+ }
+
+ if (!PL_HashTableRemove(crlGenData->entryDataHashTable, certId)) {
+ rv = SECFailure;
+ }
+
+ destroyEntryData(data);
+ return rv;
+}
+
+/* Stores CRLGENEntryData in hashtable according to certId
+ * - certId : cert serial number*/
+static CRLGENEntryData *
+crlgen_PlaceAnEntry(CRLGENGeneratorData *crlGenData,
+ CERTCrlEntry *entry, SECItem *certId)
+{
+ CRLGENEntryData *newData = NULL;
+
+ PORT_Assert(crlGenData && crlGenData->entryDataHashTable &&
+ entry);
+ if (!crlGenData || !crlGenData->entryDataHashTable || !entry) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ newData = PORT_ZNew(CRLGENEntryData);
+ if (!newData) {
+ return NULL;
+ }
+ newData->entry = entry;
+ newData->certId = certId;
+ if (!PL_HashTableAdd(crlGenData->entryDataHashTable,
+ newData->certId, newData)) {
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "Can not add entryData structure\n");
+ return NULL;
+ }
+ return newData;
+}
+
+/* Use this structure to keep pointer when commiting entries extensions */
+struct commitData {
+ int pos;
+ CERTCrlEntry **entries;
+};
+
+/* HT PL_HashTableEnumerateEntries callback. Sorts hashtable entries of the
+ * table he. Returns value through arg parameter*/
+static PRIntn PR_CALLBACK
+crlgen_CommitEntryData(PLHashEntry *he, PRIntn i, void *arg)
+{
+ CRLGENEntryData *data = NULL;
+
+ PORT_Assert(he);
+ if (!he) {
+ return HT_ENUMERATE_NEXT;
+ }
+ data = (CRLGENEntryData *)he->value;
+
+ PORT_Assert(data);
+ PORT_Assert(arg);
+
+ if (data) {
+ struct commitData *dt = (struct commitData *)arg;
+ dt->entries[dt->pos++] = data->entry;
+ destroyEntryData(data);
+ }
+ return HT_ENUMERATE_NEXT;
+}
+
+/* Copy char * datainto allocated in arena SECItem */
+static SECStatus
+crlgen_SetString(PLArenaPool *arena, const char *dataIn, SECItem *value)
+{
+ SECItem item;
+
+ PORT_Assert(arena && dataIn);
+ if (!arena || !dataIn) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ item.data = (void *)dataIn;
+ item.len = PORT_Strlen(dataIn);
+
+ return SECITEM_CopyItem(arena, value, &item);
+}
+
+/* Creates CERTGeneralName from parsed data for the Authority Key Extension */
+static CERTGeneralName *
+crlgen_GetGeneralName(PLArenaPool *arena, CRLGENGeneratorData *crlGenData,
+ const char *data)
+{
+ CERTGeneralName *namesList = NULL;
+ CERTGeneralName *current;
+ CERTGeneralName *tail = NULL;
+ SECStatus rv = SECSuccess;
+ const char *nextChunk = NULL;
+ const char *currData = NULL;
+ int intValue;
+ char buffer[512];
+ void *mark;
+
+ if (!data)
+ return NULL;
+ PORT_Assert(arena);
+ if (!arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ mark = PORT_ArenaMark(arena);
+
+ nextChunk = data;
+ currData = data;
+ do {
+ int nameLen = 0;
+ char name[128];
+ const char *sepPrt = NULL;
+ nextChunk = PORT_Strchr(currData, '|');
+ if (!nextChunk)
+ nextChunk = data + strlen(data);
+ sepPrt = PORT_Strchr(currData, ':');
+ if (sepPrt == NULL || sepPrt >= nextChunk) {
+ *buffer = '\0';
+ sepPrt = nextChunk;
+ } else {
+ PORT_Memcpy(buffer, sepPrt + 1,
+ (nextChunk - sepPrt - 1));
+ buffer[nextChunk - sepPrt - 1] = '\0';
+ }
+ nameLen = PR_MIN(sepPrt - currData, sizeof(name) - 1);
+ PORT_Memcpy(name, currData, nameLen);
+ name[nameLen] = '\0';
+ currData = nextChunk + 1;
+
+ if (!PORT_Strcmp(name, "otherName"))
+ intValue = certOtherName;
+ else if (!PORT_Strcmp(name, "rfc822Name"))
+ intValue = certRFC822Name;
+ else if (!PORT_Strcmp(name, "dnsName"))
+ intValue = certDNSName;
+ else if (!PORT_Strcmp(name, "x400Address"))
+ intValue = certX400Address;
+ else if (!PORT_Strcmp(name, "directoryName"))
+ intValue = certDirectoryName;
+ else if (!PORT_Strcmp(name, "ediPartyName"))
+ intValue = certEDIPartyName;
+ else if (!PORT_Strcmp(name, "URI"))
+ intValue = certURI;
+ else if (!PORT_Strcmp(name, "ipAddress"))
+ intValue = certIPAddress;
+ else if (!PORT_Strcmp(name, "registerID"))
+ intValue = certRegisterID;
+ else
+ intValue = -1;
+
+ if (intValue >= certOtherName && intValue <= certRegisterID) {
+ if (namesList == NULL) {
+ namesList = current = tail = PORT_ArenaZNew(arena,
+ CERTGeneralName);
+ } else {
+ current = PORT_ArenaZNew(arena, CERTGeneralName);
+ }
+ if (current == NULL) {
+ rv = SECFailure;
+ break;
+ }
+ } else {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ break;
+ }
+ current->type = intValue;
+ switch (current->type) {
+ case certURI:
+ case certDNSName:
+ case certRFC822Name:
+ current->name.other.data = PORT_ArenaAlloc(arena, strlen(buffer));
+ if (current->name.other.data == NULL) {
+ rv = SECFailure;
+ break;
+ }
+ PORT_Memcpy(current->name.other.data, buffer,
+ current->name.other.len = strlen(buffer));
+ break;
+
+ case certEDIPartyName:
+ case certIPAddress:
+ case certOtherName:
+ case certRegisterID:
+ case certX400Address: {
+
+ current->name.other.data = PORT_ArenaAlloc(arena, strlen(buffer) + 2);
+ if (current->name.other.data == NULL) {
+ rv = SECFailure;
+ break;
+ }
+
+ PORT_Memcpy(current->name.other.data + 2, buffer, strlen(buffer));
+ /* This may not be accurate for all cases.For now, use this tag type */
+ current->name.other.data[0] = (char)(((current->type - 1) & 0x1f) | 0x80);
+ current->name.other.data[1] = (char)strlen(buffer);
+ current->name.other.len = strlen(buffer) + 2;
+ break;
+ }
+
+ case certDirectoryName: {
+ CERTName *directoryName = NULL;
+
+ directoryName = CERT_AsciiToName(buffer);
+ if (!directoryName) {
+ rv = SECFailure;
+ break;
+ }
+
+ rv = CERT_CopyName(arena, &current->name.directoryName, directoryName);
+ CERT_DestroyName(directoryName);
+
+ break;
+ }
+ }
+ if (rv != SECSuccess)
+ break;
+ current->l.next = &(namesList->l);
+ current->l.prev = &(tail->l);
+ tail->l.next = &(current->l);
+ tail = current;
+
+ } while (nextChunk != data + strlen(data));
+
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease(arena, mark);
+ namesList = NULL;
+ }
+ return (namesList);
+}
+
+/* Creates CERTGeneralName from parsed data for the Authority Key Extension */
+static CERTGeneralName *
+crlgen_DistinguishedName(PLArenaPool *arena, CRLGENGeneratorData *crlGenData,
+ const char *data)
+{
+ CERTName *directoryName = NULL;
+ CERTGeneralName *current;
+ SECStatus rv = SECFailure;
+ void *mark;
+
+ if (!data)
+ return NULL;
+ PORT_Assert(arena);
+ if (!arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ mark = PORT_ArenaMark(arena);
+
+ current = PORT_ArenaZNew(arena, CERTGeneralName);
+ if (current == NULL) {
+ goto loser;
+ }
+ current->type = certDirectoryName;
+ current->l.next = &current->l;
+ current->l.prev = &current->l;
+
+ directoryName = CERT_AsciiToName((char *)data);
+ if (!directoryName) {
+ goto loser;
+ }
+
+ rv = CERT_CopyName(arena, &current->name.directoryName, directoryName);
+ CERT_DestroyName(directoryName);
+
+loser:
+ if (rv != SECSuccess) {
+ PORT_SetError(rv);
+ PORT_ArenaRelease(arena, mark);
+ current = NULL;
+ }
+ return (current);
+}
+
+/* Adding Authority Key ID extension to extension handle. */
+static SECStatus
+crlgen_AddAuthKeyID(CRLGENGeneratorData *crlGenData,
+ const char **dataArr)
+{
+ void *extHandle = NULL;
+ CERTAuthKeyID *authKeyID = NULL;
+ PLArenaPool *arena = NULL;
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(dataArr && crlGenData);
+ if (!crlGenData || !dataArr) {
+ return SECFailure;
+ }
+
+ extHandle = crlGenData->crlExtHandle;
+
+ if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of parameters.\n");
+ return SECFailure;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ return SECFailure;
+ }
+
+ authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID);
+ if (authKeyID == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ if (dataArr[3] == NULL) {
+ rv = crlgen_SetString(arena, dataArr[2], &authKeyID->keyID);
+ if (rv != SECSuccess)
+ goto loser;
+ } else {
+ rv = crlgen_SetString(arena, dataArr[3],
+ &authKeyID->authCertSerialNumber);
+ if (rv != SECSuccess)
+ goto loser;
+
+ authKeyID->authCertIssuer =
+ crlgen_DistinguishedName(arena, crlGenData, dataArr[2]);
+ if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError()) {
+ crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
+ rv = SECFailure;
+ goto loser;
+ }
+ }
+
+ rv =
+ SECU_EncodeAndAddExtensionValue(arena, extHandle, authKeyID,
+ (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
+ SEC_OID_X509_AUTH_KEY_ID,
+ (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeAuthKeyID);
+loser:
+ if (arena)
+ PORT_FreeArena(arena, PR_FALSE);
+ return rv;
+}
+
+/* Creates and add Subject Alternative Names extension */
+static SECStatus
+crlgen_AddIssuerAltNames(CRLGENGeneratorData *crlGenData,
+ const char **dataArr)
+{
+ CERTGeneralName *nameList = NULL;
+ PLArenaPool *arena = NULL;
+ void *extHandle = NULL;
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(dataArr && crlGenData);
+ if (!crlGenData || !dataArr) {
+ return SECFailure;
+ }
+
+ if (!dataArr || !dataArr[0] || !dataArr[1] || !dataArr[2]) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ return SECFailure;
+ }
+
+ PORT_Assert(dataArr && crlGenData);
+ if (!crlGenData || !dataArr) {
+ return SECFailure;
+ }
+
+ extHandle = crlGenData->crlExtHandle;
+
+ if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of parameters.\n");
+ return SECFailure;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ return SECFailure;
+ }
+
+ nameList = crlgen_GetGeneralName(arena, crlGenData, dataArr[2]);
+ if (nameList == NULL) {
+ crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
+ rv = SECFailure;
+ goto loser;
+ }
+
+ rv =
+ SECU_EncodeAndAddExtensionValue(arena, extHandle, nameList,
+ (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
+ SEC_OID_X509_ISSUER_ALT_NAME,
+ (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeAltNameExtension);
+loser:
+ if (arena)
+ PORT_FreeArena(arena, PR_FALSE);
+ return rv;
+}
+
+/* Creates and adds CRLNumber extension to extension handle.
+ * Since, this is CRL extension, extension handle is the one
+ * related to CRL extensions */
+static SECStatus
+crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
+{
+ PLArenaPool *arena = NULL;
+ SECItem encodedItem;
+ void *dummy;
+ SECStatus rv = SECFailure;
+ int code = 0;
+
+ PORT_Assert(dataArr && crlGenData);
+ if (!crlGenData || !dataArr) {
+ goto loser;
+ }
+
+ if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ goto loser;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ goto loser;
+ }
+
+ code = atoi(dataArr[2]);
+ if (code == 0 && *dataArr[2] != '0') {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
+ if (!dummy) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ rv = CERT_AddExtension(crlGenData->crlExtHandle, SEC_OID_X509_CRL_NUMBER,
+ &encodedItem,
+ (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
+ PR_TRUE);
+
+loser:
+ if (arena)
+ PORT_FreeArena(arena, PR_FALSE);
+ return rv;
+}
+
+/* Creates Cert Revocation Reason code extension. Encodes it and
+ * returns as SECItem structure */
+static SECItem *
+crlgen_CreateReasonCode(PLArenaPool *arena, const char **dataArr,
+ int *extCode)
+{
+ SECItem *encodedItem;
+ void *dummy;
+ void *mark = NULL;
+ int code = 0;
+
+ PORT_Assert(arena && dataArr);
+ if (!arena || !dataArr) {
+ goto loser;
+ }
+
+ mark = PORT_ArenaMark(arena);
+
+ encodedItem = PORT_ArenaZNew(arena, SECItem);
+ if (encodedItem == NULL) {
+ goto loser;
+ }
+
+ if (dataArr[2] == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ code = atoi(dataArr[2]);
+ /* aACompromise(10) is the last possible of the values
+ * for the Reason Core Extension */
+ if ((code == 0 && *dataArr[2] != '0') || code > 10) {
+
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ dummy = SEC_ASN1EncodeInteger(arena, encodedItem, code);
+ if (!dummy) {
+ goto loser;
+ }
+
+ *extCode = SEC_OID_X509_REASON_CODE;
+ return encodedItem;
+
+loser:
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ return NULL;
+}
+
+/* Creates Cert Invalidity Date extension. Encodes it and
+ * returns as SECItem structure */
+static SECItem *
+crlgen_CreateInvalidityDate(PLArenaPool *arena, const char **dataArr,
+ int *extCode)
+{
+ SECItem *encodedItem;
+ int length = 0;
+ void *mark = NULL;
+
+ PORT_Assert(arena && dataArr);
+ if (!arena || !dataArr) {
+ goto loser;
+ }
+
+ mark = PORT_ArenaMark(arena);
+
+ encodedItem = PORT_ArenaZNew(arena, SECItem);
+ if (encodedItem == NULL) {
+ goto loser;
+ }
+
+ length = PORT_Strlen(dataArr[2]);
+
+ encodedItem->type = siGeneralizedTime;
+ encodedItem->data = PORT_ArenaAlloc(arena, length);
+ if (!encodedItem->data) {
+ goto loser;
+ }
+
+ PORT_Memcpy(encodedItem->data, dataArr[2], (encodedItem->len = length) *
+ sizeof(char));
+
+ *extCode = SEC_OID_X509_INVALID_DATE;
+ return encodedItem;
+
+loser:
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ return NULL;
+}
+
+/* Creates(by calling extCreator function) and adds extension to a set
+ * of already added certs. Uses values of rangeFrom and rangeTo from
+ * CRLGENCrlGenCtl structure for identifying the inclusive set of certs */
+static SECStatus
+crlgen_AddEntryExtension(CRLGENGeneratorData *crlGenData,
+ const char **dataArr, char *extName,
+ SECItem *(*extCreator)(PLArenaPool *arena,
+ const char **dataArr,
+ int *extCode))
+{
+ PRUint64 i = 0;
+ SECStatus rv = SECFailure;
+ int extCode = 0;
+ PRUint64 lastRange;
+ SECItem *ext = NULL;
+ PLArenaPool *arena = NULL;
+
+ PORT_Assert(crlGenData && dataArr);
+ if (!crlGenData || !dataArr) {
+ goto loser;
+ }
+
+ if (!dataArr[0] || !dataArr[1]) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ }
+
+ lastRange = crlGenData->rangeTo - crlGenData->rangeFrom + 1;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ goto loser;
+ }
+
+ ext = extCreator(arena, dataArr, &extCode);
+ if (ext == NULL) {
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "got error while creating extension: %s\n",
+ extName);
+ goto loser;
+ }
+
+ for (i = 0; i < lastRange; i++) {
+ CRLGENEntryData *extData = NULL;
+ void *extHandle = NULL;
+ SECItem *certIdItem =
+ SEC_ASN1EncodeInteger(arena, NULL,
+ crlGenData->rangeFrom + i);
+ if (!certIdItem) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ extData = crlgen_FindEntry(crlGenData, certIdItem);
+ if (!extData) {
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "can not add extension: crl entry "
+ "(serial number: %d) is not in the list yet.\n",
+ crlGenData->rangeFrom + i);
+ continue;
+ }
+
+ extHandle = extData->extHandle;
+ if (extHandle == NULL) {
+ extHandle = extData->extHandle =
+ CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
+ (CERTCrlEntry *)extData->entry);
+ }
+ rv = CERT_AddExtension(extHandle, extCode, ext,
+ (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
+ PR_TRUE);
+ if (rv == SECFailure) {
+ goto loser;
+ }
+ }
+
+loser:
+ if (arena)
+ PORT_FreeArena(arena, PR_FALSE);
+ return rv;
+}
+
+/* Commits all added entries and their's extensions into CRL. */
+SECStatus
+CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData *crlGenData)
+{
+ int size = 0;
+ CERTCrl *crl;
+ PLArenaPool *arena;
+ SECStatus rv = SECSuccess;
+ void *mark;
+
+ PORT_Assert(crlGenData && crlGenData->signCrl && crlGenData->signCrl->arena);
+ if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ arena = crlGenData->signCrl->arena;
+ crl = &crlGenData->signCrl->crl;
+
+ mark = PORT_ArenaMark(arena);
+
+ if (crlGenData->crlExtHandle)
+ CERT_FinishExtensions(crlGenData->crlExtHandle);
+
+ size = crlGenData->entryDataHashTable->nentries;
+ crl->entries = NULL;
+ if (size) {
+ crl->entries = PORT_ArenaZNewArray(arena, CERTCrlEntry *, size + 1);
+ if (!crl->entries) {
+ rv = SECFailure;
+ } else {
+ struct commitData dt;
+ dt.entries = crl->entries;
+ dt.pos = 0;
+ PL_HashTableEnumerateEntries(crlGenData->entryDataHashTable,
+ &crlgen_CommitEntryData, &dt);
+ /* Last should be NULL */
+ crl->entries[size] = NULL;
+ }
+ }
+
+ if (rv != SECSuccess)
+ PORT_ArenaRelease(arena, mark);
+ return rv;
+}
+
+/* Initializes extHandle with data from extensions array */
+static SECStatus
+crlgen_InitExtensionHandle(void *extHandle,
+ CERTCertExtension **extensions)
+{
+ CERTCertExtension *extension = NULL;
+
+ if (!extensions)
+ return SECSuccess;
+
+ PORT_Assert(extHandle != NULL);
+ if (!extHandle) {
+ return SECFailure;
+ }
+
+ extension = *extensions;
+ while (extension) {
+ SECOidTag oidTag = SECOID_FindOIDTag(&extension->id);
+ /* shell we skip unknown extensions? */
+ CERT_AddExtension(extHandle, oidTag, &extension->value,
+ (extension->critical.len != 0) ? PR_TRUE : PR_FALSE,
+ PR_FALSE);
+ extension = *(++extensions);
+ }
+ return SECSuccess;
+}
+
+/* Used for initialization of extension handles for crl and certs
+ * extensions from existing CRL data then modifying existing CRL.*/
+SECStatus
+CRLGEN_ExtHandleInit(CRLGENGeneratorData *crlGenData)
+{
+ CERTCrl *crl = NULL;
+ PRUint64 maxSN = 0;
+
+ PORT_Assert(crlGenData && crlGenData->signCrl &&
+ crlGenData->entryDataHashTable);
+ if (!crlGenData || !crlGenData->signCrl ||
+ !crlGenData->entryDataHashTable) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ crl = &crlGenData->signCrl->crl;
+ crlGenData->crlExtHandle = CERT_StartCRLExtensions(crl);
+ crlgen_InitExtensionHandle(crlGenData->crlExtHandle,
+ crl->extensions);
+ crl->extensions = NULL;
+
+ if (crl->entries) {
+ CERTCrlEntry **entry = crl->entries;
+ while (*entry) {
+ PRUint64 sn = DER_GetInteger(&(*entry)->serialNumber);
+ CRLGENEntryData *extData =
+ crlgen_PlaceAnEntry(crlGenData, *entry, &(*entry)->serialNumber);
+ if ((*entry)->extensions) {
+ extData->extHandle =
+ CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
+ (CERTCrlEntry *)extData->entry);
+ if (crlgen_InitExtensionHandle(extData->extHandle,
+ (*entry)->extensions) == SECFailure)
+ return SECFailure;
+ }
+ (*entry)->extensions = NULL;
+ entry++;
+ maxSN = PR_MAX(maxSN, sn);
+ }
+ }
+
+ crlGenData->rangeFrom = crlGenData->rangeTo = maxSN + 1;
+ return SECSuccess;
+}
+
+/*****************************************************************************
+ * Parser trigger functions start here
+ */
+
+/* Sets new internal range value for add/rm certs.*/
+static SECStatus
+crlgen_SetNewRangeField(CRLGENGeneratorData *crlGenData, char *value)
+{
+ long rangeFrom = 0, rangeTo = 0;
+ char *dashPos = NULL;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (value == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ return SECFailure;
+ }
+
+ if ((dashPos = strchr(value, '-')) != NULL) {
+ char *rangeToS, *rangeFromS = value;
+ *dashPos = '\0';
+ rangeFrom = atoi(rangeFromS);
+ *dashPos = '-';
+
+ rangeToS = (char *)(dashPos + 1);
+ rangeTo = atol(rangeToS);
+ } else {
+ rangeFrom = atol(value);
+ rangeTo = rangeFrom;
+ }
+
+ if (rangeFrom < 1 || rangeTo < rangeFrom) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "bad cert id range: %s.\n", value);
+ return SECFailure;
+ }
+
+ crlGenData->rangeFrom = rangeFrom;
+ crlGenData->rangeTo = rangeTo;
+
+ return SECSuccess;
+}
+
+/* Changes issuer subject field in CRL. By default this data is taken from
+ * issuer cert subject field.Not yet implemented */
+static SECStatus
+crlgen_SetIssuerField(CRLGENGeneratorData *crlGenData, char *value)
+{
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "Can not change CRL issuer field.\n");
+ return SECFailure;
+}
+
+/* Encode and sets CRL thisUpdate and nextUpdate time fields*/
+static SECStatus
+crlgen_SetTimeField(CRLGENGeneratorData *crlGenData, char *value,
+ PRBool setThisUpdate)
+{
+ CERTSignedCrl *signCrl;
+ PLArenaPool *arena;
+ CERTCrl *crl;
+ int length = 0;
+ SECItem *timeDest = NULL;
+
+ PORT_Assert(crlGenData && crlGenData->signCrl &&
+ crlGenData->signCrl->arena);
+ if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ signCrl = crlGenData->signCrl;
+ arena = signCrl->arena;
+ crl = &signCrl->crl;
+
+ if (value == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ return SECFailure;
+ }
+ length = PORT_Strlen(value);
+
+ if (setThisUpdate == PR_TRUE) {
+ timeDest = &crl->lastUpdate;
+ } else {
+ timeDest = &crl->nextUpdate;
+ }
+
+ timeDest->type = siGeneralizedTime;
+ timeDest->data = PORT_ArenaAlloc(arena, length);
+ if (!timeDest->data) {
+ return SECFailure;
+ }
+ PORT_Memcpy(timeDest->data, value, length);
+ timeDest->len = length;
+
+ return SECSuccess;
+}
+
+/* Adds new extension into CRL or added cert handles */
+static SECStatus
+crlgen_AddExtension(CRLGENGeneratorData *crlGenData, const char **extData)
+{
+ PORT_Assert(crlGenData && crlGenData->crlExtHandle);
+ if (!crlGenData || !crlGenData->crlExtHandle) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (extData == NULL || *extData == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ return SECFailure;
+ }
+ if (!PORT_Strcmp(*extData, "authKeyId"))
+ return crlgen_AddAuthKeyID(crlGenData, extData);
+ else if (!PORT_Strcmp(*extData, "issuerAltNames"))
+ return crlgen_AddIssuerAltNames(crlGenData, extData);
+ else if (!PORT_Strcmp(*extData, "crlNumber"))
+ return crlgen_AddCrlNumber(crlGenData, extData);
+ else if (!PORT_Strcmp(*extData, "reasonCode"))
+ return crlgen_AddEntryExtension(crlGenData, extData, "reasonCode",
+ crlgen_CreateReasonCode);
+ else if (!PORT_Strcmp(*extData, "invalidityDate"))
+ return crlgen_AddEntryExtension(crlGenData, extData, "invalidityDate",
+ crlgen_CreateInvalidityDate);
+ else {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ return SECFailure;
+ }
+}
+
+/* Created CRLGENEntryData for cert with serial number certId and
+ * adds it to entryDataHashTable. certId can be a single cert serial
+ * number or an inclusive rage of certs */
+static SECStatus
+crlgen_AddCert(CRLGENGeneratorData *crlGenData,
+ char *certId, char *revocationDate)
+{
+ CERTSignedCrl *signCrl;
+ SECItem *certIdItem;
+ PLArenaPool *arena;
+ PRUint64 rangeFrom = 0, rangeTo = 0, i = 0;
+ int timeValLength = -1;
+ SECStatus rv = SECFailure;
+ void *mark;
+
+ PORT_Assert(crlGenData && crlGenData->signCrl &&
+ crlGenData->signCrl->arena);
+ if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ signCrl = crlGenData->signCrl;
+ arena = signCrl->arena;
+
+ if (!certId || !revocationDate) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "insufficient number of arguments.\n");
+ return SECFailure;
+ }
+
+ timeValLength = strlen(revocationDate);
+
+ if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
+ certId) {
+ return SECFailure;
+ }
+ rangeFrom = crlGenData->rangeFrom;
+ rangeTo = crlGenData->rangeTo;
+
+ for (i = 0; i < rangeTo - rangeFrom + 1; i++) {
+ CERTCrlEntry *entry;
+ mark = PORT_ArenaMark(arena);
+ entry = PORT_ArenaZNew(arena, CERTCrlEntry);
+ if (entry == NULL) {
+ goto loser;
+ }
+
+ certIdItem = SEC_ASN1EncodeInteger(arena, &entry->serialNumber,
+ rangeFrom + i);
+ if (!certIdItem) {
+ goto loser;
+ }
+
+ if (crlgen_FindEntry(crlGenData, certIdItem)) {
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "entry already exists. Use \"range\" "
+ "and \"rmcert\" before adding a new one with the "
+ "same serial number %ld\n",
+ rangeFrom + i);
+ goto loser;
+ }
+
+ entry->serialNumber.type = siBuffer;
+
+ entry->revocationDate.type = siGeneralizedTime;
+
+ entry->revocationDate.data =
+ PORT_ArenaAlloc(arena, timeValLength);
+ if (entry->revocationDate.data == NULL) {
+ goto loser;
+ }
+
+ PORT_Memcpy(entry->revocationDate.data, revocationDate,
+ timeValLength * sizeof(char));
+ entry->revocationDate.len = timeValLength;
+
+ entry->extensions = NULL;
+ if (!crlgen_PlaceAnEntry(crlGenData, entry, certIdItem)) {
+ goto loser;
+ }
+ mark = NULL;
+ }
+
+ rv = SECSuccess;
+loser:
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ return rv;
+}
+
+/* Removes certs from entryDataHashTable which have certId serial number.
+ * certId can have value of a range of certs */
+static SECStatus
+crlgen_RmCert(CRLGENGeneratorData *crlGenData, char *certId)
+{
+ PRUint64 i = 0;
+
+ PORT_Assert(crlGenData && certId);
+ if (!crlGenData || !certId) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
+ certId) {
+ return SECFailure;
+ }
+
+ for (i = 0; i < crlGenData->rangeTo - crlGenData->rangeFrom + 1; i++) {
+ SECItem *certIdItem = SEC_ASN1EncodeInteger(NULL, NULL,
+ crlGenData->rangeFrom + i);
+ if (certIdItem) {
+ CRLGENEntryData *extData =
+ crlgen_FindEntry(crlGenData, certIdItem);
+ if (!extData) {
+ printf("Cert with id %s is not in the list\n", certId);
+ } else {
+ crlgen_RmEntry(crlGenData, certIdItem);
+ }
+ SECITEM_FreeItem(certIdItem, PR_TRUE);
+ }
+ }
+
+ return SECSuccess;
+}
+
+/*************************************************************************
+ * Lex Parser Helper functions are used to store parsed information
+ * in context related structures. Context(or state) is identified base on
+ * a type of a instruction parser currently is going through. New context
+ * is identified by first token in a line. It can be addcert context,
+ * addext context, etc. */
+
+/* Updates CRL field depending on current context */
+static SECStatus
+crlgen_updateCrlFn_field(CRLGENGeneratorData *crlGenData, void *str)
+{
+ CRLGENCrlField *fieldStr = (CRLGENCrlField *)str;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (crlGenData->contextId) {
+ case CRLGEN_ISSUER_CONTEXT:
+ crlgen_SetIssuerField(crlGenData, fieldStr->value);
+ break;
+ case CRLGEN_UPDATE_CONTEXT:
+ return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_TRUE);
+ break;
+ case CRLGEN_NEXT_UPDATE_CONTEXT:
+ return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_FALSE);
+ break;
+ case CRLGEN_CHANGE_RANGE_CONTEXT:
+ return crlgen_SetNewRangeField(crlGenData, fieldStr->value);
+ break;
+ default:
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "syntax error (unknow token type: %d)\n",
+ crlGenData->contextId);
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/* Sets parsed data for CRL field update into temporary structure */
+static SECStatus
+crlgen_setNextDataFn_field(CRLGENGeneratorData *crlGenData, void *str,
+ void *data, unsigned short dtype)
+{
+ CRLGENCrlField *fieldStr = (CRLGENCrlField *)str;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (crlGenData->contextId) {
+ case CRLGEN_CHANGE_RANGE_CONTEXT:
+ if (dtype != CRLGEN_TYPE_DIGIT && dtype != CRLGEN_TYPE_DIGIT_RANGE) {
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "range value should have "
+ "numeric or numeric range values.\n");
+ return SECFailure;
+ }
+ break;
+ case CRLGEN_NEXT_UPDATE_CONTEXT:
+ case CRLGEN_UPDATE_CONTEXT:
+ if (dtype != CRLGEN_TYPE_ZDATE) {
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "bad formated date. Should be "
+ "YYYYMMDDHHMMSSZ.\n");
+ return SECFailure;
+ }
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "syntax error (unknow token type: %d).\n",
+ crlGenData->contextId, data);
+ return SECFailure;
+ }
+ fieldStr->value = PORT_Strdup(data);
+ if (!fieldStr->value) {
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/* Triggers cert entries update depending on current context */
+static SECStatus
+crlgen_updateCrlFn_cert(CRLGENGeneratorData *crlGenData, void *str)
+{
+ CRLGENCertEntry *certStr = (CRLGENCertEntry *)str;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (crlGenData->contextId) {
+ case CRLGEN_ADD_CERT_CONTEXT:
+ return crlgen_AddCert(crlGenData, certStr->certId,
+ certStr->revocationTime);
+ case CRLGEN_RM_CERT_CONTEXT:
+ return crlgen_RmCert(crlGenData, certStr->certId);
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "syntax error (unknow token type: %d).\n",
+ crlGenData->contextId);
+ return SECFailure;
+ }
+}
+
+/* Sets parsed data for CRL entries update into temporary structure */
+static SECStatus
+crlgen_setNextDataFn_cert(CRLGENGeneratorData *crlGenData, void *str,
+ void *data, unsigned short dtype)
+{
+ CRLGENCertEntry *certStr = (CRLGENCertEntry *)str;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (dtype) {
+ case CRLGEN_TYPE_DIGIT:
+ case CRLGEN_TYPE_DIGIT_RANGE:
+ certStr->certId = PORT_Strdup(data);
+ if (!certStr->certId) {
+ return SECFailure;
+ }
+ break;
+ case CRLGEN_TYPE_DATE:
+ case CRLGEN_TYPE_ZDATE:
+ certStr->revocationTime = PORT_Strdup(data);
+ if (!certStr->revocationTime) {
+ return SECFailure;
+ }
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "syntax error (unknow token type: %d).\n",
+ crlGenData->contextId);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/* Triggers cert entries/crl extension update */
+static SECStatus
+crlgen_updateCrlFn_extension(CRLGENGeneratorData *crlGenData, void *str)
+{
+ CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry *)str;
+
+ return crlgen_AddExtension(crlGenData, (const char **)extStr->extData);
+}
+
+/* Defines maximum number of fields extension may have */
+#define MAX_EXT_DATA_LENGTH 10
+
+/* Sets parsed extension data for CRL entries/CRL extensions update
+ * into temporary structure */
+static SECStatus
+crlgen_setNextDataFn_extension(CRLGENGeneratorData *crlGenData, void *str,
+ void *data, unsigned short dtype)
+{
+ CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry *)str;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (extStr->extData == NULL) {
+ extStr->extData = PORT_ZNewArray(char *, MAX_EXT_DATA_LENGTH);
+ if (!extStr->extData) {
+ return SECFailure;
+ }
+ }
+ if (extStr->nextUpdatedData >= MAX_EXT_DATA_LENGTH) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "number of fields in extension "
+ "exceeded maximum allowed data length: %d.\n",
+ MAX_EXT_DATA_LENGTH);
+ return SECFailure;
+ }
+ extStr->extData[extStr->nextUpdatedData] = PORT_Strdup(data);
+ if (!extStr->extData[extStr->nextUpdatedData]) {
+ return SECFailure;
+ }
+ extStr->nextUpdatedData += 1;
+
+ return SECSuccess;
+}
+
+/****************************************************************************************
+ * Top level functions are triggered directly by parser.
+ */
+
+/*
+ * crl generation script parser recreates a temporary data staructure
+ * for each line it is going through. This function cleans temp structure.
+ */
+void
+crlgen_destroyTempData(CRLGENGeneratorData *crlGenData)
+{
+ if (crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
+ switch (crlGenData->contextId) {
+ case CRLGEN_ISSUER_CONTEXT:
+ case CRLGEN_UPDATE_CONTEXT:
+ case CRLGEN_NEXT_UPDATE_CONTEXT:
+ case CRLGEN_CHANGE_RANGE_CONTEXT:
+ if (crlGenData->crlField->value)
+ PORT_Free(crlGenData->crlField->value);
+ PORT_Free(crlGenData->crlField);
+ break;
+ case CRLGEN_ADD_CERT_CONTEXT:
+ case CRLGEN_RM_CERT_CONTEXT:
+ if (crlGenData->certEntry->certId)
+ PORT_Free(crlGenData->certEntry->certId);
+ if (crlGenData->certEntry->revocationTime)
+ PORT_Free(crlGenData->certEntry->revocationTime);
+ PORT_Free(crlGenData->certEntry);
+ break;
+ case CRLGEN_ADD_EXTENSION_CONTEXT:
+ if (crlGenData->extensionEntry->extData) {
+ int i = 0;
+ for (; i < crlGenData->extensionEntry->nextUpdatedData; i++)
+ PORT_Free(*(crlGenData->extensionEntry->extData + i));
+ PORT_Free(crlGenData->extensionEntry->extData);
+ }
+ PORT_Free(crlGenData->extensionEntry);
+ break;
+ }
+ crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
+ }
+}
+
+SECStatus
+crlgen_updateCrl(CRLGENGeneratorData *crlGenData)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (crlGenData->contextId) {
+ case CRLGEN_ISSUER_CONTEXT:
+ case CRLGEN_UPDATE_CONTEXT:
+ case CRLGEN_NEXT_UPDATE_CONTEXT:
+ case CRLGEN_CHANGE_RANGE_CONTEXT:
+ rv = crlGenData->crlField->updateCrlFn(crlGenData, crlGenData->crlField);
+ break;
+ case CRLGEN_RM_CERT_CONTEXT:
+ case CRLGEN_ADD_CERT_CONTEXT:
+ rv = crlGenData->certEntry->updateCrlFn(crlGenData, crlGenData->certEntry);
+ break;
+ case CRLGEN_ADD_EXTENSION_CONTEXT:
+ rv = crlGenData->extensionEntry->updateCrlFn(crlGenData, crlGenData->extensionEntry);
+ break;
+ case CRLGEN_UNKNOWN_CONTEXT:
+ break;
+ default:
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "unknown lang context type code: %d.\n",
+ crlGenData->contextId);
+ PORT_Assert(0);
+ return SECFailure;
+ }
+ /* Clrean structures after crl update */
+ crlgen_destroyTempData(crlGenData);
+
+ crlGenData->parsedLineNum += 1;
+
+ return rv;
+}
+
+SECStatus
+crlgen_setNextData(CRLGENGeneratorData *crlGenData, void *data,
+ unsigned short dtype)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(crlGenData);
+ if (!crlGenData) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (crlGenData->contextId) {
+ case CRLGEN_ISSUER_CONTEXT:
+ case CRLGEN_UPDATE_CONTEXT:
+ case CRLGEN_NEXT_UPDATE_CONTEXT:
+ case CRLGEN_CHANGE_RANGE_CONTEXT:
+ rv = crlGenData->crlField->setNextDataFn(crlGenData, crlGenData->crlField,
+ data, dtype);
+ break;
+ case CRLGEN_ADD_CERT_CONTEXT:
+ case CRLGEN_RM_CERT_CONTEXT:
+ rv = crlGenData->certEntry->setNextDataFn(crlGenData, crlGenData->certEntry,
+ data, dtype);
+ break;
+ case CRLGEN_ADD_EXTENSION_CONTEXT:
+ rv =
+ crlGenData->extensionEntry->setNextDataFn(crlGenData, crlGenData->extensionEntry, data, dtype);
+ break;
+ case CRLGEN_UNKNOWN_CONTEXT:
+ break;
+ default:
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "unknown context type: %d.\n",
+ crlGenData->contextId);
+ PORT_Assert(0);
+ return SECFailure;
+ }
+ return rv;
+}
+
+SECStatus
+crlgen_createNewLangStruct(CRLGENGeneratorData *crlGenData,
+ unsigned structType)
+{
+ PORT_Assert(crlGenData &&
+ crlGenData->contextId == CRLGEN_UNKNOWN_CONTEXT);
+ if (!crlGenData ||
+ crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ switch (structType) {
+ case CRLGEN_ISSUER_CONTEXT:
+ case CRLGEN_UPDATE_CONTEXT:
+ case CRLGEN_NEXT_UPDATE_CONTEXT:
+ case CRLGEN_CHANGE_RANGE_CONTEXT:
+ crlGenData->crlField = PORT_New(CRLGENCrlField);
+ if (!crlGenData->crlField) {
+ return SECFailure;
+ }
+ crlGenData->contextId = structType;
+ crlGenData->crlField->value = NULL;
+ crlGenData->crlField->updateCrlFn = &crlgen_updateCrlFn_field;
+ crlGenData->crlField->setNextDataFn = &crlgen_setNextDataFn_field;
+ break;
+ case CRLGEN_RM_CERT_CONTEXT:
+ case CRLGEN_ADD_CERT_CONTEXT:
+ crlGenData->certEntry = PORT_New(CRLGENCertEntry);
+ if (!crlGenData->certEntry) {
+ return SECFailure;
+ }
+ crlGenData->contextId = structType;
+ crlGenData->certEntry->certId = 0;
+ crlGenData->certEntry->revocationTime = NULL;
+ crlGenData->certEntry->updateCrlFn = &crlgen_updateCrlFn_cert;
+ crlGenData->certEntry->setNextDataFn = &crlgen_setNextDataFn_cert;
+ break;
+ case CRLGEN_ADD_EXTENSION_CONTEXT:
+ crlGenData->extensionEntry = PORT_New(CRLGENExtensionEntry);
+ if (!crlGenData->extensionEntry) {
+ return SECFailure;
+ }
+ crlGenData->contextId = structType;
+ crlGenData->extensionEntry->extData = NULL;
+ crlGenData->extensionEntry->nextUpdatedData = 0;
+ crlGenData->extensionEntry->updateCrlFn =
+ &crlgen_updateCrlFn_extension;
+ crlGenData->extensionEntry->setNextDataFn =
+ &crlgen_setNextDataFn_extension;
+ break;
+ case CRLGEN_UNKNOWN_CONTEXT:
+ break;
+ default:
+ crlgen_PrintError(crlGenData->parsedLineNum,
+ "unknown context type: %d.\n", structType);
+ PORT_Assert(0);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/* Parser initialization function */
+CRLGENGeneratorData *
+CRLGEN_InitCrlGeneration(CERTSignedCrl *signCrl, PRFileDesc *src)
+{
+ CRLGENGeneratorData *crlGenData = NULL;
+
+ PORT_Assert(signCrl && src);
+ if (!signCrl || !src) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ crlGenData = PORT_ZNew(CRLGENGeneratorData);
+ if (!crlGenData) {
+ return NULL;
+ }
+
+ crlGenData->entryDataHashTable =
+ PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ PL_CompareValues, NULL, NULL);
+ if (!crlGenData->entryDataHashTable) {
+ PORT_Free(crlGenData);
+ return NULL;
+ }
+
+ crlGenData->src = src;
+ crlGenData->parsedLineNum = 1;
+ crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
+ crlGenData->signCrl = signCrl;
+ crlGenData->rangeFrom = 0;
+ crlGenData->rangeTo = 0;
+ crlGenData->crlExtHandle = NULL;
+
+ PORT_SetError(0);
+
+ return crlGenData;
+}
+
+void
+CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData *crlGenData)
+{
+ if (!crlGenData)
+ return;
+ if (crlGenData->src)
+ PR_Close(crlGenData->src);
+ PL_HashTableDestroy(crlGenData->entryDataHashTable);
+ PORT_Free(crlGenData);
+}