Back to index

lightning-sunbird  0.9+nobinonly
crlgen.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038 ** crlgen.c
00039 **
00040 ** utility for managing certificates revocation lists generation
00041 **
00042 */
00043 
00044 
00045 #include <stdio.h>
00046 #include <math.h>
00047 
00048 #include "nspr.h"
00049 #include "plgetopt.h"
00050 #include "nss.h"
00051 #include "secutil.h"
00052 #include "cert.h"
00053 #include "certi.h"
00054 #include "certdb.h"
00055 #include "pk11func.h"
00056 #include "crlgen.h"
00057 
00058 
00059 /* these reroutines were taken from secitem.c, which is supposed to
00060  * replace this file some day */
00061 /*
00062  * This is the hash function.  We simply XOR the encoded form with
00063  * itself in sizeof(PLHashNumber)-byte chunks.  Improving this
00064  * routine is left as an excercise for the more mathematically
00065  * inclined student.
00066  */
00067 PLHashNumber PR_CALLBACK
00068 SECITEM_Hash ( const void *key)
00069 {
00070     const SECItem *item = (const SECItem *)key;
00071     PLHashNumber rv = 0;
00072 
00073     PRUint8 *data = (PRUint8 *)item->data;
00074     PRUint32 i;
00075     PRUint8 *rvc = (PRUint8 *)&rv;
00076 
00077     for( i = 0; i < item->len; i++ ) {
00078         rvc[ i % sizeof(rv) ] ^= *data;
00079         data++;
00080     }
00081 
00082     return rv;
00083 }
00084 
00085 /*
00086  * This is the key-compare function.  It simply does a lexical
00087  * comparison on the item data.  This does not result in
00088  * quite the same ordering as the "sequence of numbers" order,
00089  * but heck it's only used internally by the hash table anyway.
00090  */
00091 PRIntn PR_CALLBACK
00092 SECITEM_HashCompare ( const void *k1, const void *k2)
00093 {
00094     const SECItem *i1 = (const SECItem *)k1;
00095     const SECItem *i2 = (const SECItem *)k2;
00096 
00097     return SECITEM_ItemsAreEqual(i1,i2);
00098 }
00099 
00100 /* Destroys extHandle and data. data was create on heap.
00101  * extHandle creaded by CERT_StartCRLEntryExtensions. entry
00102  * was allocated on arena.*/
00103 static void
00104 destroyEntryData(CRLGENEntryData *data)
00105 {
00106     if (!data)
00107         return;
00108     PORT_Assert(data->entry);
00109     if (data->extHandle)
00110         CERT_FinishExtensions(data->extHandle);
00111     PORT_Free(data);
00112 }
00113 
00114 
00115 /* Prints error messages along with line number */
00116 void 
00117 crlgen_PrintError(int line, char *msg, ...)
00118 {
00119     va_list args;
00120 
00121     va_start(args, msg);
00122 
00123     fprintf(stderr, "crlgen: (line: %d) ", line);
00124     vfprintf(stderr, msg, args);
00125 
00126     va_end(args);
00127 }
00128 /* Finds CRLGENEntryData in hashtable according PRUint64 value
00129  * - certId : cert serial number*/
00130 static CRLGENEntryData*
00131 crlgen_FindEntry(CRLGENGeneratorData *crlGenData, SECItem *certId) 
00132 {
00133     if (!crlGenData->entryDataHashTable || !certId)
00134         return NULL;
00135     return (CRLGENEntryData*)
00136         PL_HashTableLookup(crlGenData->entryDataHashTable,
00137                            certId);
00138 }
00139 
00140 
00141 /* Removes CRLGENEntryData from hashtable according to certId
00142  * - certId : cert serial number*/
00143 static SECStatus
00144 crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId) 
00145 {
00146     CRLGENEntryData *data = NULL;
00147 
00148     if (!crlGenData->entryDataHashTable)
00149         return SECSuccess;
00150     data = crlgen_FindEntry(crlGenData, certId);
00151     if (!data)
00152         return SECSuccess;
00153     if (PL_HashTableRemove(crlGenData->entryDataHashTable, certId))
00154         return SECSuccess;
00155     destroyEntryData(data);
00156     return SECFailure;
00157 }
00158 
00159 
00160 /* Stores CRLGENEntryData in hashtable according to certId
00161  * - certId : cert serial number*/
00162 static CRLGENEntryData*
00163 crlgen_PlaceAnEntry(CRLGENGeneratorData *crlGenData,
00164                     CERTCrlEntry *entry, SECItem *certId)
00165 {
00166     CRLGENEntryData *newData = NULL;
00167 
00168     PORT_Assert(crlGenData && crlGenData->entryDataHashTable &&
00169                 entry);
00170     if (!crlGenData || !crlGenData->entryDataHashTable || !entry) {
00171         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00172         return NULL;
00173     }
00174 
00175     newData = PORT_ZNew(CRLGENEntryData);
00176     if (!newData) {
00177         return NULL;
00178     }
00179     newData->entry = entry;
00180     newData->certId = certId;
00181     if (!PL_HashTableAdd(crlGenData->entryDataHashTable,
00182                          newData->certId, newData)) { 
00183         crlgen_PrintError(crlGenData->parsedLineNum,
00184                           "Can not add entryData structure\n");
00185         return NULL;
00186     }
00187     return newData;
00188 }
00189 
00190 /* Use this structure to keep pointer when commiting entries extensions */
00191 struct commitData {
00192     int pos;
00193     CERTCrlEntry **entries;
00194 };
00195 
00196 /* HT PL_HashTableEnumerateEntries callback. Sorts hashtable entries of the
00197  * table he. Returns value through arg parameter*/
00198 static PRIntn PR_CALLBACK 
00199 crlgen_CommitEntryData(PLHashEntry *he, PRIntn i, void *arg)
00200 {
00201     CRLGENEntryData *data = NULL;
00202 
00203     PORT_Assert(he);
00204     if (!he) {
00205         return HT_ENUMERATE_NEXT;
00206     }
00207     data = (CRLGENEntryData*)he->value;
00208 
00209     PORT_Assert(data);
00210     PORT_Assert(arg);
00211 
00212     if (data) {
00213         struct commitData *dt = (struct commitData*)arg;
00214         dt->entries[dt->pos++] = data->entry;
00215         destroyEntryData(data);
00216     }
00217     return HT_ENUMERATE_NEXT;
00218 }
00219 
00220 
00221 
00222 /* Copy char * datainto allocated in arena SECItem */
00223 static SECStatus 
00224 crlgen_SetString(PRArenaPool *arena, const char *dataIn, SECItem *value)
00225 {
00226     SECItem item;
00227 
00228     PORT_Assert(arena && dataIn);
00229     if (!arena || !dataIn) {
00230         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00231         return SECFailure;
00232     }
00233 
00234     item.data = (void*)dataIn;
00235     item.len = PORT_Strlen(dataIn);
00236 
00237     return SECITEM_CopyItem(arena, value, &item);
00238 }
00239 
00240 /* Creates CERTGeneralName from parsed data for the Authority Key Extension */
00241 static CERTGeneralName *
00242 crlgen_GetGeneralName (PRArenaPool *arena, CRLGENGeneratorData *crlGenData,
00243                        const char *data)
00244 {
00245     CERTGeneralName *namesList = NULL;
00246     CERTGeneralName *current;
00247     CERTGeneralName *tail = NULL;
00248     SECStatus rv = SECSuccess;
00249     const char *nextChunk = NULL;
00250     const char *currData = NULL;
00251     int intValue;
00252     char buffer[512];
00253     void *mark;
00254 
00255     if (!data)
00256         return NULL;
00257     PORT_Assert (arena);
00258     if (!arena) {
00259         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00260         return NULL;
00261     }
00262 
00263     mark = PORT_ArenaMark (arena);
00264 
00265     nextChunk = data;
00266     currData = data;
00267     do {
00268         int nameLen = 0;
00269         char name[128];
00270         const char *sepPrt = NULL;
00271         nextChunk = PORT_Strchr(currData, '|');
00272         if (!nextChunk)
00273             nextChunk = data + strlen(data);
00274         sepPrt = PORT_Strchr(currData, ':');
00275         if (sepPrt == NULL || sepPrt >= nextChunk) {
00276             *buffer = '\0';
00277             sepPrt = nextChunk;
00278         } else {
00279             PORT_Memcpy(buffer, sepPrt + 1,
00280                         (nextChunk - sepPrt - 1));
00281             buffer[nextChunk - sepPrt - 1] = '\0';
00282         }
00283         nameLen = PR_MIN(sepPrt - currData, sizeof(name) - 1 );
00284         PORT_Memcpy(name, currData, nameLen);
00285         name[nameLen] = '\0';
00286         currData = nextChunk + 1;
00287 
00288         if (!PORT_Strcmp(name, "otherName"))
00289             intValue = certOtherName;
00290         else if (!PORT_Strcmp(name, "rfc822Name"))
00291             intValue = certRFC822Name;
00292         else if (!PORT_Strcmp(name, "dnsName"))
00293             intValue = certDNSName;
00294         else if (!PORT_Strcmp(name, "x400Address"))
00295             intValue = certX400Address;
00296         else if (!PORT_Strcmp(name, "directoryName"))
00297             intValue = certDirectoryName;
00298         else if (!PORT_Strcmp(name, "ediPartyName"))
00299             intValue = certEDIPartyName;
00300         else if (!PORT_Strcmp(name, "URI"))
00301             intValue = certURI;
00302         else if (!PORT_Strcmp(name, "ipAddress"))
00303             intValue = certIPAddress;
00304         else if (!PORT_Strcmp(name, "registerID"))
00305             intValue = certRegisterID;
00306         else intValue = -1;
00307 
00308         if (intValue >= certOtherName && intValue <= certRegisterID) {
00309             if (namesList == NULL) {
00310                 namesList = current = tail = PORT_ArenaZNew(arena,
00311                                                             CERTGeneralName);
00312             } else {
00313                 current = PORT_ArenaZNew(arena, CERTGeneralName);
00314             }
00315             if (current == NULL) {
00316                 rv = SECFailure;
00317                 break;
00318             }
00319         } else {
00320             PORT_SetError(SEC_ERROR_INVALID_ARGS);
00321             break;
00322         }
00323         current->type = intValue;
00324         switch (current->type) {
00325           case certURI:
00326           case certDNSName:
00327           case certRFC822Name:
00328               current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer));
00329               if (current->name.other.data == NULL) {
00330                   rv = SECFailure;
00331                   break;
00332               }
00333               PORT_Memcpy(current->name.other.data, buffer,
00334                           current->name.other.len = strlen(buffer));
00335               break;
00336 
00337           case certEDIPartyName:
00338           case certIPAddress:
00339           case certOtherName:
00340           case certRegisterID:
00341           case certX400Address: {
00342 
00343               current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer) + 2);
00344               if (current->name.other.data == NULL) {
00345                   rv = SECFailure;
00346                   break;
00347               }
00348 
00349               PORT_Memcpy (current->name.other.data + 2, buffer, strlen (buffer));
00350 /* This may not be accurate for all cases.For now, use this tag type */
00351               current->name.other.data[0] = (char)(((current->type - 1) & 0x1f)| 0x80);
00352               current->name.other.data[1] = (char)strlen (buffer);
00353               current->name.other.len = strlen (buffer) + 2;
00354               break;
00355           }
00356 
00357           case certDirectoryName: {
00358               CERTName *directoryName = NULL;
00359 
00360               directoryName = CERT_AsciiToName (buffer);
00361               if (!directoryName) {
00362                   rv = SECFailure;
00363                   break;
00364               }
00365 
00366               rv = CERT_CopyName (arena, &current->name.directoryName, directoryName);
00367               CERT_DestroyName (directoryName);
00368 
00369               break;
00370           }
00371         }
00372         if (rv != SECSuccess)
00373             break;
00374         current->l.next = &(namesList->l);
00375         current->l.prev = &(tail->l);
00376         tail->l.next = &(current->l);
00377         tail = current;
00378 
00379     } while(nextChunk != data + strlen(data));
00380 
00381     if (rv != SECSuccess) {
00382         PORT_ArenaRelease (arena, mark);
00383         namesList = NULL;
00384     }
00385     return (namesList);
00386 }
00387 
00388 /* Creates CERTGeneralName from parsed data for the Authority Key Extension */
00389 static CERTGeneralName *
00390 crlgen_DistinguishedName (PRArenaPool *arena, CRLGENGeneratorData *crlGenData,
00391                           const char *data)
00392 {
00393     CERTName *directoryName = NULL;
00394     CERTGeneralName *current;
00395     SECStatus rv = SECFailure;
00396     void *mark;
00397 
00398     if (!data)
00399         return NULL;
00400     PORT_Assert (arena);
00401     if (!arena) {
00402         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00403         return NULL;
00404     }
00405 
00406     mark = PORT_ArenaMark (arena);
00407 
00408     current = PORT_ArenaZNew(arena, CERTGeneralName);
00409     if (current == NULL) {
00410         goto loser;
00411     }
00412     current->type = certDirectoryName;
00413     current->l.next = &current->l;
00414     current->l.prev = &current->l;
00415     
00416     directoryName = CERT_AsciiToName ((char*)data);
00417     if (!directoryName) {
00418         goto loser;
00419     }
00420     
00421     rv = CERT_CopyName (arena, &current->name.directoryName, directoryName);
00422     CERT_DestroyName (directoryName);
00423 
00424   loser:
00425     if (rv != SECSuccess) {
00426         PORT_SetError (rv);
00427         PORT_ArenaRelease (arena, mark);
00428         current = NULL;
00429     }
00430     return (current);
00431 }
00432 
00433 
00434 /* Adding Authority Key ID extension to extension handle. */
00435 static SECStatus 
00436 crlgen_AddAuthKeyID (CRLGENGeneratorData *crlGenData,
00437                      const char **dataArr)
00438 {
00439     void *extHandle = NULL;
00440     CERTAuthKeyID *authKeyID = NULL;
00441     PRArenaPool *arena = NULL;
00442     SECStatus rv = SECSuccess;
00443 
00444     PORT_Assert(dataArr && crlGenData);
00445     if (!crlGenData || !dataArr) {
00446         return SECFailure;
00447     }
00448 
00449     extHandle = crlGenData->crlExtHandle;
00450 
00451     if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
00452         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00453         crlgen_PrintError(crlGenData->parsedLineNum,
00454                           "insufficient number of parameters.\n");
00455         return SECFailure;
00456     }
00457 
00458     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00459     if (!arena) {
00460         return SECFailure;
00461     }
00462 
00463     authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID);
00464     if (authKeyID == NULL) {
00465         rv = SECFailure;
00466         goto loser;
00467     }
00468 
00469     if (dataArr[3] == NULL) {
00470         rv = crlgen_SetString (arena, dataArr[2], &authKeyID->keyID);
00471         if (rv != SECSuccess)
00472             goto loser;
00473     } else {
00474         rv = crlgen_SetString (arena, dataArr[3],
00475                                &authKeyID->authCertSerialNumber);
00476         if (rv != SECSuccess)
00477             goto loser;
00478 
00479         authKeyID->authCertIssuer = 
00480             crlgen_DistinguishedName (arena, crlGenData, dataArr[2]);
00481         if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError ()){
00482             crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
00483             rv = SECFailure;
00484             goto loser;
00485         }
00486     }
00487 
00488     rv =
00489         SECU_EncodeAndAddExtensionValue(arena, extHandle, authKeyID,
00490                                         (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
00491                                         SEC_OID_X509_AUTH_KEY_ID, 
00492                                         (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID);
00493   loser:
00494     if (arena)
00495         PORT_FreeArena (arena, PR_FALSE);
00496     return rv;
00497 } 
00498 
00499 /* Creates and add Subject Alternative Names extension */
00500 static SECStatus 
00501 crlgen_AddIssuerAltNames(CRLGENGeneratorData *crlGenData,
00502                           const char **dataArr)
00503 {
00504     CERTGeneralName *nameList = NULL;
00505     PRArenaPool *arena = NULL;
00506     void *extHandle = NULL;
00507     SECStatus rv = SECSuccess;
00508 
00509 
00510     PORT_Assert(dataArr && crlGenData);
00511     if (!crlGenData || !dataArr) {
00512         return SECFailure;
00513     }
00514 
00515     if (!dataArr || !dataArr[0] || !dataArr[1] || !dataArr[2]) {
00516         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00517         crlgen_PrintError(crlGenData->parsedLineNum,
00518                           "insufficient number of arguments.\n");
00519         return SECFailure;
00520     }
00521 
00522     PORT_Assert(dataArr && crlGenData);
00523     if (!crlGenData || !dataArr) {
00524         return SECFailure;
00525     }
00526 
00527     extHandle = crlGenData->crlExtHandle;
00528 
00529     if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
00530         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00531         crlgen_PrintError(crlGenData->parsedLineNum,
00532                           "insufficient number of parameters.\n");
00533         return SECFailure;
00534     }
00535 
00536     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00537     if (!arena) {
00538         return SECFailure;
00539     }
00540 
00541     nameList = crlgen_GetGeneralName(arena, crlGenData, dataArr[2]);
00542     if (nameList == NULL) {
00543         crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
00544         rv = SECFailure;
00545         goto loser;
00546     }
00547 
00548     rv =
00549         SECU_EncodeAndAddExtensionValue(arena, extHandle, nameList,
00550                                         (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
00551                                         SEC_OID_X509_ISSUER_ALT_NAME, 
00552                                         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeAltNameExtension);
00553   loser:
00554     if (arena)
00555         PORT_FreeArena (arena, PR_FALSE);
00556     return rv;
00557 }
00558 
00559 /* Creates and adds CRLNumber extension to extension handle.
00560  * Since, this is CRL extension, extension handle is the one 
00561  * related to CRL extensions */
00562 static SECStatus
00563 crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
00564 {
00565     PRArenaPool *arena = NULL;
00566     SECItem encodedItem;
00567     void *extHandle = crlGenData->crlExtHandle;
00568     void *dummy;
00569     SECStatus rv = SECFailure;
00570     int code = 0;
00571 
00572     PORT_Assert(dataArr && crlGenData);
00573     if (!crlGenData || !dataArr) {
00574         goto loser;
00575     }
00576 
00577     if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
00578         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00579         crlgen_PrintError(crlGenData->parsedLineNum,
00580                           "insufficient number of arguments.\n");
00581         goto loser;
00582     }
00583 
00584     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00585     if (arena == NULL) {
00586         goto loser;
00587     }
00588 
00589     code = atoi(dataArr[2]);
00590     if (code == 0 && *dataArr[2] != '0') {
00591         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00592         goto loser;
00593     }
00594 
00595     dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
00596     if (!dummy) {
00597         rv = SECFailure;
00598         goto loser;
00599     }
00600 
00601     rv = CERT_AddExtension (extHandle, SEC_OID_X509_CRL_NUMBER, &encodedItem, 
00602                             (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
00603                             PR_TRUE);
00604 
00605   loser:
00606     if (arena)
00607         PORT_FreeArena(arena, PR_FALSE);
00608     return rv;
00609 
00610 }
00611 
00612 
00613 /* Creates Cert Revocation Reason code extension. Encodes it and
00614  * returns as SECItem structure */
00615 static SECItem*
00616 crlgen_CreateReasonCode(PRArenaPool *arena, const char **dataArr,
00617                         int *extCode)
00618 {
00619     SECItem *encodedItem;
00620     void *dummy;
00621     void *mark;
00622     int code = 0;
00623 
00624     PORT_Assert(arena && dataArr);
00625     if (!arena || !dataArr) {
00626         goto loser;
00627     } 
00628 
00629     mark = PORT_ArenaMark(arena);
00630 
00631     encodedItem = PORT_ArenaZNew (arena, SECItem);
00632     if (encodedItem == NULL) {
00633         goto loser;
00634     }
00635 
00636     if (dataArr[2] == NULL) {
00637         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00638         goto loser;
00639     }
00640 
00641     code = atoi(dataArr[2]);
00642     /* aACompromise(10) is the last possible of the values 
00643      * for the Reason Core Extension */
00644     if ((code == 0 && *dataArr[2] != '0') || code > 10) {
00645         
00646         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00647         goto loser;
00648     }
00649 
00650     dummy = SEC_ASN1EncodeInteger(arena, encodedItem, code);
00651     if (!dummy) {
00652         goto loser;
00653     }
00654 
00655     *extCode = SEC_OID_X509_REASON_CODE;
00656     return encodedItem;
00657 
00658   loser:
00659     PORT_ArenaRelease (arena, mark);
00660     return NULL;
00661 }
00662 
00663 /* Creates Cert Invalidity Date extension. Encodes it and
00664  * returns as SECItem structure */
00665 static SECItem*
00666 crlgen_CreateInvalidityDate(PRArenaPool *arena, const char **dataArr,
00667                        int *extCode)
00668 {
00669     SECItem *encodedItem;
00670     int length = 0;
00671     void *mark;
00672 
00673     PORT_Assert(arena && dataArr);
00674     if (!arena || !dataArr) {
00675         goto loser;
00676     } 
00677 
00678     mark = PORT_ArenaMark(arena);
00679 
00680     encodedItem = PORT_ArenaZNew(arena, SECItem);
00681     if (encodedItem == NULL) {
00682         goto loser;
00683     }
00684 
00685     length = PORT_Strlen(dataArr[2]);
00686 
00687     encodedItem->type = siGeneralizedTime;
00688     encodedItem->data = PORT_ArenaAlloc(arena, length);
00689     if (!encodedItem->data) {
00690         goto loser;
00691     }
00692 
00693     PORT_Memcpy(encodedItem->data, dataArr[2], (encodedItem->len = length) *
00694                 sizeof(char));
00695 
00696     *extCode = SEC_OID_X509_INVALID_DATE;
00697     return encodedItem;
00698     
00699   loser:
00700     PORT_ArenaRelease(arena, mark);
00701     return NULL;
00702 }
00703 
00704 /* Creates(by calling extCreator function) and adds extension to a set
00705  * of already added certs. Uses values of rangeFrom and rangeTo from
00706  * CRLGENCrlGenCtl structure for identifying the inclusive set of certs */
00707 static SECStatus
00708 crlgen_AddEntryExtension(CRLGENGeneratorData *crlGenData,
00709                          const char **dataArr, char *extName,
00710                          SECItem* (*extCreator)(PRArenaPool *arena,
00711                                                 const char **dataArr,
00712                                                 int *extCode))
00713 {
00714     PRUint64 i = 0;
00715     SECStatus rv = SECFailure;
00716     int extCode = 0;
00717     PRUint64 lastRange ;
00718     SECItem *ext = NULL;
00719     PRArenaPool *arena = NULL;
00720 
00721 
00722     PORT_Assert(crlGenData &&  dataArr);
00723     if (!crlGenData || !dataArr) {
00724         goto loser;
00725     } 
00726     
00727     if (!dataArr[0] || !dataArr[1]) {
00728         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00729         crlgen_PrintError(crlGenData->parsedLineNum, 
00730                           "insufficient number of arguments.\n");
00731     }
00732 
00733     lastRange = crlGenData->rangeTo - crlGenData->rangeFrom + 1;
00734 
00735     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00736     if (arena == NULL) {
00737         goto loser;
00738     }
00739 
00740     ext = extCreator(arena, dataArr, &extCode);
00741     if (ext == NULL) {
00742         crlgen_PrintError(crlGenData->parsedLineNum, 
00743                           "got error while creating extension: %s\n",
00744                           extName);
00745         goto loser;
00746     }
00747 
00748     for (i = 0;i < lastRange;i++) {
00749         CRLGENEntryData * extData = NULL;
00750         void *extHandle = NULL;
00751         SECItem * certIdItem =
00752             SEC_ASN1EncodeInteger(arena, NULL,
00753                                   crlGenData->rangeFrom + i);
00754         if (!certIdItem) {
00755             rv = SECFailure;
00756             goto loser;
00757         }
00758 
00759         extData = crlgen_FindEntry(crlGenData, certIdItem);
00760         if (!extData) {
00761             crlgen_PrintError(crlGenData->parsedLineNum,
00762                               "can not add extension: crl entry "
00763                               "(serial number: %d) is not in the list yet.\n",
00764                               crlGenData->rangeFrom + i);
00765             continue;
00766         }
00767 
00768         extHandle = extData->extHandle;
00769         if (extHandle == NULL) {
00770             extHandle = extData->extHandle =
00771                 CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
00772                                              (CERTCrlEntry*)extData->entry);
00773         }
00774         rv = CERT_AddExtension (extHandle, extCode, ext, 
00775                                (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
00776                                PR_TRUE);
00777         if (rv == SECFailure) {
00778             goto loser;
00779         }
00780     }
00781 
00782   loser:
00783     if (arena)
00784         PORT_FreeArena(arena, PR_FALSE);
00785     return rv;
00786 }
00787 
00788 
00789 /* Commits all added entries and their's extensions into CRL. */
00790 SECStatus
00791 CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData *crlGenData)
00792 {
00793     int size = 0;
00794     CERTCrl *crl;
00795     PRArenaPool *arena;
00796     SECStatus rv = SECSuccess;
00797     void *mark;
00798 
00799     PORT_Assert(crlGenData && crlGenData->signCrl && crlGenData->signCrl->arena);
00800     if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
00801         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00802         return SECFailure;
00803     }
00804 
00805     arena = crlGenData->signCrl->arena;
00806     crl = &crlGenData->signCrl->crl;
00807 
00808     mark = PORT_ArenaMark(arena);
00809 
00810     if (crlGenData->crlExtHandle)
00811         CERT_FinishExtensions(crlGenData->crlExtHandle);
00812 
00813     size = crlGenData->entryDataHashTable->nentries;
00814     crl->entries = NULL;
00815     if (size) {
00816         crl->entries = PORT_ArenaZNewArray(arena, CERTCrlEntry*, size + 1);
00817         if (!crl->entries) {
00818             rv = SECFailure;
00819         } else {
00820             struct commitData dt;
00821             dt.entries = crl->entries;
00822             dt.pos = 0;
00823             PL_HashTableEnumerateEntries(crlGenData->entryDataHashTable,
00824                                          &crlgen_CommitEntryData, &dt);
00825             /* Last should be NULL */
00826             crl->entries[size] = NULL;
00827         }
00828     }
00829 
00830     if (rv != SECSuccess)
00831         PORT_ArenaRelease(arena, mark);
00832     return rv;
00833 }
00834 
00835 /* Initializes extHandle with data from extensions array */
00836 static SECStatus
00837 crlgen_InitExtensionHandle(void *extHandle,
00838                            CERTCertExtension **extensions)
00839 {
00840     CERTCertExtension *extension = NULL;
00841 
00842     if (!extensions)
00843         return SECSuccess;
00844 
00845     PORT_Assert(extHandle != NULL);
00846     if (!extHandle) {
00847         return SECFailure;
00848     }
00849 
00850     extension = *extensions;
00851     while (extension) {
00852         SECOidTag oidTag = SECOID_FindOIDTag (&extension->id);
00853 /* shell we skip unknown extensions? */
00854         CERT_AddExtension (extHandle, oidTag, &extension->value, 
00855                            (extension->critical.len != 0) ? PR_TRUE : PR_FALSE,
00856                            PR_FALSE);
00857         extension = *(++extensions);
00858     }
00859     return SECSuccess;
00860 }
00861 
00862 /* Used for initialization of extension handles for crl and certs
00863  * extensions from existing CRL data then modifying existing CRL.*/
00864 SECStatus
00865 CRLGEN_ExtHandleInit(CRLGENGeneratorData *crlGenData)
00866 {
00867     CERTCrl *crl = NULL;
00868     PRUint64 maxSN = 0;
00869 
00870     PORT_Assert(crlGenData && crlGenData->signCrl &&
00871                 crlGenData->entryDataHashTable);
00872     if (!crlGenData || !crlGenData->signCrl ||
00873         !crlGenData->entryDataHashTable) {
00874         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00875         return SECFailure;
00876     }
00877 
00878     crl = &crlGenData->signCrl->crl;
00879     crlGenData->crlExtHandle = CERT_StartCRLExtensions(crl);
00880     crlgen_InitExtensionHandle(crlGenData->crlExtHandle,
00881                                crl->extensions);
00882     crl->extensions = NULL;
00883 
00884     if (crl->entries) {
00885         CERTCrlEntry **entry = crl->entries;
00886         while (*entry) {
00887             PRUint64 sn = DER_GetInteger(&(*entry)->serialNumber);
00888             CRLGENEntryData *extData =
00889                 crlgen_PlaceAnEntry(crlGenData, *entry, &(*entry)->serialNumber);
00890             if ((*entry)->extensions) {
00891                 extData->extHandle = 
00892                     CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
00893                                                  (CERTCrlEntry*)extData->entry);
00894                 if (crlgen_InitExtensionHandle(extData->extHandle,
00895                                                (*entry)->extensions) == SECFailure)
00896                     return SECFailure;
00897             }
00898             (*entry)->extensions = NULL;
00899             entry++;
00900             maxSN = PR_MAX(maxSN, sn);
00901         }
00902     }
00903 
00904     crlGenData->rangeFrom = crlGenData->rangeTo = maxSN + 1;
00905     return SECSuccess;
00906 }
00907 
00908 /*****************************************************************************
00909  * Parser trigger functions start here
00910  */
00911 
00912 /* Sets new internal range value for add/rm certs.*/
00913 static SECStatus
00914 crlgen_SetNewRangeField(CRLGENGeneratorData *crlGenData, char *value)
00915 {
00916     long rangeFrom = 0, rangeTo = 0;
00917     char *dashPos = NULL;
00918 
00919     PORT_Assert(crlGenData);
00920     if (!crlGenData) {
00921         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00922         return SECFailure;
00923     }
00924 
00925     if (value == NULL) {
00926         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00927         crlgen_PrintError(crlGenData->parsedLineNum,
00928                           "insufficient number of arguments.\n");
00929         return SECFailure;
00930     }
00931 
00932     if ((dashPos = strchr(value, '-')) != NULL) {
00933         char *rangeToS, *rangeFromS = value;
00934         *dashPos = '\0';
00935         rangeFrom = atoi(rangeFromS);
00936         *dashPos = '-';
00937 
00938         rangeToS = (char*)(dashPos + 1);
00939         rangeTo = atol(rangeToS);
00940     } else {
00941         rangeFrom = atol(value);
00942         rangeTo = rangeFrom;
00943     }
00944 
00945     if (rangeFrom < 1 || rangeTo<rangeFrom) {
00946         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00947         crlgen_PrintError(crlGenData->parsedLineNum,
00948                           "bad cert id range: %s.\n", value);
00949         return SECFailure;
00950     }
00951 
00952     crlGenData->rangeFrom = rangeFrom;
00953     crlGenData->rangeTo = rangeTo;
00954 
00955     return SECSuccess;
00956 }
00957 
00958 /* Changes issuer subject field in CRL. By default this data is taken from
00959  * issuer cert subject field.Not yet implemented */
00960 static SECStatus
00961 crlgen_SetIssuerField(CRLGENGeneratorData *crlGenData, char *value)
00962 {
00963     crlgen_PrintError(crlGenData->parsedLineNum, 
00964                       "Can not change CRL issuer field.\n");
00965     return SECFailure;
00966 }
00967 
00968 /* Encode and sets CRL thisUpdate and nextUpdate time fields*/
00969 static SECStatus
00970 crlgen_SetTimeField(CRLGENGeneratorData *crlGenData, char *value,
00971                     PRBool setThisUpdate)
00972 {
00973     CERTSignedCrl *signCrl;
00974     PRArenaPool *arena;
00975     CERTCrl *crl;
00976     int length = 0;
00977     SECItem *timeDest = NULL;
00978 
00979     PORT_Assert(crlGenData && crlGenData->signCrl &&
00980                 crlGenData->signCrl->arena);
00981     if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
00982         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00983         return SECFailure;
00984     }
00985 
00986     signCrl = crlGenData->signCrl;
00987     arena = signCrl->arena;
00988     crl = &signCrl->crl;
00989 
00990     if (value == NULL) {
00991         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00992         crlgen_PrintError(crlGenData->parsedLineNum,
00993                           "insufficient number of arguments.\n");
00994         return SECFailure;
00995     }
00996     length = PORT_Strlen(value);
00997     
00998     if (setThisUpdate == PR_TRUE) {
00999         timeDest = &crl->lastUpdate;
01000     } else {
01001         timeDest = &crl->nextUpdate;
01002     }
01003 
01004     timeDest->type = siGeneralizedTime;
01005     timeDest->data = PORT_ArenaAlloc(arena, length);
01006     if (!timeDest->data) {
01007         return SECFailure;
01008     }
01009     PORT_Memcpy(timeDest->data, value, length);
01010     timeDest->len = length;
01011 
01012     return SECSuccess;
01013 }
01014 
01015 
01016 /* Adds new extension into CRL or added cert handles */
01017 static SECStatus
01018 crlgen_AddExtension(CRLGENGeneratorData *crlGenData, const char **extData)
01019 {
01020     PORT_Assert(crlGenData && crlGenData->crlExtHandle);
01021     if (!crlGenData || !crlGenData->crlExtHandle) {
01022         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01023         return SECFailure;
01024     }
01025 
01026     if (extData == NULL || *extData == NULL) {
01027         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01028         crlgen_PrintError(crlGenData->parsedLineNum, 
01029                           "insufficient number of arguments.\n");
01030         return SECFailure;
01031     }
01032     if (!PORT_Strcmp(*extData, "authKeyId"))
01033         return crlgen_AddAuthKeyID(crlGenData, extData);
01034     else if (!PORT_Strcmp(*extData, "issuerAltNames"))
01035         return crlgen_AddIssuerAltNames(crlGenData, extData);
01036     else if (!PORT_Strcmp(*extData, "crlNumber"))
01037         return crlgen_AddCrlNumber(crlGenData, extData);
01038     else if (!PORT_Strcmp(*extData, "reasonCode"))
01039         return crlgen_AddEntryExtension(crlGenData, extData, "reasonCode",
01040                                         crlgen_CreateReasonCode);
01041     else if (!PORT_Strcmp(*extData, "invalidityDate"))
01042         return crlgen_AddEntryExtension(crlGenData, extData, "invalidityDate",
01043                                         crlgen_CreateInvalidityDate);
01044     else {
01045         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01046         crlgen_PrintError(crlGenData->parsedLineNum,
01047                           "insufficient number of arguments.\n");
01048         return SECFailure;
01049     }
01050 }
01051 
01052 
01053 
01054 /* Created CRLGENEntryData for cert with serial number certId and
01055  * adds it to entryDataHashTable. certId can be a single cert serial
01056  * number or an inclusive rage of certs */
01057 static SECStatus
01058 crlgen_AddCert(CRLGENGeneratorData *crlGenData,
01059         char *certId, char *revocationDate)
01060 {
01061     CERTSignedCrl *signCrl;
01062     SECItem *certIdItem;
01063     PRArenaPool *arena;
01064     PRUint64 rangeFrom = 0, rangeTo = 0, i = 0;
01065     int timeValLength = -1;
01066     SECStatus rv = SECFailure;
01067     void *mark;
01068 
01069 
01070     PORT_Assert(crlGenData && crlGenData->signCrl &&
01071                 crlGenData->signCrl->arena);
01072     if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
01073         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01074         return SECFailure;
01075     }
01076 
01077     signCrl = crlGenData->signCrl;
01078     arena = signCrl->arena;
01079 
01080     if (!certId || !revocationDate) {
01081         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01082         crlgen_PrintError(crlGenData->parsedLineNum,
01083                           "insufficient number of arguments.\n");
01084         return SECFailure;
01085     }
01086 
01087     timeValLength = strlen(revocationDate);
01088 
01089     if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
01090         certId) {
01091         return SECFailure;
01092     }
01093     rangeFrom = crlGenData->rangeFrom;
01094     rangeTo = crlGenData->rangeTo;
01095 
01096     for (i = 0;i < rangeTo - rangeFrom + 1;i++) {
01097         CERTCrlEntry *entry;
01098         mark = PORT_ArenaMark(arena);
01099         entry = PORT_ArenaZNew(arena, CERTCrlEntry);
01100         if (entry == NULL) {
01101             goto loser;
01102         }
01103 
01104         certIdItem = SEC_ASN1EncodeInteger(arena, &entry->serialNumber,
01105                                            rangeFrom + i);
01106         if (!certIdItem) {
01107             goto loser;
01108         }
01109 
01110         if (crlgen_FindEntry(crlGenData, certIdItem)) {
01111             crlgen_PrintError(crlGenData->parsedLineNum,
01112                               "entry already exists. Use \"range\" "
01113                               "and \"rmcert\" before adding a new one with the "
01114                               "same serial number %ld\n", rangeFrom + i);
01115             goto loser;
01116         }
01117 
01118         entry->serialNumber.type = siBuffer;
01119 
01120         entry->revocationDate.type = siGeneralizedTime;
01121 
01122         entry->revocationDate.data =
01123             PORT_ArenaAlloc(arena, timeValLength);
01124         if (entry->revocationDate.data == NULL) {
01125             goto loser;
01126         }
01127 
01128         PORT_Memcpy(entry->revocationDate.data, revocationDate,
01129                     timeValLength * sizeof(char));
01130         entry->revocationDate.len = timeValLength;
01131 
01132 
01133         entry->extensions = NULL;
01134         if (!crlgen_PlaceAnEntry(crlGenData, entry, certIdItem)) {
01135             goto loser;
01136         }
01137         mark = NULL;
01138     }
01139 
01140     rv = SECSuccess;
01141   loser:
01142     if (mark) {
01143         PORT_ArenaRelease(arena, mark);
01144     }
01145     return rv;
01146 }
01147 
01148 
01149 /* Removes certs from entryDataHashTable which have certId serial number.
01150  * certId can have value of a range of certs */
01151 static SECStatus
01152 crlgen_RmCert(CRLGENGeneratorData *crlGenData, char *certId)
01153 {
01154     PRUint64 i = 0;
01155     PRArenaPool *arena;
01156 
01157     PORT_Assert(crlGenData && certId);
01158     if (!crlGenData || !certId) {
01159         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01160         return SECFailure;
01161     }
01162 
01163     arena = crlGenData->signCrl->arena;
01164 
01165     if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
01166         certId) {
01167         return SECFailure;
01168     }
01169 
01170     for (i = 0;i < crlGenData->rangeTo - crlGenData->rangeFrom + 1;i++) {
01171         SECItem* certIdItem = SEC_ASN1EncodeInteger(NULL, NULL,
01172                                                     crlGenData->rangeFrom + i);
01173         if (certIdItem) {
01174             CRLGENEntryData *extData =
01175                 crlgen_FindEntry(crlGenData, certIdItem);
01176             if (!extData) {
01177                 printf("Cert with id %s is not in the list\n", certId);
01178             } else {
01179                 crlgen_RmEntry(crlGenData, certIdItem);
01180             }
01181             SECITEM_FreeItem(certIdItem, PR_TRUE);
01182         }
01183     }
01184 
01185     return SECSuccess;
01186 }
01187 
01188 /*************************************************************************
01189  * Lex Parser Helper functions are used to store parsed information
01190  * in context related structures. Context(or state) is identified base on 
01191  * a type of a instruction parser currently is going through. New context
01192  * is identified by first token in a line. It can be addcert context,
01193  * addext context, etc. */
01194 
01195 /* Updates CRL field depending on current context */ 
01196 static SECStatus
01197 crlgen_updateCrlFn_field(CRLGENGeneratorData *crlGenData, void *str)
01198 {
01199     CRLGENCrlField *fieldStr = (CRLGENCrlField*)str;
01200 
01201     PORT_Assert(crlGenData);
01202     if (!crlGenData) {
01203         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01204         return SECFailure;
01205     }
01206 
01207     switch(crlGenData->contextId) {
01208       case CRLGEN_ISSUER_CONTEXT:
01209           crlgen_SetIssuerField(crlGenData, fieldStr->value);
01210           break;
01211       case CRLGEN_UPDATE_CONTEXT:
01212           return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_TRUE);
01213           break;
01214       case CRLGEN_NEXT_UPDATE_CONTEXT:
01215           return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_FALSE);
01216           break;
01217       case CRLGEN_CHANGE_RANGE_CONTEXT:
01218           return crlgen_SetNewRangeField(crlGenData, fieldStr->value);
01219           break;
01220       default:
01221           crlgen_PrintError(crlGenData->parsedLineNum,
01222                             "syntax error (unknow token type: %d)\n",
01223                             crlGenData->contextId);
01224           PORT_SetError(SEC_ERROR_INVALID_ARGS);
01225           return SECFailure;
01226     }
01227     return SECSuccess;
01228 }
01229 
01230 /* Sets parsed data for CRL field update into temporary structure */ 
01231 static SECStatus
01232 crlgen_setNextDataFn_field(CRLGENGeneratorData *crlGenData, void *str,
01233                     void *data, unsigned short dtype)
01234 {
01235     CRLGENCrlField *fieldStr = (CRLGENCrlField*)str;
01236 
01237     PORT_Assert(crlGenData);
01238     if (!crlGenData) {
01239         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01240         return SECFailure;
01241     }
01242 
01243     switch (crlGenData->contextId) {
01244       case CRLGEN_CHANGE_RANGE_CONTEXT:
01245           if (dtype != CRLGEN_TYPE_DIGIT || dtype != CRLGEN_TYPE_DIGIT_RANGE) {
01246               crlgen_PrintError(crlGenData->parsedLineNum,
01247                                 "range value should have "
01248                                 "numeric or numeric range values.\n");
01249               return SECFailure;
01250           }
01251           break;
01252       case CRLGEN_NEXT_UPDATE_CONTEXT:
01253       case CRLGEN_UPDATE_CONTEXT:
01254           if (dtype != CRLGEN_TYPE_ZDATE){
01255               crlgen_PrintError(crlGenData->parsedLineNum,
01256                                 "bad formated date. Should be "
01257                                 "YYYYMMDDHHMMSSZ.\n");
01258               return SECFailure;
01259           }
01260           break;
01261       default:
01262           PORT_SetError(SEC_ERROR_INVALID_ARGS);
01263           crlgen_PrintError(crlGenData->parsedLineNum,
01264                             "syntax error (unknow token type: %d).\n",
01265                             crlGenData->contextId, data);
01266           return SECFailure;
01267     }
01268     fieldStr->value = PORT_Strdup(data);
01269     if (!fieldStr->value) {
01270         return SECFailure;
01271     }
01272     return SECSuccess;
01273 }
01274 
01275 /* Triggers cert entries update depending on current context */ 
01276 static SECStatus
01277 crlgen_updateCrlFn_cert(CRLGENGeneratorData *crlGenData, void *str)
01278 {
01279     CRLGENCertEntry *certStr = (CRLGENCertEntry*)str;
01280 
01281     PORT_Assert(crlGenData);
01282     if (!crlGenData) {
01283         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01284         return SECFailure;
01285     }
01286 
01287     switch(crlGenData->contextId) {
01288       case CRLGEN_ADD_CERT_CONTEXT:
01289           return crlgen_AddCert(crlGenData, certStr->certId,
01290                          certStr->revocationTime);
01291       case CRLGEN_RM_CERT_CONTEXT:
01292           return crlgen_RmCert(crlGenData, certStr->certId);
01293       default:
01294           PORT_SetError(SEC_ERROR_INVALID_ARGS);
01295           crlgen_PrintError(crlGenData->parsedLineNum,
01296                             "syntax error (unknow token type: %d).\n",
01297                             crlGenData->contextId);
01298           return SECFailure;
01299     }
01300 }
01301 
01302 
01303 /* Sets parsed data for CRL entries update into temporary structure */ 
01304 static SECStatus
01305 crlgen_setNextDataFn_cert(CRLGENGeneratorData *crlGenData, void *str,
01306                    void *data, unsigned short dtype)
01307 {
01308     CRLGENCertEntry *certStr = (CRLGENCertEntry*)str;
01309 
01310     PORT_Assert(crlGenData);
01311     if (!crlGenData) {
01312         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01313         return SECFailure;
01314     }
01315 
01316     switch(dtype) {
01317       case CRLGEN_TYPE_DIGIT:
01318       case CRLGEN_TYPE_DIGIT_RANGE:
01319           certStr->certId = PORT_Strdup(data);
01320           if (!certStr->certId) {
01321               return SECFailure;
01322           }
01323           break;
01324       case CRLGEN_TYPE_DATE:
01325       case CRLGEN_TYPE_ZDATE:
01326           certStr->revocationTime = PORT_Strdup(data);
01327           if (!certStr->revocationTime) {
01328               return SECFailure;
01329           }
01330           break;
01331       default:
01332           PORT_SetError(SEC_ERROR_INVALID_ARGS);
01333           crlgen_PrintError(crlGenData->parsedLineNum,
01334                             "syntax error (unknow token type: %d).\n",
01335                             crlGenData->contextId);
01336           return SECFailure;
01337     }
01338     return SECSuccess;
01339 }
01340 
01341 /* Triggers cert entries/crl extension update */ 
01342 static SECStatus
01343 crlgen_updateCrlFn_extension(CRLGENGeneratorData *crlGenData, void *str)
01344 {
01345     CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry*)str;
01346 
01347     return crlgen_AddExtension(crlGenData, (const char**)extStr->extData);
01348 }
01349 
01350 /* Defines maximum number of fields extension may have */
01351 #define MAX_EXT_DATA_LENGTH 10
01352 
01353 /* Sets parsed extension data for CRL entries/CRL extensions update
01354  * into temporary structure */ 
01355 static SECStatus
01356 crlgen_setNextDataFn_extension(CRLGENGeneratorData *crlGenData, void *str,
01357                         void *data, unsigned short dtype)
01358 {
01359     CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry*)str;
01360 
01361     PORT_Assert(crlGenData);
01362     if (!crlGenData) {
01363         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01364         return SECFailure;
01365     }
01366 
01367     if (extStr->extData == NULL) {
01368         extStr->extData = PORT_ZNewArray(char *, MAX_EXT_DATA_LENGTH);
01369         if (!extStr->extData) {
01370             return SECFailure;
01371         }
01372     }
01373     if (extStr->nextUpdatedData >= MAX_EXT_DATA_LENGTH) {
01374         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01375         crlgen_PrintError(crlGenData->parsedLineNum, 
01376                           "number of fields in extension "
01377                           "exceeded maximum allowed data length: %d.\n",
01378                           MAX_EXT_DATA_LENGTH);
01379         return SECFailure;
01380     }
01381     extStr->extData[extStr->nextUpdatedData] = PORT_Strdup(data);
01382     if (!extStr->extData[extStr->nextUpdatedData]) {
01383         return SECFailure;
01384     }
01385     extStr->nextUpdatedData += 1;
01386 
01387     return SECSuccess;
01388 }
01389 
01390 
01391 /****************************************************************************************
01392  * Top level functions are triggered directly by parser.
01393  */
01394 
01395 /*
01396  * crl generation script parser recreates a temporary data staructure
01397  * for each line it is going through. This function cleans temp structure.
01398  */
01399 void
01400 crlgen_destroyTempData(CRLGENGeneratorData *crlGenData)
01401 {
01402     if (crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
01403         switch(crlGenData->contextId) {
01404           case CRLGEN_ISSUER_CONTEXT:
01405           case CRLGEN_UPDATE_CONTEXT:
01406           case CRLGEN_NEXT_UPDATE_CONTEXT:
01407           case CRLGEN_CHANGE_RANGE_CONTEXT:
01408               if (crlGenData->crlField->value)
01409                   PORT_Free(crlGenData->crlField->value);
01410               PORT_Free(crlGenData->crlField);
01411               break;
01412           case CRLGEN_ADD_CERT_CONTEXT:
01413           case CRLGEN_RM_CERT_CONTEXT:
01414               if (crlGenData->certEntry->certId)
01415                   PORT_Free(crlGenData->certEntry->certId);
01416               if (crlGenData->certEntry->revocationTime)
01417                   PORT_Free(crlGenData->certEntry->revocationTime);
01418               PORT_Free(crlGenData->certEntry);
01419               break;
01420           case CRLGEN_ADD_EXTENSION_CONTEXT:
01421               if (crlGenData->extensionEntry->extData) {
01422                   int i = 0;
01423                   for (;i < crlGenData->extensionEntry->nextUpdatedData;i++)
01424                       PORT_Free(*(crlGenData->extensionEntry->extData + i));
01425                   PORT_Free(crlGenData->extensionEntry->extData);
01426               }
01427               PORT_Free(crlGenData->extensionEntry);
01428               break;
01429         }
01430         crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
01431     }
01432 }
01433 
01434 SECStatus
01435 crlgen_updateCrl(CRLGENGeneratorData *crlGenData)
01436 {
01437     SECStatus rv = SECSuccess;
01438 
01439     PORT_Assert(crlGenData);
01440     if (!crlGenData) {
01441         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01442         return SECFailure;
01443     }
01444 
01445     switch(crlGenData->contextId) {
01446       case CRLGEN_ISSUER_CONTEXT:
01447       case CRLGEN_UPDATE_CONTEXT:
01448       case CRLGEN_NEXT_UPDATE_CONTEXT:
01449       case CRLGEN_CHANGE_RANGE_CONTEXT:
01450           rv = crlGenData->crlField->updateCrlFn(crlGenData, crlGenData->crlField);
01451           break;
01452       case CRLGEN_RM_CERT_CONTEXT:
01453       case CRLGEN_ADD_CERT_CONTEXT:
01454           rv = crlGenData->certEntry->updateCrlFn(crlGenData, crlGenData->certEntry);
01455           break;
01456       case CRLGEN_ADD_EXTENSION_CONTEXT:
01457           rv = crlGenData->extensionEntry->
01458               updateCrlFn(crlGenData, crlGenData->extensionEntry);
01459           break;
01460       case CRLGEN_UNKNOWN_CONTEXT:
01461           break;
01462       default:
01463           crlgen_PrintError(crlGenData->parsedLineNum,
01464                             "unknown lang context type code: %d.\n",
01465                             crlGenData->contextId);
01466           PORT_Assert(0);
01467           return SECFailure;
01468     }
01469     /* Clrean structures after crl update */
01470     crlgen_destroyTempData(crlGenData);
01471 
01472     crlGenData->parsedLineNum += 1;
01473 
01474     return rv;
01475 }
01476 
01477 SECStatus
01478 crlgen_setNextData(CRLGENGeneratorData *crlGenData, void *data,
01479                    unsigned short dtype)
01480 {
01481     SECStatus rv = SECSuccess;
01482 
01483     PORT_Assert(crlGenData);
01484     if (!crlGenData) {
01485         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01486         return SECFailure;
01487     }
01488 
01489     switch(crlGenData->contextId) {
01490       case CRLGEN_ISSUER_CONTEXT:
01491       case CRLGEN_UPDATE_CONTEXT:
01492       case CRLGEN_NEXT_UPDATE_CONTEXT:
01493       case CRLGEN_CHANGE_RANGE_CONTEXT:
01494           rv = crlGenData->crlField->setNextDataFn(crlGenData, crlGenData->crlField,
01495                                                    data, dtype);
01496           break;
01497       case CRLGEN_ADD_CERT_CONTEXT:
01498       case CRLGEN_RM_CERT_CONTEXT:
01499           rv = crlGenData->certEntry->setNextDataFn(crlGenData, crlGenData->certEntry,
01500                                                     data, dtype);
01501           break;
01502       case CRLGEN_ADD_EXTENSION_CONTEXT:
01503           rv =
01504               crlGenData->extensionEntry->
01505               setNextDataFn(crlGenData, crlGenData->extensionEntry, data, dtype);
01506           break;
01507       case CRLGEN_UNKNOWN_CONTEXT:
01508           break;
01509       default:
01510           crlgen_PrintError(crlGenData->parsedLineNum,
01511                             "unknown context type: %d.\n",
01512                             crlGenData->contextId);
01513           PORT_Assert(0);
01514           return SECFailure;
01515     }
01516     return rv;
01517 }
01518 
01519 SECStatus
01520 crlgen_createNewLangStruct(CRLGENGeneratorData *crlGenData,
01521                            unsigned structType)
01522 {
01523     PORT_Assert(crlGenData &&
01524                 crlGenData->contextId == CRLGEN_UNKNOWN_CONTEXT);
01525     if (!crlGenData ||
01526         crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
01527         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01528         return SECFailure;
01529     }
01530 
01531     switch(structType) {
01532       case CRLGEN_ISSUER_CONTEXT:
01533       case CRLGEN_UPDATE_CONTEXT:
01534       case CRLGEN_NEXT_UPDATE_CONTEXT:
01535       case CRLGEN_CHANGE_RANGE_CONTEXT:
01536           crlGenData->crlField = PORT_New(CRLGENCrlField);
01537           if (!crlGenData->crlField) {
01538               return SECFailure;
01539           }
01540           crlGenData->contextId = structType;
01541           crlGenData->crlField->value = NULL;
01542           crlGenData->crlField->updateCrlFn = &crlgen_updateCrlFn_field;
01543           crlGenData->crlField->setNextDataFn = &crlgen_setNextDataFn_field;
01544           break;
01545       case CRLGEN_RM_CERT_CONTEXT:
01546       case CRLGEN_ADD_CERT_CONTEXT:
01547           crlGenData->certEntry = PORT_New(CRLGENCertEntry);
01548           if (!crlGenData->certEntry) {
01549               return SECFailure;
01550           }
01551           crlGenData->contextId = structType;
01552           crlGenData->certEntry->certId = 0;
01553           crlGenData->certEntry->revocationTime = NULL;
01554           crlGenData->certEntry->updateCrlFn = &crlgen_updateCrlFn_cert;
01555           crlGenData->certEntry->setNextDataFn = &crlgen_setNextDataFn_cert;
01556           break;
01557       case CRLGEN_ADD_EXTENSION_CONTEXT:
01558           crlGenData->extensionEntry = PORT_New(CRLGENExtensionEntry);
01559           if (!crlGenData->extensionEntry) {
01560               return SECFailure;
01561           }
01562           crlGenData->contextId = structType;
01563           crlGenData->extensionEntry->extData = NULL;
01564           crlGenData->extensionEntry->nextUpdatedData = 0;
01565           crlGenData->extensionEntry->updateCrlFn =
01566               &crlgen_updateCrlFn_extension;
01567           crlGenData->extensionEntry->setNextDataFn =
01568               &crlgen_setNextDataFn_extension;
01569           break;
01570       case CRLGEN_UNKNOWN_CONTEXT:
01571           break;
01572       default:
01573           crlgen_PrintError(crlGenData->parsedLineNum,
01574                             "unknown context type: %d.\n", structType);
01575           PORT_Assert(0);
01576           return SECFailure;
01577     }
01578     return SECSuccess;
01579 }
01580 
01581 
01582 /* Parser initialization function */
01583 CRLGENGeneratorData*
01584 CRLGEN_InitCrlGeneration(CERTSignedCrl *signCrl, PRFileDesc *src)
01585 {
01586     CRLGENGeneratorData *crlGenData = NULL;
01587 
01588     PORT_Assert(signCrl && src);
01589     if (!signCrl || !src) {
01590         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01591         return NULL;
01592     }
01593 
01594     crlGenData = PORT_ZNew(CRLGENGeneratorData);
01595     if (!crlGenData) {
01596         return NULL;
01597     }
01598 
01599     crlGenData->entryDataHashTable = 
01600         PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
01601                         PL_CompareValues, NULL, NULL);
01602     if (!crlGenData->entryDataHashTable) {
01603         PORT_Free(crlGenData);
01604         return NULL;
01605     }
01606 
01607     crlGenData->src = src;
01608     crlGenData->parsedLineNum = 1;
01609     crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
01610     crlGenData->signCrl = signCrl;
01611     crlGenData->rangeFrom = 0;
01612     crlGenData->rangeTo = 0;
01613     crlGenData->crlExtHandle = NULL;
01614 
01615     PORT_SetError(0);
01616 
01617     return crlGenData;
01618 }
01619 
01620 void
01621 CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData *crlGenData)
01622 {
01623     if (!crlGenData)
01624         return;
01625     if (crlGenData->src)
01626         PR_Close(crlGenData->src);
01627     PL_HashTableDestroy(crlGenData->entryDataHashTable);
01628     PORT_Free(crlGenData);
01629 }
01630