| /* 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, ¤t->name.directoryName, directoryName); |
| CERT_DestroyName(directoryName); |
| |
| break; |
| } |
| } |
| if (rv != SECSuccess) |
| break; |
| current->l.next = &(namesList->l); |
| current->l.prev = &(tail->l); |
| tail->l.next = &(current->l); |
| tail = current; |
| |
| } while (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 = ¤t->l; |
| current->l.prev = ¤t->l; |
| |
| directoryName = CERT_AsciiToName((char *)data); |
| if (!directoryName) { |
| goto loser; |
| } |
| |
| rv = CERT_CopyName(arena, ¤t->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); |
| } |