mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 03:30:17 +01:00
44b7f056d9
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
1559 lines
46 KiB
C
1559 lines
46 KiB
C
/* 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;
|
|
|
|
if (!crlGenData->entryDataHashTable)
|
|
return SECSuccess;
|
|
data = crlgen_FindEntry(crlGenData, certId);
|
|
if (!data)
|
|
return SECSuccess;
|
|
if (PL_HashTableRemove(crlGenData->entryDataHashTable, certId))
|
|
return SECSuccess;
|
|
destroyEntryData(data);
|
|
return SECFailure;
|
|
}
|
|
|
|
|
|
/* 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 *extHandle = crlGenData->crlExtHandle;
|
|
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 (extHandle, 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);
|
|
}
|
|
|