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