summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralexei.volkov.bugs%sun.com <devnull@localhost>2005-04-12 02:24:17 +0000
committeralexei.volkov.bugs%sun.com <devnull@localhost>2005-04-12 02:24:17 +0000
commit2cfda9af6243e32d9d2915050874c9adaef2c226 (patch)
treeab1fc11b985836f8bab81a03ca32af82499a5157
parent9fc79613b23fba0541ff45bff78dee8f94bb03b5 (diff)
downloadnss-hg-2cfda9af6243e32d9d2915050874c9adaef2c226.tar.gz
Fix for bug 265003: Add CRL generation to crlutil. Reviewed JP+
-rw-r--r--security/nss/cmd/certutil/certutil.c116
-rw-r--r--security/nss/cmd/crlutil/Makefile9
-rw-r--r--security/nss/cmd/crlutil/crlgen.c1627
-rw-r--r--security/nss/cmd/crlutil/crlgen.h182
-rw-r--r--security/nss/cmd/crlutil/crlgen_lex.c1783
-rw-r--r--security/nss/cmd/crlutil/crlgen_lex_fix.sed4
-rw-r--r--security/nss/cmd/crlutil/crlgen_lex_orig.l177
-rw-r--r--security/nss/cmd/crlutil/crlutil.c570
-rw-r--r--security/nss/cmd/crlutil/manifest.mn2
-rw-r--r--security/nss/cmd/lib/secutil.c331
-rw-r--r--security/nss/cmd/lib/secutil.h71
-rw-r--r--security/nss/lib/certdb/certt.h2
-rw-r--r--security/nss/lib/certdb/crl.c16
-rw-r--r--security/nss/lib/nss/nss.def2
-rwxr-xr-xsecurity/nss/tests/cert/cert.sh155
-rw-r--r--security/nss/tests/common/init.sh24
-rwxr-xr-xsecurity/nss/tests/ssl/ssl.sh270
17 files changed, 5210 insertions, 131 deletions
diff --git a/security/nss/cmd/certutil/certutil.c b/security/nss/cmd/certutil/certutil.c
index a1fe09ea8..b26b5b7ca 100644
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -110,13 +110,15 @@ GetGeneralName (PRArenaPool *arena)
PORT_SetError(SEC_ERROR_INPUT_LEN);
GEN_BREAK (SECFailure);
}
+ /*
+ * Should use ZAlloc instead of Alloc to avoid problem with garbage
+ * initialized pointers in CERT_CopyName
+ */
if (intValue >= certOtherName || intValue <= certRegisterID) {
if (namesList == NULL) {
- namesList = current = tail = (CERTGeneralName *) PORT_ArenaAlloc
- (arena, sizeof (CERTGeneralName));
+ namesList = current = tail = PORT_ArenaZNew(arena, CERTGeneralName);
} else {
- current = (CERTGeneralName *) PORT_ArenaAlloc(arena,
- sizeof (CERTGeneralName));
+ current = PORT_ArenaZNew(arena, CERTGeneralName);
}
if (current == NULL) {
GEN_BREAK (SECFailure);
@@ -356,53 +358,6 @@ AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts,
return rv;
}
-/* This function belongs in libNSS somewhere. */
-static SECOidTag
-getSignatureOidTag(KeyType keyType, SECOidTag hashAlgTag)
-{
- SECOidTag sigTag = SEC_OID_UNKNOWN;
-
- switch (keyType) {
- case rsaKey:
- switch (hashAlgTag) {
- case SEC_OID_MD2:
- sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; break;
- case SEC_OID_UNKNOWN: /* default for RSA if not specified */
- case SEC_OID_MD5:
- sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; break;
- case SEC_OID_SHA1:
- sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break;
- case SEC_OID_SHA256:
- sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break;
- case SEC_OID_SHA384:
- sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break;
- case SEC_OID_SHA512:
- sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break;
- default:
- break;
- }
- break;
- case dsaKey:
- switch (hashAlgTag) {
- case SEC_OID_UNKNOWN: /* default for DSA if not specified */
- case SEC_OID_SHA1:
- sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break;
- default:
- break;
- }
- break;
-#ifdef NSS_ENABLE_ECC
- case ecKey:
- /* XXX For now only ECDSA with SHA1 is supported */
- sigTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
- break;
-#endif /* NSS_ENABLE_ECC */
- default:
- break;
- }
- return sigTag;
-}
-
static SECStatus
AddExtensions(void *, const char *, const char *, PRBool, PRBool, PRBool, PRBool,
PRBool, PRBool);
@@ -472,7 +427,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
}
/* Sign the request */
- signAlgTag = getSignatureOidTag(keyType, hashAlgTag);
+ signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
if (signAlgTag == SEC_OID_UNKNOWN) {
SECU_PrintError(progName, "unknown Key or Hash type");
return SECFailure;
@@ -1799,36 +1754,6 @@ AddDNSSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp,
}
-typedef SECStatus (* EXTEN_VALUE_ENCODER)
- (PRArenaPool *extHandle, void *value, SECItem *encodedValue);
-
-static SECStatus
-EncodeAndAddExtensionValue(
- PRArenaPool * arena,
- void * extHandle,
- void * value,
- PRBool criticality,
- int extenType,
- EXTEN_VALUE_ENCODER EncodeValueFn)
-{
- SECItem encodedValue;
- SECStatus rv;
-
-
- encodedValue.data = NULL;
- encodedValue.len = 0;
- do {
- rv = (*EncodeValueFn)(arena, value, &encodedValue);
- if (rv != SECSuccess)
- break;
-
- rv = CERT_AddExtension
- (extHandle, extenType, &encodedValue, criticality,PR_TRUE);
- } while (0);
-
- return (rv);
-}
-
static SECStatus
AddBasicConstraint(void *extHandle)
{
@@ -1898,7 +1823,7 @@ SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
arena = cert->arena;
- algID = getSignatureOidTag(privKey->keyType, hashAlgTag);
+ algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
if (algID == SEC_OID_UNKNOWN) {
fprintf(stderr, "Unknown key or hash type for issuer.");
goto done;
@@ -1983,11 +1908,11 @@ AddAuthKeyID (void *extHandle)
puts ("Is this a critical extension [y/n]? ");
gets (buffer);
- rv = EncodeAndAddExtensionValue
+ rv = SECU_EncodeAndAddExtensionValue
(arena, extHandle, authKeyID,
(buffer[0] == 'y' || buffer[0] == 'Y') ? PR_TRUE : PR_FALSE,
SEC_OID_X509_AUTH_KEY_ID,
- (EXTEN_VALUE_ENCODER) CERT_EncodeAuthKeyID);
+ (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID);
if (rv)
break;
@@ -2106,10 +2031,10 @@ AddCrlDistPoint(void *extHandle)
puts ("Is this a critical extension [y/n]? ");
gets (buffer);
- rv = EncodeAndAddExtensionValue(arena, extHandle, crlDistPoints,
+ rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, crlDistPoints,
(buffer[0] == 'Y' || buffer[0] == 'y') ? PR_TRUE : PR_FALSE,
SEC_OID_X509_CRL_DIST_POINTS,
- (EXTEN_VALUE_ENCODER) CERT_EncodeCRLDistributionPoints);
+ (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeCRLDistributionPoints);
}
if (arena)
PORT_FreeArena (arena, PR_FALSE);
@@ -2514,21 +2439,8 @@ secuCommandFlag certutil_options[] =
/* -Z hash type */
if (certutil.options[opt_Hash].activated) {
char * arg = certutil.options[opt_Hash].arg;
- if (!PL_strcmp(arg, "MD2")) {
- hashAlgTag = SEC_OID_MD2;
- } else if (!PL_strcmp(arg, "MD4")) {
- hashAlgTag = SEC_OID_MD4;
- } else if (!PL_strcmp(arg, "MD5")) {
- hashAlgTag = SEC_OID_MD5;
- } else if (!PL_strcmp(arg, "SHA1")) {
- hashAlgTag = SEC_OID_SHA1;
- } else if (!PL_strcmp(arg, "SHA256")) {
- hashAlgTag = SEC_OID_SHA256;
- } else if (!PL_strcmp(arg, "SHA384")) {
- hashAlgTag = SEC_OID_SHA384;
- } else if (!PL_strcmp(arg, "SHA512")) {
- hashAlgTag = SEC_OID_SHA512;
- } else {
+ hashAlgTag = SECU_StringToSignatureAlgTag(arg);
+ if (hashAlgTag == SEC_OID_UNKNOWN) {
PR_fprintf(PR_STDERR, "%s -Z: %s is not a recognized type.\n",
progName, arg);
return 255;
diff --git a/security/nss/cmd/crlutil/Makefile b/security/nss/cmd/crlutil/Makefile
index 140b4191f..0f01f4c47 100644
--- a/security/nss/cmd/crlutil/Makefile
+++ b/security/nss/cmd/crlutil/Makefile
@@ -74,7 +74,12 @@ include $(CORE_DEPTH)/coreconf/rules.mk
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
-
+#
+# crlgen_lex can be generated on linux by flex or solaris by lex
+#
+crlgen_lex:
+ ${LEX} -t crlgen_lex_orig.l > crlgen_lex_fix.c
+ sed -f crlgen_lex_fix.sed < crlgen_lex_fix.c > crlgen_lex.c
+ rm -f crlgen_lex_fix.c
include ../platrules.mk
-
diff --git a/security/nss/cmd/crlutil/crlgen.c b/security/nss/cmd/crlutil/crlgen.c
new file mode 100644
index 000000000..def866090
--- /dev/null
+++ b/security/nss/cmd/crlutil/crlgen.c
@@ -0,0 +1,1627 @@
+/*
+ * The contents of this file are subject to the Maxilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+** 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"
+
+
+/* these reroutines were taken from secitem.c, which is supposed to
+ * replace this file some day */
+/*
+ * This is the hash function. We simply XOR the encoded form with
+ * itself in sizeof(PLHashNumber)-byte chunks. Improving this
+ * routine is left as an excercise for the more mathematically
+ * inclined student.
+ */
+PLHashNumber PR_CALLBACK
+SECITEM_Hash ( const void *key)
+{
+ const SECItem *item = (const SECItem *)key;
+ PLHashNumber rv = 0;
+
+ PRUint8 *data = (PRUint8 *)item->data;
+ PRUint32 i;
+ PRUint8 *rvc = (PRUint8 *)&rv;
+
+ for( i = 0; i < item->len; i++ ) {
+ rvc[ i % sizeof(rv) ] ^= *data;
+ data++;
+ }
+
+ return rv;
+}
+
+/*
+ * This is the key-compare function. It simply does a lexical
+ * comparison on the item data. This does not result in
+ * quite the same ordering as the "sequence of numbers" order,
+ * but heck it's only used internally by the hash table anyway.
+ */
+PRIntn PR_CALLBACK
+SECITEM_HashCompare ( const void *k1, const void *k2)
+{
+ const SECItem *i1 = (const SECItem *)k1;
+ const SECItem *i2 = (const SECItem *)k2;
+
+ return SECITEM_ItemsAreEqual(i1,i2);
+}
+
+/* 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(PRArenaPool *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 (PRArenaPool *arena, CRLGENGeneratorData *crlGenData,
+ const char *data)
+{
+ CERTGeneralName *namesList = NULL;
+ CERTGeneralName *current;
+ CERTGeneralName *tail = NULL;
+ SECStatus rv = SECSuccess;
+ const char *nextChunk = NULL;
+ const char *currData = NULL;
+ int intValue;
+ char buffer[512];
+ void *mark;
+
+ if (!data)
+ return NULL;
+ PORT_Assert (arena);
+ if (!arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ mark = PORT_ArenaMark (arena);
+
+ nextChunk = data;
+ currData = data;
+ do {
+ int nameLen = 0;
+ char name[128];
+ const char *sepPrt = NULL;
+ nextChunk = PORT_Strchr(currData, '|');
+ if (!nextChunk)
+ nextChunk = data + strlen(data);
+ sepPrt = PORT_Strchr(currData, ':');
+ if (sepPrt == NULL || sepPrt >= nextChunk) {
+ *buffer = '\0';
+ sepPrt = nextChunk;
+ } else {
+ PORT_Memcpy(buffer, sepPrt + 1,
+ (nextChunk - sepPrt - 1));
+ buffer[nextChunk - sepPrt - 1] = '\0';
+ }
+ nameLen = PR_MIN(sepPrt - currData, sizeof(name) - 1 );
+ PORT_Memcpy(name, currData, nameLen);
+ name[nameLen] = '\0';
+ currData = nextChunk + 1;
+
+ if (!PORT_Strcmp(name, "otherName"))
+ intValue = certOtherName;
+ else if (!PORT_Strcmp(name, "rfc822Name"))
+ intValue = certRFC822Name;
+ else if (!PORT_Strcmp(name, "dnsName"))
+ intValue = certDNSName;
+ else if (!PORT_Strcmp(name, "x400Address"))
+ intValue = certX400Address;
+ else if (!PORT_Strcmp(name, "directoryName"))
+ intValue = certDirectoryName;
+ else if (!PORT_Strcmp(name, "ediPartyName"))
+ intValue = certEDIPartyName;
+ else if (!PORT_Strcmp(name, "URI"))
+ intValue = certURI;
+ else if (!PORT_Strcmp(name, "ipAddress"))
+ intValue = certIPAddress;
+ else if (!PORT_Strcmp(name, "registerID"))
+ intValue = certRegisterID;
+ else intValue = -1;
+
+ if (intValue >= certOtherName && intValue <= certRegisterID) {
+ if (namesList == NULL) {
+ namesList = current = tail = PORT_ArenaZNew(arena,
+ CERTGeneralName);
+ } else {
+ current = PORT_ArenaZNew(arena, CERTGeneralName);
+ }
+ if (current == NULL) {
+ rv = SECFailure;
+ break;
+ }
+ } else {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ break;
+ }
+ current->type = intValue;
+ switch (current->type) {
+ case certURI:
+ case certDNSName:
+ case certRFC822Name:
+ current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer));
+ if (current->name.other.data == NULL) {
+ rv = SECFailure;
+ break;
+ }
+ PORT_Memcpy(current->name.other.data, buffer,
+ current->name.other.len = strlen(buffer));
+ break;
+
+ case certEDIPartyName:
+ case certIPAddress:
+ case certOtherName:
+ case certRegisterID:
+ case certX400Address: {
+
+ current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer) + 2);
+ if (current->name.other.data == NULL) {
+ rv = SECFailure;
+ break;
+ }
+
+ PORT_Memcpy (current->name.other.data + 2, buffer, strlen (buffer));
+/* This may not be accurate for all cases.For now, use this tag type */
+ current->name.other.data[0] = (char)(((current->type - 1) & 0x1f)| 0x80);
+ current->name.other.data[1] = (char)strlen (buffer);
+ current->name.other.len = strlen (buffer) + 2;
+ break;
+ }
+
+ case certDirectoryName: {
+ CERTName *directoryName = NULL;
+
+ directoryName = CERT_AsciiToName (buffer);
+ if (!directoryName) {
+ rv = SECFailure;
+ break;
+ }
+
+ rv = CERT_CopyName (arena, &current->name.directoryName, directoryName);
+ CERT_DestroyName (directoryName);
+
+ break;
+ }
+ }
+ if (rv != SECSuccess)
+ break;
+ current->l.next = &(namesList->l);
+ current->l.prev = &(tail->l);
+ tail->l.next = &(current->l);
+ tail = current;
+
+ } while(nextChunk != data + strlen(data));
+
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease (arena, mark);
+ namesList = NULL;
+ }
+ return (namesList);
+}
+
+/* Creates CERTGeneralName from parsed data for the Authority Key Extension */
+static CERTGeneralName *
+crlgen_DistinguishedName (PRArenaPool *arena, CRLGENGeneratorData *crlGenData,
+ const char *data)
+{
+ CERTName *directoryName = NULL;
+ CERTGeneralName *current;
+ SECStatus rv = SECFailure;
+ void *mark;
+
+ if (!data)
+ return NULL;
+ PORT_Assert (arena);
+ if (!arena) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ mark = PORT_ArenaMark (arena);
+
+ current = PORT_ArenaZNew(arena, CERTGeneralName);
+ if (current == NULL) {
+ goto loser;
+ }
+ current->type = certDirectoryName;
+ current->l.next = &current->l;
+ current->l.prev = &current->l;
+
+ directoryName = CERT_AsciiToName ((char*)data);
+ if (!directoryName) {
+ goto loser;
+ }
+
+ rv = CERT_CopyName (arena, &current->name.directoryName, directoryName);
+ CERT_DestroyName (directoryName);
+
+ loser:
+ if (rv != SECSuccess) {
+ PORT_SetError (rv);
+ PORT_ArenaRelease (arena, mark);
+ current = NULL;
+ }
+ return (current);
+}
+
+
+/* Adding Authority Key ID extension to extension handle. */
+static SECStatus
+crlgen_AddAuthKeyID (CRLGENGeneratorData *crlGenData,
+ const char **dataArr)
+{
+ void *extHandle = NULL;
+ CERTAuthKeyID *authKeyID = NULL;
+ PRArenaPool *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;
+ PRArenaPool *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)
+{
+ PRArenaPool *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(PRArenaPool *arena, const char **dataArr,
+ int *extCode)
+{
+ SECItem *encodedItem;
+ void *dummy;
+ void *mark;
+ 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:
+ PORT_ArenaRelease (arena, mark);
+ return NULL;
+}
+
+/* Creates Cert Invalidity Date extension. Encodes it and
+ * returns as SECItem structure */
+static SECItem*
+crlgen_CreateInvalidityDate(PRArenaPool *arena, const char **dataArr,
+ int *extCode)
+{
+ SECItem *encodedItem;
+ int length = 0;
+ void *mark;
+
+ 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:
+ 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)(PRArenaPool *arena,
+ const char **dataArr,
+ int *extCode))
+{
+ PRUint64 i = 0;
+ SECStatus rv = SECFailure;
+ int extCode = 0;
+ PRUint64 lastRange ;
+ SECItem *ext = NULL;
+ PRArenaPool *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;
+ PRArenaPool *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;
+ PRArenaPool *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;
+ PRArenaPool *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;
+ PRArenaPool *arena;
+
+ PORT_Assert(crlGenData && certId);
+ if (!crlGenData || !certId) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ arena = crlGenData->signCrl->arena;
+
+ 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_ZAlloc(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->nextUpdatedData) {
+ 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);
+}
+
diff --git a/security/nss/cmd/crlutil/crlgen.h b/security/nss/cmd/crlutil/crlgen.h
new file mode 100644
index 000000000..4eb5304e3
--- /dev/null
+++ b/security/nss/cmd/crlutil/crlgen.h
@@ -0,0 +1,182 @@
+
+#ifndef _CRLGEN_H_
+#define _CRLGEN_H_
+
+#include "prio.h"
+#include "prprf.h"
+#include "plhash.h"
+#include "seccomon.h"
+#include "certt.h"
+#include "secoidt.h"
+
+
+#define CRLGEN_UNKNOWN_CONTEXT 0
+#define CRLGEN_ISSUER_CONTEXT 1
+#define CRLGEN_UPDATE_CONTEXT 2
+#define CRLGEN_NEXT_UPDATE_CONTEXT 3
+#define CRLGEN_ADD_EXTENSION_CONTEXT 4
+#define CRLGEN_ADD_CERT_CONTEXT 6
+#define CRLGEN_CHANGE_RANGE_CONTEXT 7
+#define CRLGEN_RM_CERT_CONTEXT 8
+
+#define CRLGEN_TYPE_DATE 0
+#define CRLGEN_TYPE_ZDATE 1
+#define CRLGEN_TYPE_DIGIT 2
+#define CRLGEN_TYPE_DIGIT_RANGE 3
+#define CRLGEN_TYPE_OID 4
+#define CRLGEN_TYPE_STRING 5
+#define CRLGEN_TYPE_ID 6
+
+
+typedef struct CRLGENGeneratorDataStr CRLGENGeneratorData;
+typedef struct CRLGENEntryDataStr CRLGENEntryData;
+typedef struct CRLGENExtensionEntryStr CRLGENExtensionEntry;
+typedef struct CRLGENCertEntrySrt CRLGENCertEntry;
+typedef struct CRLGENCrlFieldStr CRLGENCrlField;
+typedef struct CRLGENEntriesSortedDataStr CRLGENEntriesSortedData;
+
+/* Exported functions */
+
+/* Used for initialization of extension handles for crl and certs
+ * extensions from existing CRL data then modifying existing CRL.*/
+extern SECStatus CRLGEN_ExtHandleInit(CRLGENGeneratorData *crlGenData);
+
+/* Commits all added entries and their's extensions into CRL. */
+extern SECStatus CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData *crlGenData);
+
+/* Lunches the crl generation script parse */
+extern SECStatus CRLGEN_StartCrlGen(CRLGENGeneratorData *crlGenData);
+
+/* Closes crl generation script file and frees crlGenData */
+extern void CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData *crlGenData);
+
+/* Parser initialization function. Creates CRLGENGeneratorData structure
+ * for the current thread */
+extern CRLGENGeneratorData* CRLGEN_InitCrlGeneration(CERTSignedCrl *newCrl,
+ PRFileDesc *src);
+
+
+/* This lock is defined in crlgen_lex.c(derived from crlgen_lex.l).
+ * It controls access to invocation of yylex, allows to parse one
+ * script at a time */
+extern void CRLGEN_InitCrlGenParserLock();
+extern void CRLGEN_DestroyCrlGenParserLock();
+
+
+/* The following function types are used to define functions for each of
+ * CRLGENExtensionEntryStr, CRLGENCertEntrySrt, CRLGENCrlFieldStr to
+ * provide functionality needed for these structures*/
+typedef SECStatus updateCrlFn_t(CRLGENGeneratorData *crlGenData, void *str);
+typedef SECStatus setNextDataFn_t(CRLGENGeneratorData *crlGenData, void *str,
+ void *data, unsigned short dtype);
+typedef SECStatus createNewLangStructFn_t(CRLGENGeneratorData *crlGenData,
+ void *str, unsigned i);
+
+/* Sets reports failure to parser if anything goes wrong */
+extern void crlgen_setFailure(CRLGENGeneratorData *str, char *);
+
+/* Collects data in to one of the current data structure that corresponds
+ * to the correct context type. This function gets called after each token
+ * is found for a particular line */
+extern SECStatus crlgen_setNextData(CRLGENGeneratorData *str, void *data,
+ unsigned short dtype);
+
+/* initiates crl update with collected data. This function is called at the
+ * end of each line */
+extern SECStatus crlgen_updateCrl(CRLGENGeneratorData *str);
+
+/* Creates new context structure depending on token that was parsed
+ * at the beginning of a line */
+extern SECStatus crlgen_createNewLangStruct(CRLGENGeneratorData *str,
+ unsigned structType);
+
+
+/* CRLGENExtensionEntry is used to store addext request data for either
+ * CRL extensions or CRL entry extensions. The differentiation between
+ * is based on order and type of extension been added.
+ * - extData : all data in request staring from name of the extension are
+ * in saved here.
+ * - nextUpdatedData: counter of elements added to extData
+ */
+struct CRLGENExtensionEntryStr {
+ char **extData;
+ int nextUpdatedData;
+ updateCrlFn_t *updateCrlFn;
+ setNextDataFn_t *setNextDataFn;
+};
+
+/* CRLGENCeryestEntry is used to store addcert request data
+ * - certId : certificate id or range of certificate with dash as a delimiter
+ * All certs from range will be inclusively added to crl
+ * - revocationTime: revocation time of cert(s)
+ */
+struct CRLGENCertEntrySrt {
+ char *certId;
+ char *revocationTime;
+ updateCrlFn_t *updateCrlFn;
+ setNextDataFn_t *setNextDataFn;
+};
+
+
+/* CRLGENCrlField is used to store crl fields record like update time, next
+ * update time, etc.
+ * - value: value of the parsed field data*/
+struct CRLGENCrlFieldStr {
+ char *value;
+ updateCrlFn_t *updateCrlFn;
+ setNextDataFn_t *setNextDataFn;
+};
+
+/* Can not create entries extension until completely done with parsing.
+ * Therefore need to keep joined data
+ * - certId : serial number of certificate
+ * - extHandle: head pointer to a list of extensions that belong to
+ * entry
+ * - entry : CERTCrlEntry structure pointer*/
+struct CRLGENEntryDataStr {
+ SECItem *certId;
+ void *extHandle;
+ CERTCrlEntry *entry;
+};
+
+/* Crl generator/parser main structure. Keeps info regarding current state of
+ * parser(context, status), parser helper functions pointers, parsed data and
+ * generated data.
+ * - contextId : current parsing context. Context in this parser environment
+ * defines what type of crl operations parser is going through
+ * in the current line of crl generation script.
+ * setting or new cert or an extension addition, etc.
+ * - createNewLangStructFn: pointer to top level function which creates
+ * data structures according contextId
+ * - setNextDataFn : pointer to top level function which sets new parsed data
+ * in temporary structure
+ * - updateCrlFn : pointer to top level function which triggers actual
+ * crl update functions with gathered data
+ * - union : data union create according to contextId
+ * - rangeFrom, rangeTo : holds last range in which certs was added
+ * - newCrl : pointer to CERTSignedCrl newly created crl
+ * - crlExtHandle : pointer to crl extension handle
+ * - entryDataHashTable: hash of CRLGENEntryData.
+ * key: cert serial number
+ * data: CRLGENEntryData pointer
+ * - parserStatus : current status of parser. Triggers parser to abort when
+ * set to SECFailure
+ * - src : PRFileDesc structure pointer of crl generator config file
+ * - parsedLineNum : currently parsing line. Keeping it to report errors */
+struct CRLGENGeneratorDataStr {
+ unsigned short contextId;
+ CRLGENCrlField *crlField;
+ CRLGENCertEntry *certEntry;
+ CRLGENExtensionEntry *extensionEntry;
+ PRUint64 rangeFrom;
+ PRUint64 rangeTo;
+ CERTSignedCrl *signCrl;
+ void *crlExtHandle;
+ PLHashTable *entryDataHashTable;
+
+ PRFileDesc *src;
+ int parsedLineNum;
+};
+
+
+#endif /* _CRLGEN_H_ */
diff --git a/security/nss/cmd/crlutil/crlgen_lex.c b/security/nss/cmd/crlutil/crlgen_lex.c
new file mode 100644
index 000000000..26a888d60
--- /dev/null
+++ b/security/nss/cmd/crlutil/crlgen_lex.c
@@ -0,0 +1,1783 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yytext_ptr -= yy_more_len; \
+ yyleng = (int) (yy_cp - yytext_ptr); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 17
+#define YY_END_OF_BUFFER 18
+static yyconst short int yy_accept[67] =
+ { 0,
+ 0, 0, 18, 16, 14, 15, 16, 11, 12, 2,
+ 10, 9, 9, 9, 9, 9, 13, 14, 15, 11,
+ 12, 0, 12, 2, 9, 9, 9, 9, 9, 13,
+ 3, 4, 2, 9, 9, 9, 9, 2, 9, 9,
+ 9, 9, 2, 2, 9, 9, 8, 9, 2, 5,
+ 9, 6, 2, 9, 2, 9, 2, 9, 2, 7,
+ 2, 2, 2, 2, 1, 0
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 5, 6, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 7, 8, 1, 9, 9, 10,
+ 11, 12, 12, 12, 13, 13, 13, 14, 1, 1,
+ 15, 1, 1, 1, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 17,
+ 1, 1, 1, 1, 1, 1, 18, 16, 16, 19,
+
+ 20, 16, 21, 16, 22, 16, 16, 16, 16, 23,
+ 16, 24, 16, 25, 26, 27, 28, 16, 16, 29,
+ 16, 16, 1, 14, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[30] =
+ { 0,
+ 1, 1, 2, 1, 3, 1, 1, 4, 5, 5,
+ 5, 5, 5, 4, 1, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4
+ } ;
+
+static yyconst short int yy_base[72] =
+ { 0,
+ 0, 149, 154, 205, 138, 205, 103, 0, 0, 23,
+ 205, 29, 30, 31, 32, 33, 0, 99, 205, 0,
+ 0, 0, 50, 55, 34, 61, 41, 63, 64, 0,
+ 0, 0, 79, 65, 68, 86, 66, 99, 105, 88,
+ 106, 90, 118, 76, 107, 110, 89, 125, 43, 91,
+ 127, 128, 138, 144, 113, 129, 154, 160, 160, 130,
+ 172, 166, 177, 144, 0, 205, 190, 192, 194, 199,
+ 76
+ } ;
+
+static yyconst short int yy_def[72] =
+ { 0,
+ 66, 1, 66, 66, 66, 66, 66, 67, 68, 68,
+ 66, 69, 69, 69, 69, 69, 70, 66, 66, 67,
+ 68, 71, 68, 10, 69, 69, 69, 69, 69, 70,
+ 71, 23, 10, 69, 69, 69, 69, 10, 69, 69,
+ 69, 69, 10, 38, 69, 69, 69, 69, 38, 69,
+ 69, 69, 38, 69, 38, 69, 38, 69, 38, 69,
+ 38, 38, 38, 38, 68, 0, 66, 66, 66, 66,
+ 66
+ } ;
+
+static yyconst short int yy_nxt[235] =
+ { 0,
+ 4, 5, 6, 7, 8, 4, 4, 9, 10, 10,
+ 10, 10, 10, 9, 11, 12, 12, 12, 12, 12,
+ 12, 13, 14, 12, 15, 12, 12, 16, 12, 22,
+ 23, 24, 24, 24, 24, 24, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 28,
+ 27, 53, 53, 53, 21, 26, 29, 32, 32, 32,
+ 32, 32, 32, 33, 33, 33, 33, 33, 21, 35,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 31, 21, 37, 42, 44, 36, 34, 38, 38, 38,
+ 38, 38, 39, 21, 40, 21, 21, 21, 21, 21,
+
+ 18, 21, 21, 21, 21, 19, 41, 43, 44, 44,
+ 44, 44, 21, 21, 21, 46, 48, 21, 21, 21,
+ 21, 57, 57, 21, 45, 47, 49, 49, 49, 49,
+ 49, 50, 21, 51, 21, 21, 21, 21, 21, 18,
+ 21, 21, 21, 21, 52, 54, 55, 55, 55, 55,
+ 55, 21, 44, 66, 17, 58, 66, 21, 66, 66,
+ 65, 56, 59, 59, 59, 59, 59, 21, 61, 61,
+ 61, 61, 66, 21, 63, 63, 63, 63, 66, 60,
+ 62, 62, 62, 62, 62, 64, 64, 64, 64, 64,
+ 20, 20, 66, 20, 20, 21, 21, 25, 25, 30,
+
+ 66, 30, 30, 30, 3, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66
+ } ;
+
+static yyconst short int yy_chk[235] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 10,
+ 10, 10, 10, 10, 10, 10, 12, 13, 14, 15,
+ 16, 25, 12, 13, 14, 15, 16, 25, 27, 15,
+ 14, 49, 49, 49, 27, 13, 16, 23, 23, 23,
+ 23, 23, 23, 24, 24, 24, 24, 24, 26, 27,
+ 28, 29, 34, 37, 26, 35, 28, 29, 34, 37,
+ 71, 35, 29, 37, 44, 28, 26, 33, 33, 33,
+ 33, 33, 34, 36, 35, 40, 47, 42, 50, 36,
+
+ 18, 40, 47, 42, 50, 7, 36, 38, 38, 38,
+ 38, 38, 39, 41, 45, 40, 42, 46, 39, 41,
+ 45, 55, 55, 46, 39, 41, 43, 43, 43, 43,
+ 43, 45, 48, 46, 51, 52, 56, 60, 48, 5,
+ 51, 52, 56, 60, 48, 51, 53, 53, 53, 53,
+ 53, 54, 64, 3, 2, 56, 0, 54, 0, 0,
+ 64, 54, 57, 57, 57, 57, 57, 58, 59, 59,
+ 59, 59, 0, 58, 62, 62, 62, 62, 0, 58,
+ 61, 61, 61, 61, 61, 63, 63, 63, 63, 63,
+ 67, 67, 0, 67, 67, 68, 68, 69, 69, 70,
+
+ 0, 70, 70, 70, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+static int yy_more_flag = 0;
+static int yy_more_len = 0;
+#define yymore() (yy_more_flag = 1)
+#define YY_MORE_ADJ yy_more_len
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "crlgen_lex_orig.l"
+#define INITIAL 0
+#line 2 "crlgen_lex_orig.l"
+
+#include "crlgen.h"
+
+static SECStatus parserStatus = SECSuccess;
+static CRLGENGeneratorData *parserData;
+static PRFileDesc *src;
+
+#define YY_INPUT(buf,result,max_size) \
+ if ( parserStatus != SECFailure) { \
+ if (((result = PR_Read(src, buf, max_size)) == 0) && \
+ ferror( yyin )) \
+ return SECFailure; \
+ } else { return SECFailure; }
+
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ yy_current_buffer->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp = NULL, *yy_bp = NULL;
+ register int yy_act;
+
+#line 28 "crlgen_lex_orig.l"
+
+
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_more_len = 0;
+ if ( yy_more_flag )
+ {
+ yy_more_len = yy_c_buf_p - yytext_ptr;
+ yy_more_flag = 0;
+ }
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 67 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 205 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 30 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_ZDATE);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 36 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_DIGIT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 42 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_DIGIT_RANGE);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 48 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_OID);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 54 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_ISSUER_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 60 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_UPDATE_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 65 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_NEXT_UPDATE_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 71 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_CHANGE_RANGE_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 77 "crlgen_lex_orig.l"
+{
+if (strcmp(yytext, "addcert") == 0) {
+ parserStatus = crlgen_createNewLangStruct(parserData,
+ CRLGEN_ADD_CERT_CONTEXT);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+} else if (strcmp(yytext, "rmcert") == 0) {
+ parserStatus = crlgen_createNewLangStruct(parserData,
+ CRLGEN_RM_CERT_CONTEXT);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+} else if (strcmp(yytext, "addext") == 0) {
+ parserStatus = crlgen_createNewLangStruct(parserData,
+ CRLGEN_ADD_EXTENSION_CONTEXT);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+} else {
+ parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_ID);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+}
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 100 "crlgen_lex_orig.l"
+
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 102 "crlgen_lex_orig.l"
+{
+if (yytext[yyleng-1] == '\\') {
+ yymore();
+} else {
+ register int c;
+ c = input();
+ if (c != '\"') {
+ printf( "Error: Line ending \" is missing: %c\n", c);
+ unput(c);
+ } else {
+ parserStatus = crlgen_setNextData(parserData, yytext + 1,
+ CRLGEN_TYPE_STRING);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+ }
+}
+}
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 120 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_STRING);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 128 "crlgen_lex_orig.l"
+/* eat up one-line comments */ {}
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 130 "crlgen_lex_orig.l"
+{}
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 132 "crlgen_lex_orig.l"
+{
+parserStatus = crlgen_updateCrl(parserData);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 138 "crlgen_lex_orig.l"
+{
+ fprintf(stderr, "Syntax error at line %d: unknown token %s\n",
+ parserData->parsedLineNum, yytext);
+ return SECFailure;
+}
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 144 "crlgen_lex_orig.l"
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 67 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 67 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 66);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ yy_current_buffer->yy_at_bol = (c == '\n');
+
+ return c;
+ }
+#endif /* YY_NO_INPUT */
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 144 "crlgen_lex_orig.l"
+
+#include "prlock.h"
+
+static PRLock *parserInvocationLock;
+
+void CRLGEN_InitCrlGenParserLock()
+{
+ parserInvocationLock = PR_NewLock();
+}
+
+void CRLGEN_DestroyCrlGenParserLock()
+{
+ PR_DestroyLock(parserInvocationLock);
+}
+
+
+SECStatus CRLGEN_StartCrlGen(CRLGENGeneratorData *parserCtlData)
+{
+ SECStatus rv;
+
+ PR_Lock(parserInvocationLock);
+
+ parserStatus = SECSuccess;
+ parserData = parserCtlData;
+ src = parserCtlData->src;
+
+ rv = yylex();
+
+ PR_Unlock(parserInvocationLock);
+
+ return rv;
+}
+
+int yywrap() {return 1;}
diff --git a/security/nss/cmd/crlutil/crlgen_lex_fix.sed b/security/nss/cmd/crlutil/crlgen_lex_fix.sed
new file mode 100644
index 000000000..57125cd4a
--- /dev/null
+++ b/security/nss/cmd/crlutil/crlgen_lex_fix.sed
@@ -0,0 +1,4 @@
+/<unistd.h>/ {
+ i #ifndef _WIN32
+ a #endif
+}
diff --git a/security/nss/cmd/crlutil/crlgen_lex_orig.l b/security/nss/cmd/crlutil/crlgen_lex_orig.l
new file mode 100644
index 000000000..7cb1e5cde
--- /dev/null
+++ b/security/nss/cmd/crlutil/crlgen_lex_orig.l
@@ -0,0 +1,177 @@
+%{
+
+#include "crlgen.h"
+
+static SECStatus parserStatus = SECSuccess;
+static CRLGENGeneratorData *parserData;
+static PRFileDesc *src;
+
+#define YY_INPUT(buf,result,max_size) \
+ if ( parserStatus != SECFailure) { \
+ if (((result = PR_Read(src, buf, max_size)) == 0) && \
+ ferror( yyin )) \
+ return SECFailure; \
+ } else { return SECFailure; }
+
+
+%}
+
+%a 5000
+DIGIT [0-9]+
+DIGIT_RANGE [0-9]+-[0-9]+
+ID [a-zA-Z][a-zA-Z0-9]*
+OID [0-9]+\.[\.0-9]+
+DATE [0-9]{4}[01][0-9][0-3][0-9][0-2][0-9][0-6][0-9][0-6][0-9]
+ZDATE [0-9]{4}[01][0-9][0-3][0-9][0-2][0-9][0-6][0-9][0-6][0-9]Z
+N_SP_STRING [a-zA-Z0-9\:\|\.]+
+
+%%
+
+{ZDATE} {
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_ZDATE);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+{DIGIT} {
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_DIGIT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+{DIGIT_RANGE} {
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_DIGIT_RANGE);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+{OID} {
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_OID);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+issuer {
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_ISSUER_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+update {
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_UPDATE_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+nextupdate {
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_NEXT_UPDATE_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+range {
+parserStatus = crlgen_createNewLangStruct(parserData, CRLGEN_CHANGE_RANGE_CONTEXT);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+{ID} {
+if (strcmp(yytext, "addcert") == 0) {
+ parserStatus = crlgen_createNewLangStruct(parserData,
+ CRLGEN_ADD_CERT_CONTEXT);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+} else if (strcmp(yytext, "rmcert") == 0) {
+ parserStatus = crlgen_createNewLangStruct(parserData,
+ CRLGEN_RM_CERT_CONTEXT);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+} else if (strcmp(yytext, "addext") == 0) {
+ parserStatus = crlgen_createNewLangStruct(parserData,
+ CRLGEN_ADD_EXTENSION_CONTEXT);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+} else {
+ parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_ID);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+}
+
+"="
+
+\"[^\"]* {
+if (yytext[yyleng-1] == '\\') {
+ yymore();
+} else {
+ register int c;
+ c = input();
+ if (c != '\"') {
+ printf( "Error: Line ending \" is missing: %c\n", c);
+ unput(c);
+ } else {
+ parserStatus = crlgen_setNextData(parserData, yytext + 1,
+ CRLGEN_TYPE_STRING);
+ if (parserStatus != SECSuccess)
+ return parserStatus;
+ }
+}
+}
+
+{N_SP_STRING} {
+parserStatus = crlgen_setNextData(parserData, yytext, CRLGEN_TYPE_STRING);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+
+
+^#[^\n]* /* eat up one-line comments */ {}
+
+[ \t]+ {}
+
+(\n|\r\n) {
+parserStatus = crlgen_updateCrl(parserData);
+if (parserStatus != SECSuccess)
+ return parserStatus;
+}
+
+. {
+ fprintf(stderr, "Syntax error at line %d: unknown token %s\n",
+ parserData->parsedLineNum, yytext);
+ return SECFailure;
+}
+
+%%
+#include "prlock.h"
+
+static PRLock *parserInvocationLock;
+
+void CRLGEN_InitCrlGenParserLock()
+{
+ parserInvocationLock = PR_NewLock();
+}
+
+void CRLGEN_DestroyCrlGenParserLock()
+{
+ PR_DestroyLock(parserInvocationLock);
+}
+
+
+SECStatus CRLGEN_StartCrlGen(CRLGENGeneratorData *parserCtlData)
+{
+ SECStatus rv;
+
+ PR_Lock(parserInvocationLock);
+
+ parserStatus = SECSuccess;
+ parserData = parserCtlData;
+ src = parserCtlData->src;
+
+ rv = yylex();
+
+ PR_Unlock(parserInvocationLock);
+
+ return rv;
+}
+
+int yywrap() {return 1;}
diff --git a/security/nss/cmd/crlutil/crlutil.c b/security/nss/cmd/crlutil/crlutil.c
index 829be6112..ab066c33a 100644
--- a/security/nss/cmd/crlutil/crlutil.c
+++ b/security/nss/cmd/crlutil/crlutil.c
@@ -46,9 +46,11 @@
#include "plgetopt.h"
#include "secutil.h"
#include "cert.h"
+#include "certi.h"
#include "certdb.h"
#include "nss.h"
#include "pk11func.h"
+#include "crlgen.h"
#define SEC_CERT_DB_EXISTS 0
#define SEC_CREATE_CERT_DB 1
@@ -182,9 +184,9 @@ static SECStatus DeleteCRL (CERTCertDBHandle *certHandle, char *name, int type)
rv = SEC_DeletePermCRL (crl);
SEC_DestroyCrl(crl);
if (rv != SECSuccess) {
- SECU_PrintError
- (progName, "fail to delete the issuer %s's CRL from the perm database (reason: %s)",
- name, SECU_Strerror(PORT_GetError()));
+ SECU_PrintError(progName, "fail to delete the issuer %s's CRL "
+ "from the perm database (reason: %s)",
+ name, SECU_Strerror(PORT_GetError()));
return SECFailure;
}
return (rv);
@@ -247,16 +249,449 @@ SECStatus ImportCRL (CERTCertDBHandle *certHandle, char *url, int type,
}
return (rv);
}
-
+
+
+static CERTCertificate*
+FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl,
+ char *certNickName)
+{
+ CERTCertificate *cert = NULL, *certTemp = NULL;
+ SECStatus rv = SECFailure;
+ CERTAuthKeyID* authorityKeyID = NULL;
+ SECItem* subject = NULL;
+
+ PORT_Assert(certHandle != NULL);
+ if (!certHandle || (!signCrl && !certNickName)) {
+ SECU_PrintError(progName, "invalid args for function "
+ "FindSigningCert \n");
+ return NULL;
+ }
+
+ if (signCrl) {
+#if 0
+ authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl);
+#endif
+ subject = &signCrl->crl.derName;
+ } else {
+ certTemp = CERT_FindCertByNickname(certHandle, certNickName);
+ if (!certTemp) {
+ SECU_PrintError(progName, "could not find certificate \"%s\" "
+ "in database", certNickName);
+ goto loser;
+ }
+ subject = &certTemp->derSubject;
+ }
+
+ cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now());
+ if (!cert) {
+ SECU_PrintError(progName, "could not find signing certificate "
+ "in database");
+ goto loser;
+ } else {
+ rv = SECSuccess;
+ }
+
+ loser:
+ if (certTemp)
+ CERT_DestroyCertificate(certTemp);
+ if (cert && rv != SECSuccess)
+ CERT_DestroyCertificate(cert);
+ return cert;
+}
+
+static CERTSignedCrl*
+DuplicateModCrl(PRArenaPool *arena, CERTCertDBHandle *certHandle,
+ CERTCertificate **cert, char *certNickName,
+ PRFileDesc *inFile, PRInt32 decodeOptions,
+ PRInt32 importOptions)
+{
+ SECItem crlDER;
+ CERTSignedCrl *signCrl = NULL;
+ CERTSignedCrl *modCrl = NULL;
+ PRArenaPool *modArena = NULL;
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(arena != NULL && certHandle != NULL &&
+ certNickName != NULL);
+ if (!arena || !certHandle || !certNickName) {
+ SECU_PrintError(progName, "DuplicateModCrl: invalid args\n");
+ return NULL;
+ }
+
+ modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (!modArena) {
+ SECU_PrintError(progName, "fail to allocate memory\n");
+ return NULL;
+ }
+
+ if (inFile != NULL) {
+ rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "unable to read input file");
+ PORT_FreeArena(modArena, PR_FALSE);
+ goto loser;
+ }
+
+ decodeOptions |= CRL_DECODE_DONT_COPY_DER;
+
+ modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE,
+ decodeOptions);
+ if (!modCrl) {
+ SECU_PrintError(progName, "fail to decode CRL");
+ goto loser;
+ }
+
+ if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){
+ /* If caCert is a v2 certificate, make sure that it
+ * can be used for crl signing purpose */
+ *cert = FindSigningCert(certHandle, modCrl, NULL);
+ if (!*cert) {
+ goto loser;
+ }
+
+ rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert,
+ PR_Now(), NULL);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "fail to verify signed data\n");
+ goto loser;
+ }
+ }
+ } else {
+ modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE);
+ if (!modCrl) {
+ SECU_PrintError(progName, "fail to find crl %s in database\n",
+ certNickName);
+ goto loser;
+ }
+ }
+
+ signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
+ if (signCrl == NULL) {
+ SECU_PrintError(progName, "fail to allocate memory\n");
+ goto loser;
+ }
+
+ rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "unable to dublicate crl for "
+ "modification.");
+ goto loser;
+ }
+
+ signCrl->arena = arena;
+
+ loser:
+ SECITEM_FreeItem(&crlDER, PR_FALSE);
+ if (modCrl)
+ SEC_DestroyCrl(modCrl);
+ if (rv != SECSuccess && signCrl) {
+ SEC_DestroyCrl(signCrl);
+ signCrl = NULL;
+ }
+ return signCrl;
+}
+
+
+static CERTSignedCrl*
+CreateNewCrl(PRArenaPool *arena, CERTCertDBHandle *certHandle,
+ CERTCertificate *cert)
+{
+ CERTSignedCrl *signCrl = NULL;
+ void *dummy = NULL;
+ SECStatus rv;
+ void* mark = NULL;
+
+ /* if the CERTSignedCrl structure changes, this function will need to be
+ updated as well */
+ PORT_Assert(cert != NULL);
+ if (!cert || !arena) {
+ SECU_PrintError(progName, "invalid args for function "
+ "CreateNewCrl\n");
+ return NULL;
+ }
+
+ mark = PORT_ArenaMark(arena);
+
+ signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
+ if (signCrl == NULL) {
+ SECU_PrintError(progName, "fail to allocate memory\n");
+ return NULL;
+ }
+
+ dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version,
+ SEC_CRL_VERSION_2);
+ /* set crl->version */
+ if (!dummy) {
+ SECU_PrintError(progName, "fail to create crl version data "
+ "container\n");
+ goto loser;
+ }
+
+ /* copy SECItem name from cert */
+ rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "fail to duplicate der name from "
+ "certificate.\n");
+ goto loser;
+ }
+
+ /* copy CERTName name structure from cert issuer */
+ rv = CERT_CopyName (arena, &signCrl->crl.name, &cert->subject);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "fail to duplicate RD name from "
+ "certificate.\n");
+ goto loser;
+ }
+
+ rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "fail to encode current time\n");
+ goto loser;
+ }
+
+ /* set fields */
+ signCrl->arena = arena;
+ signCrl->dbhandle = certHandle;
+ signCrl->crl.arena = arena;
+
+ return signCrl;
+
+ loser:
+ PORT_ArenaRelease(arena, mark);
+ return NULL;
+}
+
+
+static SECStatus
+UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile)
+{
+ CRLGENGeneratorData *crlGenData = NULL;
+ SECStatus rv;
+
+ PORT_Assert(signCrl != NULL && inCrlInitFile != NULL);
+ if (!signCrl || !inCrlInitFile) {
+ SECU_PrintError(progName, "invalid args for function "
+ "CreateNewCrl\n");
+ return SECFailure;
+ }
+
+ crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile);
+ if (!crlGenData) {
+ SECU_PrintError(progName, "can not initialize parser structure.\n");
+ return SECFailure;
+ }
+
+ rv = CRLGEN_ExtHandleInit(crlGenData);
+ if (rv == SECFailure) {
+ SECU_PrintError(progName, "can not initialize entries handle.\n");
+ goto loser;
+ }
+
+ rv = CRLGEN_StartCrlGen(crlGenData);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "crl generation failed");
+ goto loser;
+ }
+
+ loser:
+ /* CommitExtensionsAndEntries is partially responsible for freeing
+ * up memory that was used for CRL generation. Should be called regardless
+ * of previouse call status, but only after initialization of
+ * crlGenData was done. It will commit all changes that was done before
+ * an error has occured.
+ */
+ if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) {
+ SECU_PrintError(progName, "crl generation failed");
+ rv = SECFailure;
+ }
+ CRLGEN_FinalizeCrlGeneration(crlGenData);
+ return rv;
+}
+
+static SECStatus
+SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert,
+ char *outFileName, SECOidTag hashAlgTag, int ascii,
+ char *slotName, char *url, secuPWData *pwdata)
+{
+ PK11SlotInfo *slot = NULL;
+ PRFileDesc *outFile = NULL;
+ SECStatus rv;
+ SignAndEncodeFuncExitStat errCode;
+
+ PORT_Assert(signCrl && (!ascii || outFileName));
+ if (!signCrl || (ascii && !outFileName)) {
+ SECU_PrintError(progName, "invalid args for function "
+ "SignAndStoreCrl\n");
+ return SECFailure;
+ }
+
+ if (!slotName || !PL_strcmp(slotName, "internal"))
+ slot = PK11_GetInternalKeySlot();
+ else
+ slot = PK11_FindSlotByName(slotName);
+ if (!slot) {
+ SECU_PrintError(progName, "can not find requested slot");
+ return SECFailure;
+ }
+
+ if (PK11_NeedLogin(slot)) {
+ rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
+ if (rv != SECSuccess)
+ goto loser;
+ }
+
+ rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode);
+ if (rv != SECSuccess) {
+ char* errMsg = NULL;
+ switch (errCode)
+ {
+ case noKeyFound:
+ errMsg = "No private key found of signing cert";
+ break;
+
+ case noSignatureMatch:
+ errMsg = "Key and Algorithm OId are do not match";
+ break;
+
+ default:
+ case failToEncode:
+ errMsg = "Failed to encode crl structure";
+ break;
+
+ case failToSign:
+ errMsg = "Failed to sign crl structure";
+ break;
+
+ case noMem:
+ errMsg = "Can not allocate memory";
+ break;
+ }
+ SECU_PrintError(progName, "%s\n", errMsg);
+ goto loser;
+ }
+
+ if (outFileName) {
+ outFile = PR_Open(outFileName, PR_WRONLY|PR_CREATE_FILE, PR_IRUSR | PR_IWUSR);
+ if (!outFile) {
+ SECU_PrintError(progName, "unable to open \"%s\" for writing\n",
+ outFileName);
+ goto loser;
+ }
+ }
+
+ rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "fail to save CRL\n");
+ }
+
+ loser:
+ if (outFile)
+ PR_Close(outFile);
+ if (slot)
+ PK11_FreeSlot(slot);
+ return rv;
+}
+
+static SECStatus
+GenerateCRL (CERTCertDBHandle *certHandle, char *certNickName,
+ PRFileDesc *inCrlInitFile, PRFileDesc *inFile,
+ char *outFileName, int ascii, char *slotName,
+ PRInt32 importOptions, char *alg, PRBool quiet,
+ PRInt32 decodeOptions, char *url, secuPWData *pwdata,
+ int modifyFlag)
+{
+ CERTCertificate *cert = NULL;
+ CERTSignedCrl *signCrl = NULL;
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
+
+ if (alg) {
+ hashAlgTag = SECU_StringToSignatureAlgTag(alg);
+ if (hashAlgTag == SEC_OID_UNKNOWN) {
+ SECU_PrintError(progName, "%s -Z: %s is not a recognized type.\n",
+ progName, alg);
+ return SECFailure;
+ }
+ } else {
+ hashAlgTag = SEC_OID_UNKNOWN;
+ }
+
+ arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (!arena) {
+ SECU_PrintError(progName, "fail to allocate memory\n");
+ return SECFailure;
+ }
+
+ if (modifyFlag == PR_TRUE) {
+ signCrl = DuplicateModCrl(arena, certHandle, &cert, certNickName,
+ inFile, decodeOptions, importOptions);
+ if (signCrl == NULL) {
+ goto loser;
+ }
+ }
+
+ if (!cert) {
+ cert = FindSigningCert(certHandle, signCrl, certNickName);
+ if (cert == NULL) {
+ goto loser;
+ }
+ }
+
+ if (!signCrl) {
+ if (modifyFlag == PR_TRUE) {
+ if (!outFileName) {
+ int len = strlen(certNickName) + 5;
+ outFileName = PORT_ArenaAlloc(arena, len);
+ PR_snprintf(outFileName, len, "%s.crl", certNickName);
+ }
+ SECU_PrintError(progName, "Will try to generate crl. "
+ "It will be saved in file: %s",
+ outFileName);
+ }
+ signCrl = CreateNewCrl(arena, certHandle, cert);
+ if (!signCrl)
+ goto loser;
+ }
+
+ rv = UpdateCrl(signCrl, inCrlInitFile);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii,
+ slotName, url, pwdata);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ if (signCrl && !quiet) {
+ SECU_PrintCRLInfo (stdout, &signCrl->crl, "CRL Info:\n", 0);
+ }
+
+ loser:
+ if (arena && (!signCrl || !signCrl->arena))
+ PORT_FreeArena (arena, PR_FALSE);
+ if (signCrl)
+ SEC_DestroyCrl (signCrl);
+ if (cert)
+ CERT_DestroyCertificate (cert);
+ return (rv);
+}
static void Usage(char *progName)
{
fprintf(stderr,
"Usage: %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n"
" %s -D -n nickname [-d keydir] [-P dbprefix]\n"
- " %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B]\n"
+ " %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] "
+ "[-p pwd-file] -w [pwd-string]\n"
" %s -E -t crlType [-d keydir] [-P dbprefix]\n"
- " %s -T\n", progName, progName, progName, progName, progName);
+ " %s -T\n"
+ " %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] "
+ "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] "
+ "[-a] [-B]\n",
+ progName, progName, progName, progName, progName, progName);
fprintf (stderr, "%-15s List CRL\n", "-L");
fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
@@ -300,6 +735,28 @@ static void Usage(char *progName)
fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p");
fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>");
+ fprintf(stderr, "\n%-15s Create CRL\n", "-G");
+ fprintf(stderr, "%-15s Modify CRL\n", "-M");
+ fprintf(stderr, "%-20s Specify crl initialization file\n",
+ "-c crl-conf-file");
+ fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
+ "-n nickname");
+ fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
+ "-i crl");
+ fprintf(stderr, "%-20s Specify a CRL output file\n",
+ "-o crl-output-file");
+ fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n",
+ "-a");
+ fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
+ "-d keydir");
+ fprintf(stderr, "%-20s Provide path to a default pwd file\n",
+ "-f pwd-file");
+ fprintf(stderr, "%-20s Provide db password in command line\n",
+ "-w pwd-string");
+ fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
+ "-P dbprefix");
+ fprintf(stderr, "%-20s Specify the url.\n", "-u url");
+ fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
exit(-1);
}
@@ -310,6 +767,9 @@ int main(int argc, char **argv)
CERTCertDBHandle *certHandle;
FILE *certFile;
PRFileDesc *inFile;
+ PRFileDesc *inCrlInitFile = NULL;
+ int generateCRL;
+ int modifyCRL;
int listCRL;
int importCRL;
int deleteCRL;
@@ -317,22 +777,29 @@ int main(int argc, char **argv)
char *nickName;
char *url;
char *dbPrefix = "";
+ char *alg = NULL;
+ char *outFile = NULL;
+ char *slotName = NULL;
+ int ascii = 0;
int crlType;
PLOptState *optstate;
PLOptStatus status;
SECStatus secstatus;
PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
+ PRBool quiet = PR_FALSE;
PRBool test = PR_FALSE;
PRBool erase = PR_FALSE;
PRInt32 i = 0;
PRInt32 iterations = 1;
+ secuPWData pwdata = { PW_NONE, 0 };
+
progName = strrchr(argv[0], '/');
progName = progName ? progName+1 : argv[0];
rv = 0;
- deleteCRL = importCRL = listCRL = 0;
+ deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = 0;
certFile = NULL;
inFile = NULL;
nickName = url = NULL;
@@ -342,7 +809,7 @@ int main(int argc, char **argv)
/*
* Parse command line arguments
*/
- optstate = PL_CreateOptState(argc, argv, "BCDILP:d:i:n:pt:u:TEr:");
+ optstate = PL_CreateOptState(argc, argv, "sqBCDGILMTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
@@ -361,9 +828,13 @@ int main(int argc, char **argv)
importOptions |= CRL_IMPORT_BYPASS_CHECKS;
break;
- case 'C':
- listCRL = 1;
- break;
+ case 'G':
+ generateCRL = 1;
+ break;
+
+ case 'M':
+ modifyCRL = 1;
+ break;
case 'D':
deleteCRL = 1;
@@ -373,22 +844,50 @@ int main(int argc, char **argv)
importCRL = 1;
break;
+ case 'C':
case 'L':
listCRL = 1;
break;
case 'P':
- dbPrefix = strdup(optstate->value);
- break;
-
+ dbPrefix = strdup(optstate->value);
+ break;
+
+ case 'Z':
+ alg = strdup(optstate->value);
+ break;
+
+ case 'a':
+ ascii = 1;
+ break;
+
+ case 'c':
+ inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
+ if (!inCrlInitFile) {
+ PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
+ progName, optstate->value);
+ PL_DestroyOptState(optstate);
+ return -1;
+ }
+ break;
+
case 'd':
- SECU_ConfigDirectory(optstate->value);
- break;
+ SECU_ConfigDirectory(optstate->value);
+ break;
+
+ case 'f':
+ pwdata.source = PW_FROMFILE;
+ pwdata.data = strdup(optstate->value);
+ break;
+
+ case 'h':
+ slotName = strdup(optstate->value);
+ break;
case 'i':
inFile = PR_Open(optstate->value, PR_RDONLY, 0);
if (!inFile) {
- fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
+ PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
progName, optstate->value);
PL_DestroyOptState(optstate);
return -1;
@@ -399,6 +898,10 @@ int main(int argc, char **argv)
nickName = strdup(optstate->value);
break;
+ case 'o':
+ outFile = strdup(optstate->value);
+ break;
+
case 'p':
decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
break;
@@ -416,25 +919,41 @@ int main(int argc, char **argv)
type = strdup(optstate->value);
crlType = atoi (type);
if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
- fprintf(stderr, "%s: invalid crl type\n", progName);
+ PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
PL_DestroyOptState(optstate);
return -1;
}
break;
+ case 'q':
+ quiet = PR_TRUE;
+ break;
+
+ case 'w':
+ pwdata.source = PW_PLAINTEXT;
+ pwdata.data = strdup(optstate->value);
+ break;
+
case 'u':
url = strdup(optstate->value);
break;
+
}
}
}
PL_DestroyOptState(optstate);
if (deleteCRL && !nickName) Usage (progName);
- if (!(listCRL || deleteCRL || importCRL || test || erase)) Usage (progName);
if (importCRL && !inFile) Usage (progName);
+ if ((generateCRL && !nickName) ||
+ (modifyCRL && !inFile && !nickName)) Usage (progName);
+ if (!(listCRL || deleteCRL || importCRL || generateCRL ||
+ modifyCRL || test || erase)) Usage (progName);
PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+
+ PK11_SetPasswordFunc(SECU_GetModulePassword);
+
secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
"secmod.db", 0);
if (secstatus != SECSuccess) {
@@ -451,6 +970,8 @@ int main(int argc, char **argv)
return (-1);
}
+ CRLGEN_InitCrlGenParserLock();
+
for (i=0; i<iterations; i++) {
/* Read in the private key info */
if (deleteCRL)
@@ -461,6 +982,14 @@ int main(int argc, char **argv)
else if (importCRL) {
rv = ImportCRL (certHandle, url, crlType, inFile, importOptions,
decodeOptions);
+ } else if (generateCRL || modifyCRL) {
+ if (!inCrlInitFile)
+ inCrlInitFile = PR_STDIN;
+ rv = GenerateCRL (certHandle, nickName, inCrlInitFile,
+ inFile, outFile, ascii, slotName,
+ importOptions, alg, quiet,
+ decodeOptions, url, &pwdata,
+ modifyCRL);
}
else if (erase) {
/* list and delete all CRLs */
@@ -480,6 +1009,9 @@ int main(int argc, char **argv)
}
#endif
}
+
+ CRLGEN_DestroyCrlGenParserLock();
+
if (NSS_Shutdown() != SECSuccess) {
rv = SECFailure;
}
diff --git a/security/nss/cmd/crlutil/manifest.mn b/security/nss/cmd/crlutil/manifest.mn
index e3ae7130a..c56ac20c7 100644
--- a/security/nss/cmd/crlutil/manifest.mn
+++ b/security/nss/cmd/crlutil/manifest.mn
@@ -48,7 +48,7 @@ REQUIRES = seccmd dbm
DEFINES = -DNSPR20
-CSRCS = crlutil.c
+CSRCS = crlgen_lex.c crlgen.c crlutil.c
# this has to be different for NT and UNIX.
# PROGRAM = ./$(OBJDIR)/crlutil.exe
diff --git a/security/nss/cmd/lib/secutil.c b/security/nss/cmd/lib/secutil.c
index de9ed446b..04236540d 100644
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -48,6 +48,7 @@
#include "prenv.h"
#include "prnetdb.h"
+#include "cryptohi.h"
#include "secutil.h"
#include "secpkcs7.h"
#include <stdarg.h>
@@ -3346,3 +3347,333 @@ SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle,
}
PORT_SetError(err); /* restore original error code */
}
+
+SECOidTag
+SECU_StringToSignatureAlgTag(const char *alg)
+{
+ SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
+
+ if (alg) {
+ if (!PL_strcmp(alg, "MD2")) {
+ hashAlgTag = SEC_OID_MD2;
+ } else if (!PL_strcmp(alg, "MD4")) {
+ hashAlgTag = SEC_OID_MD4;
+ } else if (!PL_strcmp(alg, "MD5")) {
+ hashAlgTag = SEC_OID_MD5;
+ } else if (!PL_strcmp(alg, "SHA1")) {
+ hashAlgTag = SEC_OID_SHA1;
+ } else if (!PL_strcmp(alg, "SHA256")) {
+ hashAlgTag = SEC_OID_SHA256;
+ } else if (!PL_strcmp(alg, "SHA384")) {
+ hashAlgTag = SEC_OID_SHA384;
+ } else if (!PL_strcmp(alg, "SHA512")) {
+ hashAlgTag = SEC_OID_SHA512;
+ }
+ }
+ return hashAlgTag;
+}
+
+
+SECStatus
+SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile,
+ const PRBool ascii, char *url)
+{
+ PORT_Assert(derCrl != NULL);
+ if (!derCrl) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (outFile != NULL) {
+ if (ascii) {
+ PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER,
+ BTOA_DataToAscii(derCrl->data, derCrl->len),
+ NS_CRL_TRAILER);
+ } else {
+ if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) {
+ return SECFailure;
+ }
+ }
+ }
+ if (slot) {
+ CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url,
+ SEC_CRL_TYPE, NULL, 0, NULL, 0);
+ if (newCrl != NULL) {
+ SEC_DestroyCrl(newCrl);
+ return SECSuccess;
+ }
+ return SECFailure;
+ }
+ if (!outFile && !slot) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
+ SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode)
+{
+ SECItem der;
+ SECKEYPrivateKey *caPrivateKey = NULL;
+ SECStatus rv;
+ PRArenaPool *arena;
+ SECOidTag algID;
+ void *dummy;
+
+ PORT_Assert(issuer != NULL && signCrl != NULL);
+ if (!issuer || !signCrl) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ arena = signCrl->arena;
+
+ caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL);
+ if (caPrivateKey == NULL) {
+ *resCode = noKeyFound;
+ return SECFailure;
+ }
+
+ algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag);
+ if (algID == SEC_OID_UNKNOWN) {
+ *resCode = noSignatureMatch;
+ rv = SECFailure;
+ goto done;
+ }
+
+ if (!signCrl->crl.signatureAlg.parameters.data) {
+ rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0);
+ if (rv != SECSuccess) {
+ *resCode = failToEncode;
+ goto done;
+ }
+ }
+
+ der.len = 0;
+ der.data = NULL;
+ dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl,
+ SEC_ASN1_GET(CERT_CrlTemplate));
+ if (!dummy) {
+ *resCode = failToEncode;
+ rv = SECFailure;
+ goto done;
+ }
+
+ rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap,
+ der.data, der.len, caPrivateKey, algID);
+ if (rv != SECSuccess) {
+ *resCode = failToSign;
+ goto done;
+ }
+
+ signCrl->derCrl = PORT_ArenaZNew(arena, SECItem);
+ if (signCrl->derCrl == NULL) {
+ *resCode = noMem;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ rv = SECFailure;
+ goto done;
+ }
+
+ signCrl->derCrl->len = 0;
+ signCrl->derCrl->data = NULL;
+ dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl,
+ SEC_ASN1_GET(CERT_SignedCrlTemplate));
+ if (!dummy) {
+ *resCode = failToEncode;
+ rv = SECFailure;
+ goto done;
+ }
+
+done:
+ if (caPrivateKey) {
+ SECKEY_DestroyPrivateKey(caPrivateKey);
+ }
+ return rv;
+}
+
+
+
+SECStatus
+SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl)
+{
+ void *dummy;
+ SECStatus rv = SECSuccess;
+ SECItem der;
+
+ PORT_Assert(destArena && srcCrl && destCrl);
+ if (!destArena || !srcCrl || !destCrl) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ der.len = 0;
+ der.data = NULL;
+ dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl,
+ SEC_ASN1_GET(CERT_CrlTemplate));
+ if (!dummy) {
+ return SECFailure;
+ }
+
+ rv = SEC_QuickDERDecodeItem(destArena, destCrl,
+ SEC_ASN1_GET(CERT_CrlTemplate), &der);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ destCrl->arena = destArena;
+
+ return rv;
+}
+
+SECStatus
+SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd,
+ unsigned char *buf, int len, SECKEYPrivateKey *pk,
+ SECOidTag algID)
+{
+ SECItem it;
+ SECStatus rv;
+
+ it.data = 0;
+
+ /* XXX We should probably have some asserts here to make sure the key type
+ * and algID match
+ */
+
+ /* Sign input buffer */
+ rv = SEC_SignData(&it, buf, len, pk, algID);
+ if (rv) goto loser;
+
+ /* Fill out SignedData object */
+ PORT_Memset(sd, 0, sizeof(sd));
+ sd->data.data = buf;
+ sd->data.len = len;
+ sd->signature.data = it.data;
+ sd->signature.len = it.len << 3; /* convert to bit string */
+ if (!sd->signatureAlgorithm.parameters.data) {
+ rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0);
+ if (rv) goto loser;
+ }
+
+ return rv;
+
+ loser:
+ PORT_Free(it.data);
+ return rv;
+}
+
+#if 0
+
+/* we need access to the private function cert_FindExtension for this code to work */
+
+CERTAuthKeyID *
+SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *scrl)
+{
+ SECItem encodedExtenValue;
+ SECStatus rv;
+ CERTAuthKeyID *ret;
+ CERTCrl* crl;
+
+ if (!scrl) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ crl = &scrl->crl;
+
+ encodedExtenValue.data = NULL;
+ encodedExtenValue.len = 0;
+
+ rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID,
+ &encodedExtenValue);
+ if ( rv != SECSuccess ) {
+ return (NULL);
+ }
+
+ ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
+
+ PORT_Free(encodedExtenValue.data);
+ encodedExtenValue.data = NULL;
+
+ return(ret);
+}
+
+#endif
+
+/*
+ * Find the issuer of a Crl. Use the authorityKeyID if it exists.
+ */
+CERTCertificate *
+SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject,
+ CERTAuthKeyID* authorityKeyID, PRTime validTime)
+{
+ CERTCertListNode *node;
+ CERTCertificate * issuerCert = NULL, *cert = NULL;
+ CERTCertList *certList = NULL;
+ SECStatus rv = SECFailure;
+
+ if (!subject) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ certList =
+ CERT_CreateSubjectCertList(NULL, dbhandle, subject,
+ validTime, PR_TRUE);
+ if (!certList) {
+ goto loser;
+ }
+
+ node = CERT_LIST_HEAD(certList);
+
+ /* XXX and authoritykeyid in the future */
+ while ( ! CERT_LIST_END(node, certList) ) {
+ cert = node->cert;
+ if (CERT_CheckCertUsage(cert, KU_CRL_SIGN) != SECSuccess ||
+ !cert->trust) {
+ continue;
+ }
+ /* select the first (newest) user cert */
+ if (CERT_IsUserCert(cert)) {
+ rv = SECSuccess;
+ goto success;
+ }
+ }
+
+ success:
+ if (rv == SECSuccess) {
+ issuerCert = CERT_DupCertificate(cert);
+ }
+ loser:
+ if (certList) {
+ CERT_DestroyCertList(certList);
+ }
+ return(issuerCert);
+}
+
+
+/* Encodes and adds extensions to the CRL or CRL entries. */
+SECStatus
+SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle,
+ void *value, PRBool criticality, int extenType,
+ EXTEN_EXT_VALUE_ENCODER EncodeValueFn)
+{
+ SECItem encodedValue;
+ SECStatus rv;
+
+ encodedValue.data = NULL;
+ encodedValue.len = 0;
+ do {
+ rv = (*EncodeValueFn)(arena, value, &encodedValue);
+ if (rv != SECSuccess)
+ break;
+
+ rv = CERT_AddExtension(extHandle, extenType, &encodedValue,
+ criticality, PR_TRUE);
+ if (rv != SECSuccess)
+ break;
+ } while (0);
+
+ return (rv);
+}
diff --git a/security/nss/cmd/lib/secutil.h b/security/nss/cmd/lib/secutil.h
index f774ed972..e8fc37550 100644
--- a/security/nss/cmd/lib/secutil.h
+++ b/security/nss/cmd/lib/secutil.h
@@ -59,6 +59,9 @@
#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"
#define NS_CERT_TRAILER "-----END CERTIFICATE-----"
+#define NS_CRL_HEADER "-----BEGIN CRL-----"
+#define NS_CRL_TRAILER "-----END CRL-----"
+
/* From libsec/pcertdb.c --- it's not declared in sec.h */
extern SECStatus SEC_AddPermCertificate(CERTCertDBHandle *handle,
SECItem *derCert, char *nickname, CERTCertTrust *trust);
@@ -299,6 +302,74 @@ extern void SECU_PrintPRandOSError(char *progName);
extern SECStatus SECU_RegisterDynamicOids(void);
+/* Identifies hash algorithm tag by its string representation. */
+extern SECOidTag SECU_StringToSignatureAlgTag(const char *alg);
+
+/* Store CRL in output file or pk11 db. Also
+ * encodes with base64 and exports to file if ascii flag is set
+ * and file is not NULL. */
+extern SECStatus SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl,
+ PRFileDesc *outFile, int ascii, char *url);
+
+
+/*
+** DER sign a single block of data using private key encryption and the
+** MD5 hashing algorithm. This routine first computes a digital signature
+** using SEC_SignData, then wraps it with an CERTSignedData and then der
+** encodes the result.
+** "arena" is the memory arena to use to allocate data from
+** "sd" returned CERTSignedData
+** "result" the final der encoded data (memory is allocated)
+** "buf" the input data to sign
+** "len" the amount of data to sign
+** "pk" the private key to encrypt with
+*/
+extern SECStatus SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd,
+ unsigned char *buf, int len,
+ SECKEYPrivateKey *pk, SECOidTag algID);
+
+typedef enum {
+ noKeyFound = 1,
+ noSignatureMatch = 2,
+ failToEncode = 3,
+ failToSign = 4,
+ noMem = 5
+} SignAndEncodeFuncExitStat;
+
+extern SECStatus
+SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
+ SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode);
+
+extern SECStatus
+SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl);
+
+/*
+** Finds the crl Authority Key Id extension. Returns NULL if no such extension
+** was found.
+*/
+CERTAuthKeyID *
+SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *crl);
+
+/*
+ * Find the issuer of a crl. Cert usage should be checked before signing a crl.
+ */
+CERTCertificate *
+SECU_FindCrlIssuer(CERTCertDBHandle *dbHandle, SECItem* subject,
+ CERTAuthKeyID* id, PRTime validTime);
+
+
+/* call back function used in encoding of an extension. Called from
+ * SECU_EncodeAndAddExtensionValue */
+typedef SECStatus (* EXTEN_EXT_VALUE_ENCODER) (PRArenaPool *extHandleArena,
+ void *value, SECItem *encodedValue);
+
+/* Encodes and adds extensions to the CRL or CRL entries. */
+SECStatus
+SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle,
+ void *value, PRBool criticality, int extenType,
+ EXTEN_EXT_VALUE_ENCODER EncodeValueFn);
+
+
/*
*
* Utilities for parsing security tools command lines
diff --git a/security/nss/lib/certdb/certt.h b/security/nss/lib/certdb/certt.h
index 568524734..a513092c6 100644
--- a/security/nss/lib/certdb/certt.h
+++ b/security/nss/lib/certdb/certt.h
@@ -843,6 +843,7 @@ extern const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[];
extern const SEC_ASN1Template CERT_RDNTemplate[];
extern const SEC_ASN1Template CERT_SignedDataTemplate[];
extern const SEC_ASN1Template CERT_CrlTemplate[];
+extern const SEC_ASN1Template CERT_SignedCrlTemplate[];
/*
** XXX should the attribute stuff be centralized for all of ns/security?
@@ -863,6 +864,7 @@ SEC_ASN1_CHOOSER_DECLARE(CERT_SetOfSignedCrlTemplate)
SEC_ASN1_CHOOSER_DECLARE(CERT_SignedDataTemplate)
SEC_ASN1_CHOOSER_DECLARE(CERT_SubjectPublicKeyInfoTemplate)
SEC_ASN1_CHOOSER_DECLARE(SEC_SignedCertificateTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_SignedCrlTemplate)
SEC_ASN1_CHOOSER_DECLARE(CERT_TimeChoiceTemplate)
SEC_END_PROTOS
diff --git a/security/nss/lib/certdb/crl.c b/security/nss/lib/certdb/crl.c
index f0e0edaa5..aee251f67 100644
--- a/security/nss/lib/certdb/crl.c
+++ b/security/nss/lib/certdb/crl.c
@@ -231,7 +231,7 @@ const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
{ 0 }
};
-static const SEC_ASN1Template cert_SignedCrlTemplate[] = {
+const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CERTSignedCrl) },
{ SEC_ASN1_SAVE,
@@ -264,7 +264,7 @@ static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
};
const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
- { SEC_ASN1_SET_OF, 0, cert_SignedCrlTemplate },
+ { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
};
/* get CRL version */
@@ -462,7 +462,7 @@ CERT_DecodeDERCrlWithFlags(PRArenaPool *narena, SECItem *derSignedCrl,
CERTSignedCrl *crl;
SECStatus rv;
OpaqueCRLFields* extended = NULL;
- const SEC_ASN1Template* crlTemplate = cert_SignedCrlTemplate;
+ const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
if (!derSignedCrl ||
( (options & CRL_DECODE_ADOPT_HEAP_DER) && /* adopting DER requires
@@ -827,10 +827,13 @@ SEC_DestroyCrl(CERTSignedCrl *crl)
if (crl->slot) {
PK11_FreeSlot(crl->slot);
}
- if (PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
+ if (GetOpaqueCRLFields(crl) &&
+ PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
SECITEM_FreeItem(crl->derCrl, PR_TRUE);
}
- PORT_FreeArena(crl->arena, PR_FALSE);
+ if (crl->arena) {
+ PORT_FreeArena(crl->arena, PR_FALSE);
+ }
}
return SECSuccess;
} else {
@@ -879,6 +882,7 @@ SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
*/
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate)
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
/* CRL cache code starts here */
@@ -2998,3 +3002,5 @@ static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
return SECSuccess;
}
+
+
diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def
index 3ef2dc935..2ef0b4434 100644
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -844,7 +844,9 @@ SECOID_AddEntry;
;+#
;+# Don't export these DATA symbols on Windows because they don't work right.
;;CERT_SequenceOfCertExtensionTemplate DATA ;
+;;CERT_SignedCrlTemplate DATA ;
NSS_Get_CERT_SequenceOfCertExtensionTemplate;
+NSS_Get_CERT_SignedCrlTemplate;
;+ local:
;+ *;
;+};
diff --git a/security/nss/tests/cert/cert.sh b/security/nss/tests/cert/cert.sh
index 21ff388d7..9feeb76d7 100755
--- a/security/nss/tests/cert/cert.sh
+++ b/security/nss/tests/cert/cert.sh
@@ -74,7 +74,8 @@ cert_init()
. ./init.sh
fi
SCRIPTNAME="cert.sh"
- html_head "Certutil Tests"
+ CRL_GRP_DATE=`date "+%Y%m%d%H%M%SZ"`
+ html_head "Certutil and Crlutil Tests"
################## Generate noise for our CA cert. ######################
# NOTE: these keys are only suitable for testing, as this whole thing
@@ -139,6 +140,31 @@ certu()
return $RET
}
+################################ certu #################################
+# local shell function to call crlutil, also: writes action and options to
+# stdout, sets variable RET and writes results to the html file results
+########################################################################
+crlu()
+{
+ echo "$SCRIPTNAME: ${CU_ACTION} --------------------------"
+
+ CRLUTIL=crlutil
+ echo "$CRLUTIL $*"
+ $CRLUTIL $*
+ RET=$?
+ if [ "$RET" -ne 0 ]; then
+ CRLFAILED=$RET
+ html_failed "<TR><TD>${CU_ACTION} ($RET) "
+ cert_log "ERROR: ${CU_ACTION} failed $RET"
+ else
+ html_passed "<TR><TD>${CU_ACTION}"
+ fi
+
+ # echo "Contine?"
+ # cat > /dev/null
+ return $RET
+}
+
############################# cert_init_cert ##########################
# local shell function to initialize creation of client and server certs
########################################################################
@@ -346,6 +372,7 @@ cert_CA()
certu -S -n $NICKNAME -t $TRUSTARG -v 600 $SIGNER -d ${LPROFILE} -1 -2 -5 \
-f ${R_PWFILE} -z ${R_NOISE_FILE} -m $CERTSERIAL 2>&1 <<CERTSCRIPT
5
+6
9
n
y
@@ -628,6 +655,131 @@ MODSCRIPT
fi
}
+
+############################## cert_stresscerts ################################
+# local shell function to generate certs and crls for SSL tests
+########################################################################
+cert_crl_ssl()
+{
+
+ ################# Creating Certs ###################################
+ #
+ CERTFAILED=0
+ CERTSERIAL=${CRL_GRP_1_BEGIN}
+
+ cd $CADIR
+
+ PROFILEDIR=${CLIENTDIR}
+ CRL_GRPS_END=`expr ${CRL_GRP_1_BEGIN} + ${TOTAL_CRL_RANGE} - 1`
+ echo "$SCRIPTNAME: Creating Client CA Issued Certificates Range $CRL_GRP_1_BEGIN - $CRL_GRPS_END ==="
+ CU_ACTION="Creating client test certs"
+
+ while [ $CERTSERIAL -le $CRL_GRPS_END ]
+ do
+ CERTNAME="TestUser$CERTSERIAL"
+ cert_add_cert
+ CERTSERIAL=`expr $CERTSERIAL + 1 `
+ done
+
+ #################### CRL Creation ##############################
+ CRL_GEN_RES=0
+ echo "$SCRIPTNAME: Creating CA CRL ====================================="
+
+ CRL_GRP_END=`expr ${CRL_GRP_1_BEGIN} + ${CRL_GRP_1_RANGE} - 1`
+ CRL_FILE_GRP_1=${R_SERVERDIR}/root.crl_${CRL_GRP_1_BEGIN}-${CRL_GRP_END}
+ CRL_FILE=${CRL_FILE_GRP_1}
+
+ CRLUPDATE=`date +%Y%m%d%H%M%SZ`
+ CU_ACTION="Generating CRL for range ${CRL_GRP_1_BEGIN}-${CRL_GRP_END} TestCA authority"
+ CRL_GRP_END_=`expr ${CRL_GRP_END} - 1`
+ crlu -d $CADIR -G -n "TestCA" -f ${R_PWFILE} -o ${CRL_FILE_GRP_1}_or <<EOF_CRLINI
+update=$CRLUPDATE
+addcert ${CRL_GRP_1_BEGIN}-${CRL_GRP_END_} $CRL_GRP_DATE
+addext reasonCode 0 4
+addext issuerAltNames 0 "rfc822Name:caemail@ca.com|dnsName:ca.com|x400Address:x400Address|directoryName:CN=NSS Test CA,O=BOGUS NSS,L=Mountain View,ST=California,C=US|URI:http://ca.com|ipAddress:192.168.0.1|registerID=reg CA"
+EOF_CRLINI
+# This extension should be added to the list, but currently nss has bug
+#addext authKeyId 0 "CN=NSS Test CA,O=BOGUS NSS,L=Mountain View,ST=California,C=US" 1
+ CRL_GEN_RES=`expr $? + $CRL_GEN_RES`
+
+ chmod 600 ${CRL_FILE_GRP_1}_or
+
+ echo test > file
+ ############################# Modification ##################################
+
+ echo "$SCRIPTNAME: Modifying CA CRL by adding one more cert ============"
+ sleep 2
+ CRL_GRP_DATE=`date "+%Y%m%d%H%M%SZ"`
+ CU_ACTION="Modification CRL by adding one more cert"
+ crlu -d $CADIR -M -n "TestCA" -f ${R_PWFILE} -o ${CRL_FILE_GRP_1}_or1 \
+ -i ${CRL_FILE_GRP_1}_or <<EOF_CRLINI
+addcert ${CRL_GRP_END} $CRL_GRP_DATE
+EOF_CRLINI
+ CRL_GEN_RES=`expr $? + $CRL_GEN_RES`
+ chmod 600 ${CRL_FILE_GRP_1}_or1
+ TEMPFILES="$TEMPFILES ${CRL_FILE_GRP_1}_or"
+
+ ########### Removing one cert ${UNREVOKED_CERT_GRP_1} #######################
+ echo "$SCRIPTNAME: Modifying CA CRL by removing one cert ==============="
+ CU_ACTION="Modification CRL by removing one cert"
+ crlu -d $CADIR -M -n "TestCA" -f ${R_PWFILE} -o ${CRL_FILE_GRP_1} \
+ -i ${CRL_FILE_GRP_1}_or1 <<EOF_CRLINI
+rmcert ${UNREVOKED_CERT_GRP_1}
+EOF_CRLINI
+ chmod 600 ${CRL_FILE_GRP_1}
+ TEMPFILES="$TEMPFILES ${CRL_FILE_GRP_1}_or1"
+
+ ########### Creating second CRL which includes groups 1 and 2 ##############
+ CRL_GRP_END=`expr ${CRL_GRP_2_BEGIN} + ${CRL_GRP_2_RANGE} - 1`
+ CRL_FILE_GRP_2=${R_SERVERDIR}/root.crl_${CRL_GRP_2_BEGIN}-${CRL_GRP_END}
+
+ echo "$SCRIPTNAME: Creating CA CRL for groups 1 and 2 ==============="
+ CRLUPDATE=`date "+%Y%m%d%H%M%SZ"`
+ CRL_GRP_DATE=`date "+%Y%m%d%H%M%SZ"`
+ CU_ACTION="Creating CRL for groups 1 and 2"
+ crlu -d $CADIR -M -n "TestCA" -f ${R_PWFILE} -o ${CRL_FILE_GRP_2} \
+ -i ${CRL_FILE_GRP_1} <<EOF_CRLINI
+update=$CRLUPDATE
+addcert ${CRL_GRP_2_BEGIN}-${CRL_GRP_END} $CRL_GRP_DATE
+addext invalidityDate 0 $CRLUPDATE
+rmcert ${UNREVOKED_CERT_GRP_2}
+EOF_CRLINI
+ CRL_GEN_RES=`expr $? + $CRL_GEN_RES`
+ chmod 600 ${CRL_FILE_GRP_2}
+
+ ########### Creating second CRL which includes groups 1, 2 and 3 ##############
+ CRL_GRP_END=`expr ${CRL_GRP_3_BEGIN} + ${CRL_GRP_3_RANGE} - 1`
+ CRL_FILE_GRP_3=${R_SERVERDIR}/root.crl_${CRL_GRP_3_BEGIN}-${CRL_GRP_END}
+
+ echo "$SCRIPTNAME: Creating CA CRL for groups 1, 2 and 3 ==============="
+ sleep 2
+ CRLUPDATE=`date "+%Y%m%d%H%M%SZ"`
+ CRL_GRP_DATE=`date "+%Y%m%d%H%M%SZ"`
+ CU_ACTION="Creating CRL for groups 1, 2 and 3"
+ crlu -d $CADIR -M -n "TestCA" -f ${R_PWFILE} -o ${CRL_FILE_GRP_3} \
+ -i ${CRL_FILE_GRP_2} <<EOF_CRLINI
+update=$CRLUPDATE
+addcert ${CRL_GRP_3_BEGIN}-${CRL_GRP_END} $CRL_GRP_DATE
+rmcert ${UNREVOKED_CERT_GRP_3}
+addext crlNumber 0 2
+EOF_CRLINI
+ CRL_GEN_RES=`expr $? + $CRL_GEN_RES`
+ chmod 600 ${CRL_FILE_GRP_3}
+
+ ############ Importing Server CA Issued CRL for certs of first group #######
+
+ echo "$SCRIPTNAME: Importing Server CA Issued CRL for certs ${CRL_GRP_BEGIN} trough ${CRL_GRP_END}"
+ CU_ACTION="Importing CRL for groups 1"
+ crlu -I -i ${CRL_FILE} -n "TestCA" -f "${R_PWFILE}" -d "${R_SERVERDIR}"
+ CRL_GEN_RES=`expr $? + $CRL_GEN_RES`
+
+ if [ "$CERTFAILED" != 0 -o "$CRL_GEN_RES" != 0 ] ; then
+ cert_log "ERROR: SSL CRL prep failed $CERTFAILED : $CRL_GEN_RES"
+ else
+ cert_log "SUCCESS: SSL CRL prep passed"
+ fi
+}
+
############################## cert_cleanup ############################
# local shell function to finish this script (no exit since it might be
# sourced)
@@ -648,6 +800,7 @@ cert_extended_ssl
cert_ssl
cert_smime_client
cert_fips
+cert_crl_ssl
if [ -n "$DO_DIST_ST" -a "$DO_DIST_ST" = "TRUE" ] ; then
cert_stresscerts
#following lines to be used when databases are to be reused
diff --git a/security/nss/tests/common/init.sh b/security/nss/tests/common/init.sh
index e07f974c0..0c0126372 100644
--- a/security/nss/tests/common/init.sh
+++ b/security/nss/tests/common/init.sh
@@ -467,6 +467,30 @@ if [ -z "${INIT_SOURCED}" -o "${INIT_SOURCED}" != "TRUE" ]; then
MAX_CERT=$GLOB_MAX_CERT
fi
+ #################################################
+ # CRL SSL testing constatnts
+ #
+
+
+ CRL_GRP_1_BEGIN=40
+ CRL_GRP_1_RANGE=3
+ UNREVOKED_CERT_GRP_1=41
+
+ CRL_GRP_2_BEGIN=43
+ CRL_GRP_2_RANGE=6
+ UNREVOKED_CERT_GRP_2=46
+
+ CRL_GRP_3_BEGIN=49
+ CRL_GRP_3_RANGE=4
+ UNREVOKED_CERT_GRP_3=51
+
+ TOTAL_CRL_RANGE=`expr ${CRL_GRP_1_RANGE} + ${CRL_GRP_2_RANGE} + \
+ ${CRL_GRP_3_RANGE}`
+
+ TOTAL_GRP_NUM=3
+
+ RELOAD_CRL=1
+
SCRIPTNAME=$0
INIT_SOURCED=TRUE #whatever one does - NEVER export this one please
fi
diff --git a/security/nss/tests/ssl/ssl.sh b/security/nss/tests/ssl/ssl.sh
index aa6099d40..5a1286999 100755
--- a/security/nss/tests/ssl/ssl.sh
+++ b/security/nss/tests/ssl/ssl.sh
@@ -73,7 +73,8 @@ ssl_init()
SCRIPTNAME=ssl.sh
echo "$SCRIPTNAME: SSL tests ==============================="
- grep "SUCCESS: SSL passed" $CERT_LOG_FILE >/dev/null || {
+ grep "SUCCESS: SSL passed" $CERT_LOG_FILE >/dev/null &&
+ grep "SUCCESS: SSL CRL prep passed" $CERT_LOG_FILE >/dev/null || {
html_head "SSL Test failure"
Exit 8 "Fatal - SSL of cert.sh needs to pass first"
}
@@ -330,6 +331,271 @@ ssl_stress()
html "</TABLE><BR>"
}
+############################## ssl_crl #################################
+# local shell function to perform SSL test with/out revoked certs tests
+########################################################################
+
+ssl_crl_ssl()
+{
+ html_head "CRL SSL Client Tests $NORM_EXT"
+
+ # Using First CRL Group for this test. There are $CRL_GRP_1_RANGE certs in it.
+ # Cert number $UNREVOKED_CERT_GRP_1 was not revoked
+ CRL_GROUP_BEGIN=$CRL_GRP_1_BEGIN
+ CRL_GROUP_RANGE=$CRL_GRP_1_RANGE
+ UNREVOKED_CERT=$UNREVOKED_CERT_GRP_1
+
+ while read value sparam cparam testname
+ do
+ if [ $value != "#" ]; then
+ servarg=`echo $sparam | awk '{r=split($0,a,"-r") - 1;print r;}'`
+ pwd=`echo $cparam | grep nss`
+ user=`echo $cparam | grep TestUser`
+ _cparam=$cparam
+ case $servarg in
+ 1) if [ -z "$pwd" -o -z "$user" ]; then
+ rev_modvalue=0
+ else
+ rev_modvalue=254
+ fi
+ ;;
+ 2) rev_modvalue=254 ;;
+ 3) if [ -z "$pwd" -o -z "$user" ]; then
+ rev_modvalue=0
+ else
+ rev_modvalue=1
+ fi
+ ;;
+ 4) rev_modvalue=1 ;;
+ esac
+ TEMP_NUM=0
+ while [ $TEMP_NUM -lt $CRL_GROUP_RANGE ]
+ do
+ CURR_SER_NUM=`expr ${CRL_GROUP_BEGIN} + ${TEMP_NUM}`
+ TEMP_NUM=`expr $TEMP_NUM + 1`
+ USER_NICKNAME="TestUser${CURR_SER_NUM}"
+ cparam=`echo $_cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
+ start_selfserv
+
+ echo "tstclnt -p ${PORT} -h ${HOSTADDR} -f -d ${R_CLIENTDIR} \\"
+ echo " ${cparam} < ${REQUEST_FILE}"
+ rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
+ tstclnt -p ${PORT} -h ${HOSTADDR} -f ${cparam} \
+ -d ${R_CLIENTDIR} < ${REQUEST_FILE} \
+ >${TMP}/$HOST.tmp.$$ 2>&1
+ ret=$?
+ cat ${TMP}/$HOST.tmp.$$
+ rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
+ if [ $CURR_SER_NUM -ne $UNREVOKED_CERT ]; then
+ modvalue=$rev_modvalue
+ else
+ modvalue=$value
+ fi
+
+ html_msg $ret $modvalue "${testname}" \
+ "produced a returncode of $ret, expected is $modvalue"
+ kill_selfserv
+ done
+ fi
+ done < ${SSLAUTH}
+
+ html "</TABLE><BR>"
+}
+
+############################## ssl_crl #################################
+# local shell function to perform SSL test for crl cache functionality
+# with/out revoked certs
+########################################################################
+
+is_revoked() {
+ certNum=$1
+ currLoadedGrp=$2
+
+ found=0
+ ownerGrp=1
+ while [ $ownerGrp -le $TOTAL_GRP_NUM -a $found -eq 0 ]
+ do
+ currGrpBegin=`eval echo \$\{CRL_GRP_${ownerGrp}_BEGIN\}`
+ currGrpRange=`eval echo \$\{CRL_GRP_${ownerGrp}_RANGE\}`
+ currGrpEnd=`expr $currGrpBegin + $currGrpRange - 1`
+ if [ $certNum -ge $currGrpBegin -a $certNum -le $currGrpEnd ]; then
+ found=1
+ else
+ ownerGrp=`expr $ownerGrp + 1`
+ fi
+ done
+ if [ $found -eq 1 -a $currLoadedGrp -lt $ownerGrp ]; then
+ return 1
+ fi
+ if [ $found -eq 0 ]; then
+ return 1
+ fi
+ unrevokedGrpCert=`eval echo \$\{UNREVOKED_CERT_GRP_${ownerGrp}\}`
+ if [ $certNum -eq $unrevokedGrpCert ]; then
+ return 1
+ fi
+ return 0
+}
+
+load_group_crl() {
+ group=$1
+
+ OUTFILE_TMP=${TMP}/$HOST.tmp.$$
+ grpBegin=`eval echo \$\{CRL_GRP_${group}_BEGIN\}`
+ grpRange=`eval echo \$\{CRL_GRP_${group}_RANGE\}`
+ grpEnd=`expr $grpBegin + $grpRange - 1`
+
+ if [ "$grpBegin" = "" -o "$grpRange" = "" ]; then
+ ret=1
+ return 1;
+ fi
+
+ if [ "$RELOAD_CRL" != "" ]; then
+ if [ $group -eq 1 ]; then
+ echo "==================== Resetting to group 1 crl ==================="
+ kill_selfserv
+ start_selfserv
+ is_selfserv_alive
+ fi
+ echo "================= Reloading CRL for group $grpBegin - $grpEnd ============="
+
+ echo "tstclnt -p ${PORT} -h ${HOSTADDR} -f -d ${R_CLIENTDIR} \\"
+ echo " -w nss -n TestUser${UNREVOKED_CERT_GRP_1}"
+ echo "Request:"
+ echo "GET crl://${SERVERDIR}/root.crl_${grpBegin}-${grpEnd}"
+ echo ""
+ echo "RELOAD time $i"
+ tstclnt -p ${PORT} -h ${HOSTADDR} -f \
+ -d ${R_CLIENTDIR} -w nss -n TestUser${UNREVOKED_CERT_GRP_1} \
+ <<_EOF_REQUEST_ >${OUTFILE_TMP} 2>&1
+GET crl://${SERVERDIR}/root.crl_${grpBegin}-${grpEnd}
+
+_EOF_REQUEST_
+ cat ${OUTFILE_TMP}
+ grep "CRL ReCache Error" ${OUTFILE_TMP}
+ if [ $? -eq 0 ]; then
+ ret=1
+ return 1
+ fi
+ else
+ echo "=== Updating DB for group $grpBegin - $grpEnd and restarting selfserv ====="
+
+ kill_selfserv
+ CU_ACTION="Importing CRL for groups $grpBegin - $grpEnd"
+ crlu -d ${R_SERVERDIR} -I -i ${SERVERDIR}/root.crl_${grpBegin}-${grpEnd} \
+ -p ../tests.pw.928
+ ret=$?
+ if [ "$ret" -eq 0 ]; then
+ return 1
+ fi
+ start_selfserv
+ fi
+ is_selfserv_alive
+ ret=$?
+ echo "================= CRL Reloaded ============="
+}
+
+
+ssl_crl_cache()
+{
+ html_head "Cache CRL SSL Client Tests $NORM_EXT"
+ SSLAUTH_TMP=${TMP}/authin.tl.tmp
+ SERV_ARG=-r_-r
+ rm -f ${SSLAUTH_TMP}
+ echo ${SSLAUTH_TMP}
+
+ grep -- " $SERV_ARG " ${SSLAUTH} | grep -v "^#" | grep -v none | grep -v bogus > ${SSLAUTH_TMP}
+ echo $?
+ while [ $? -eq 0 -a -f ${SSLAUTH_TMP} ]
+ do
+ sparam=$SERV_ARG
+ start_selfserv
+ while read value sparam cparam testname
+ do
+ servarg=`echo $sparam | awk '{r=split($0,a,"-r") - 1;print r;}'`
+ pwd=`echo $cparam | grep nss`
+ user=`echo $cparam | grep TestUser`
+ _cparam=$cparam
+ case $servarg in
+ 1) if [ -z "$pwd" -o -z "$user" ]; then
+ rev_modvalue=0
+ else
+ rev_modvalue=254
+ fi
+ ;;
+ 2) rev_modvalue=254 ;;
+
+ 3) if [ -z "$pwd" -o -z "$user" ]; then
+ rev_modvalue=0
+ else
+ rev_modvalue=1
+ fi
+ ;;
+ 4) rev_modvalue=1 ;;
+ esac
+ TEMP_NUM=0
+ LOADED_GRP=1
+ while [ ${LOADED_GRP} -le ${TOTAL_GRP_NUM} ]
+ do
+ while [ $TEMP_NUM -lt $TOTAL_CRL_RANGE ]
+ do
+ CURR_SER_NUM=`expr ${CRL_GRP_1_BEGIN} + ${TEMP_NUM}`
+ TEMP_NUM=`expr $TEMP_NUM + 1`
+ USER_NICKNAME="TestUser${CURR_SER_NUM}"
+ cparam=`echo $_cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
+
+ echo "Server Args: $SERV_ARG"
+ echo "tstclnt -p ${PORT} -h ${HOSTADDR} -f -d ${R_CLIENTDIR} \\"
+ echo " ${cparam} < ${REQUEST_FILE}"
+ rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
+ tstclnt -p ${PORT} -h ${HOSTADDR} -f ${cparam} \
+ -d ${R_CLIENTDIR} < ${REQUEST_FILE} \
+ >${TMP}/$HOST.tmp.$$ 2>&1
+ ret=$?
+ cat ${TMP}/$HOST.tmp.$$
+ rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
+ is_revoked ${CURR_SER_NUM} ${LOADED_GRP}
+ isRevoked=$?
+ if [ $isRevoked -eq 0 ]; then
+ modvalue=$rev_modvalue
+ testAddMsg="is revoked"
+ else
+ modvalue=$value
+ testAddMsg="is not revoked"
+ fi
+
+ is_selfserv_alive
+ ss_status=$?
+ if [ "$ss_status" -ne 0 ]; then
+ html_msg $ret $modvalue \
+ "${testname}(cert ${USER_NICKNAME} - $testAddMsg)" \
+ "produced a returncode of $ret, expected is $modvalue. " \
+ "selfserv is not alive!"
+ else
+ html_msg $ret $modvalue \
+ "${testname}(cert ${USER_NICKNAME} - $testAddMsg)" \
+ "produced a returncode of $ret, expected is $modvalue"
+ fi
+ done
+ LOADED_GRP=`expr $LOADED_GRP + 1`
+ TEMP_NUM=0
+ if [ "$LOADED_GRP" -le "$TOTAL_GRP_NUM" ]; then
+ load_group_crl $LOADED_GRP
+ html_msg $ret 0 "Load group $LOADED_GRP crl " \
+ "produced a returncode of $ret, expected is 0"
+ fi
+ done
+ load_group_crl 1
+ done < ${SSLAUTH_TMP}
+ kill_selfserv
+ SERV_ARG="${SERV_ARG}_-r"
+ rm -f ${SSLAUTH_TMP}
+ grep -- " $SERV_ARG " ${SSLAUTH} | grep -v none | grep -v bogus > ${SSLAUTH_TMP}
+ done
+ TEMPFILES=${SSLAUTH_TMP}
+ html "</TABLE><BR>"
+}
+
############################## ssl_cleanup #############################
# local shell function to finish this script (no exit since it might be
@@ -350,6 +616,8 @@ if [ -z "$DO_REM_ST" -a -z "$DO_DIST_ST" ] ; then
ssl_init
ssl_cov
ssl_auth
+ ssl_crl_ssl
+ ssl_crl_cache
ssl_stress
SERVERDIR=$EXT_SERVERDIR