1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is the Netscape security libraries.
16
* The Initial Developer of the Original Code is
17
* Netscape Communications Corporation.
18
* Portions created by the Initial Developer are Copyright (C) 1994-2000
19
* the Initial Developer. All Rights Reserved.
23
* Alternatively, the contents of this file may be used under the terms of
24
* either the GNU General Public License Version 2 or later (the "GPL"), or
25
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
* in which case the provisions of the GPL or the LGPL are applicable instead
27
* of those above. If you wish to allow use of your version of this file only
28
* under the terms of either the GPL or the LGPL, and not to allow others to
29
* use your version of this file under the terms of the MPL, indicate your
30
* decision by deleting the provisions above and replace them with the notice
31
* and other provisions required by the GPL or the LGPL. If you do not delete
32
* the provisions above, a recipient may use your version of this file under
33
* the terms of any one of the MPL, the GPL or the LGPL.
35
* ***** END LICENSE BLOCK ***** */
40
** utility for managing certificates revocation lists generation
59
/* these reroutines were taken from secitem.c, which is supposed to
60
* replace this file some day */
62
* This is the hash function. We simply XOR the encoded form with
63
* itself in sizeof(PLHashNumber)-byte chunks. Improving this
64
* routine is left as an excercise for the more mathematically
67
PLHashNumber PR_CALLBACK
68
SECITEM_Hash ( const void *key)
70
const SECItem *item = (const SECItem *)key;
73
PRUint8 *data = (PRUint8 *)item->data;
75
PRUint8 *rvc = (PRUint8 *)&rv;
77
for( i = 0; i < item->len; i++ ) {
78
rvc[ i % sizeof(rv) ] ^= *data;
86
* This is the key-compare function. It simply does a lexical
87
* comparison on the item data. This does not result in
88
* quite the same ordering as the "sequence of numbers" order,
89
* but heck it's only used internally by the hash table anyway.
92
SECITEM_HashCompare ( const void *k1, const void *k2)
94
const SECItem *i1 = (const SECItem *)k1;
95
const SECItem *i2 = (const SECItem *)k2;
97
return SECITEM_ItemsAreEqual(i1,i2);
100
/* Destroys extHandle and data. data was create on heap.
101
* extHandle creaded by CERT_StartCRLEntryExtensions. entry
102
* was allocated on arena.*/
104
destroyEntryData(CRLGENEntryData *data)
108
PORT_Assert(data->entry);
110
CERT_FinishExtensions(data->extHandle);
115
/* Prints error messages along with line number */
117
crlgen_PrintError(int line, char *msg, ...)
123
fprintf(stderr, "crlgen: (line: %d) ", line);
124
vfprintf(stderr, msg, args);
128
/* Finds CRLGENEntryData in hashtable according PRUint64 value
129
* - certId : cert serial number*/
130
static CRLGENEntryData*
131
crlgen_FindEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
133
if (!crlGenData->entryDataHashTable || !certId)
135
return (CRLGENEntryData*)
136
PL_HashTableLookup(crlGenData->entryDataHashTable,
141
/* Removes CRLGENEntryData from hashtable according to certId
142
* - certId : cert serial number*/
144
crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
146
CRLGENEntryData *data = NULL;
148
if (!crlGenData->entryDataHashTable)
150
data = crlgen_FindEntry(crlGenData, certId);
153
if (PL_HashTableRemove(crlGenData->entryDataHashTable, certId))
155
destroyEntryData(data);
160
/* Stores CRLGENEntryData in hashtable according to certId
161
* - certId : cert serial number*/
162
static CRLGENEntryData*
163
crlgen_PlaceAnEntry(CRLGENGeneratorData *crlGenData,
164
CERTCrlEntry *entry, SECItem *certId)
166
CRLGENEntryData *newData = NULL;
168
PORT_Assert(crlGenData && crlGenData->entryDataHashTable &&
170
if (!crlGenData || !crlGenData->entryDataHashTable || !entry) {
171
PORT_SetError(SEC_ERROR_INVALID_ARGS);
175
newData = PORT_ZNew(CRLGENEntryData);
179
newData->entry = entry;
180
newData->certId = certId;
181
if (!PL_HashTableAdd(crlGenData->entryDataHashTable,
182
newData->certId, newData)) {
183
crlgen_PrintError(crlGenData->parsedLineNum,
184
"Can not add entryData structure\n");
190
/* Use this structure to keep pointer when commiting entries extensions */
193
CERTCrlEntry **entries;
196
/* HT PL_HashTableEnumerateEntries callback. Sorts hashtable entries of the
197
* table he. Returns value through arg parameter*/
198
static PRIntn PR_CALLBACK
199
crlgen_CommitEntryData(PLHashEntry *he, PRIntn i, void *arg)
201
CRLGENEntryData *data = NULL;
205
return HT_ENUMERATE_NEXT;
207
data = (CRLGENEntryData*)he->value;
213
struct commitData *dt = (struct commitData*)arg;
214
dt->entries[dt->pos++] = data->entry;
215
destroyEntryData(data);
217
return HT_ENUMERATE_NEXT;
222
/* Copy char * datainto allocated in arena SECItem */
224
crlgen_SetString(PRArenaPool *arena, const char *dataIn, SECItem *value)
228
PORT_Assert(arena && dataIn);
229
if (!arena || !dataIn) {
230
PORT_SetError(SEC_ERROR_INVALID_ARGS);
234
item.data = (void*)dataIn;
235
item.len = PORT_Strlen(dataIn);
237
return SECITEM_CopyItem(arena, value, &item);
240
/* Creates CERTGeneralName from parsed data for the Authority Key Extension */
241
static CERTGeneralName *
242
crlgen_GetGeneralName (PRArenaPool *arena, CRLGENGeneratorData *crlGenData,
245
CERTGeneralName *namesList = NULL;
246
CERTGeneralName *current;
247
CERTGeneralName *tail = NULL;
248
SECStatus rv = SECSuccess;
249
const char *nextChunk = NULL;
250
const char *currData = NULL;
259
PORT_SetError(SEC_ERROR_INVALID_ARGS);
263
mark = PORT_ArenaMark (arena);
270
const char *sepPrt = NULL;
271
nextChunk = PORT_Strchr(currData, '|');
273
nextChunk = data + strlen(data);
274
sepPrt = PORT_Strchr(currData, ':');
275
if (sepPrt == NULL || sepPrt >= nextChunk) {
279
PORT_Memcpy(buffer, sepPrt + 1,
280
(nextChunk - sepPrt - 1));
281
buffer[nextChunk - sepPrt - 1] = '\0';
283
nameLen = PR_MIN(sepPrt - currData, sizeof(name) - 1 );
284
PORT_Memcpy(name, currData, nameLen);
285
name[nameLen] = '\0';
286
currData = nextChunk + 1;
288
if (!PORT_Strcmp(name, "otherName"))
289
intValue = certOtherName;
290
else if (!PORT_Strcmp(name, "rfc822Name"))
291
intValue = certRFC822Name;
292
else if (!PORT_Strcmp(name, "dnsName"))
293
intValue = certDNSName;
294
else if (!PORT_Strcmp(name, "x400Address"))
295
intValue = certX400Address;
296
else if (!PORT_Strcmp(name, "directoryName"))
297
intValue = certDirectoryName;
298
else if (!PORT_Strcmp(name, "ediPartyName"))
299
intValue = certEDIPartyName;
300
else if (!PORT_Strcmp(name, "URI"))
302
else if (!PORT_Strcmp(name, "ipAddress"))
303
intValue = certIPAddress;
304
else if (!PORT_Strcmp(name, "registerID"))
305
intValue = certRegisterID;
308
if (intValue >= certOtherName && intValue <= certRegisterID) {
309
if (namesList == NULL) {
310
namesList = current = tail = PORT_ArenaZNew(arena,
313
current = PORT_ArenaZNew(arena, CERTGeneralName);
315
if (current == NULL) {
320
PORT_SetError(SEC_ERROR_INVALID_ARGS);
323
current->type = intValue;
324
switch (current->type) {
328
current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer));
329
if (current->name.other.data == NULL) {
333
PORT_Memcpy(current->name.other.data, buffer,
334
current->name.other.len = strlen(buffer));
337
case certEDIPartyName:
341
case certX400Address: {
343
current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer) + 2);
344
if (current->name.other.data == NULL) {
349
PORT_Memcpy (current->name.other.data + 2, buffer, strlen (buffer));
350
/* This may not be accurate for all cases.For now, use this tag type */
351
current->name.other.data[0] = (char)(((current->type - 1) & 0x1f)| 0x80);
352
current->name.other.data[1] = (char)strlen (buffer);
353
current->name.other.len = strlen (buffer) + 2;
357
case certDirectoryName: {
358
CERTName *directoryName = NULL;
360
directoryName = CERT_AsciiToName (buffer);
361
if (!directoryName) {
366
rv = CERT_CopyName (arena, ¤t->name.directoryName, directoryName);
367
CERT_DestroyName (directoryName);
372
if (rv != SECSuccess)
374
current->l.next = &(namesList->l);
375
current->l.prev = &(tail->l);
376
tail->l.next = &(current->l);
379
} while(nextChunk != data + strlen(data));
381
if (rv != SECSuccess) {
382
PORT_ArenaRelease (arena, mark);
388
/* Creates CERTGeneralName from parsed data for the Authority Key Extension */
389
static CERTGeneralName *
390
crlgen_DistinguishedName (PRArenaPool *arena, CRLGENGeneratorData *crlGenData,
393
CERTName *directoryName = NULL;
394
CERTGeneralName *current;
395
SECStatus rv = SECFailure;
402
PORT_SetError(SEC_ERROR_INVALID_ARGS);
406
mark = PORT_ArenaMark (arena);
408
current = PORT_ArenaZNew(arena, CERTGeneralName);
409
if (current == NULL) {
412
current->type = certDirectoryName;
413
current->l.next = ¤t->l;
414
current->l.prev = ¤t->l;
416
directoryName = CERT_AsciiToName ((char*)data);
417
if (!directoryName) {
421
rv = CERT_CopyName (arena, ¤t->name.directoryName, directoryName);
422
CERT_DestroyName (directoryName);
425
if (rv != SECSuccess) {
427
PORT_ArenaRelease (arena, mark);
434
/* Adding Authority Key ID extension to extension handle. */
436
crlgen_AddAuthKeyID (CRLGENGeneratorData *crlGenData,
437
const char **dataArr)
439
void *extHandle = NULL;
440
CERTAuthKeyID *authKeyID = NULL;
441
PRArenaPool *arena = NULL;
442
SECStatus rv = SECSuccess;
444
PORT_Assert(dataArr && crlGenData);
445
if (!crlGenData || !dataArr) {
449
extHandle = crlGenData->crlExtHandle;
451
if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
452
PORT_SetError(SEC_ERROR_INVALID_ARGS);
453
crlgen_PrintError(crlGenData->parsedLineNum,
454
"insufficient number of parameters.\n");
458
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
463
authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID);
464
if (authKeyID == NULL) {
469
if (dataArr[3] == NULL) {
470
rv = crlgen_SetString (arena, dataArr[2], &authKeyID->keyID);
471
if (rv != SECSuccess)
474
rv = crlgen_SetString (arena, dataArr[3],
475
&authKeyID->authCertSerialNumber);
476
if (rv != SECSuccess)
479
authKeyID->authCertIssuer =
480
crlgen_DistinguishedName (arena, crlGenData, dataArr[2]);
481
if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError ()){
482
crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
489
SECU_EncodeAndAddExtensionValue(arena, extHandle, authKeyID,
490
(*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
491
SEC_OID_X509_AUTH_KEY_ID,
492
(EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID);
495
PORT_FreeArena (arena, PR_FALSE);
499
/* Creates and add Subject Alternative Names extension */
501
crlgen_AddIssuerAltNames(CRLGENGeneratorData *crlGenData,
502
const char **dataArr)
504
CERTGeneralName *nameList = NULL;
505
PRArenaPool *arena = NULL;
506
void *extHandle = NULL;
507
SECStatus rv = SECSuccess;
510
PORT_Assert(dataArr && crlGenData);
511
if (!crlGenData || !dataArr) {
515
if (!dataArr || !dataArr[0] || !dataArr[1] || !dataArr[2]) {
516
PORT_SetError(SEC_ERROR_INVALID_ARGS);
517
crlgen_PrintError(crlGenData->parsedLineNum,
518
"insufficient number of arguments.\n");
522
PORT_Assert(dataArr && crlGenData);
523
if (!crlGenData || !dataArr) {
527
extHandle = crlGenData->crlExtHandle;
529
if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
530
PORT_SetError(SEC_ERROR_INVALID_ARGS);
531
crlgen_PrintError(crlGenData->parsedLineNum,
532
"insufficient number of parameters.\n");
536
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
541
nameList = crlgen_GetGeneralName(arena, crlGenData, dataArr[2]);
542
if (nameList == NULL) {
543
crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
549
SECU_EncodeAndAddExtensionValue(arena, extHandle, nameList,
550
(*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
551
SEC_OID_X509_ISSUER_ALT_NAME,
552
(EXTEN_EXT_VALUE_ENCODER)CERT_EncodeAltNameExtension);
555
PORT_FreeArena (arena, PR_FALSE);
559
/* Creates and adds CRLNumber extension to extension handle.
560
* Since, this is CRL extension, extension handle is the one
561
* related to CRL extensions */
563
crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
565
PRArenaPool *arena = NULL;
567
void *extHandle = crlGenData->crlExtHandle;
569
SECStatus rv = SECFailure;
572
PORT_Assert(dataArr && crlGenData);
573
if (!crlGenData || !dataArr) {
577
if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
578
PORT_SetError(SEC_ERROR_INVALID_ARGS);
579
crlgen_PrintError(crlGenData->parsedLineNum,
580
"insufficient number of arguments.\n");
584
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
589
code = atoi(dataArr[2]);
590
if (code == 0 && *dataArr[2] != '0') {
591
PORT_SetError(SEC_ERROR_INVALID_ARGS);
595
dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
601
rv = CERT_AddExtension (extHandle, SEC_OID_X509_CRL_NUMBER, &encodedItem,
602
(*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
607
PORT_FreeArena(arena, PR_FALSE);
613
/* Creates Cert Revocation Reason code extension. Encodes it and
614
* returns as SECItem structure */
616
crlgen_CreateReasonCode(PRArenaPool *arena, const char **dataArr,
619
SECItem *encodedItem;
624
PORT_Assert(arena && dataArr);
625
if (!arena || !dataArr) {
629
mark = PORT_ArenaMark(arena);
631
encodedItem = PORT_ArenaZNew (arena, SECItem);
632
if (encodedItem == NULL) {
636
if (dataArr[2] == NULL) {
637
PORT_SetError(SEC_ERROR_INVALID_ARGS);
641
code = atoi(dataArr[2]);
642
/* aACompromise(10) is the last possible of the values
643
* for the Reason Core Extension */
644
if ((code == 0 && *dataArr[2] != '0') || code > 10) {
646
PORT_SetError(SEC_ERROR_INVALID_ARGS);
650
dummy = SEC_ASN1EncodeInteger(arena, encodedItem, code);
655
*extCode = SEC_OID_X509_REASON_CODE;
659
PORT_ArenaRelease (arena, mark);
663
/* Creates Cert Invalidity Date extension. Encodes it and
664
* returns as SECItem structure */
666
crlgen_CreateInvalidityDate(PRArenaPool *arena, const char **dataArr,
669
SECItem *encodedItem;
673
PORT_Assert(arena && dataArr);
674
if (!arena || !dataArr) {
678
mark = PORT_ArenaMark(arena);
680
encodedItem = PORT_ArenaZNew(arena, SECItem);
681
if (encodedItem == NULL) {
685
length = PORT_Strlen(dataArr[2]);
687
encodedItem->type = siGeneralizedTime;
688
encodedItem->data = PORT_ArenaAlloc(arena, length);
689
if (!encodedItem->data) {
693
PORT_Memcpy(encodedItem->data, dataArr[2], (encodedItem->len = length) *
696
*extCode = SEC_OID_X509_INVALID_DATE;
700
PORT_ArenaRelease(arena, mark);
704
/* Creates(by calling extCreator function) and adds extension to a set
705
* of already added certs. Uses values of rangeFrom and rangeTo from
706
* CRLGENCrlGenCtl structure for identifying the inclusive set of certs */
708
crlgen_AddEntryExtension(CRLGENGeneratorData *crlGenData,
709
const char **dataArr, char *extName,
710
SECItem* (*extCreator)(PRArenaPool *arena,
711
const char **dataArr,
715
SECStatus rv = SECFailure;
719
PRArenaPool *arena = NULL;
722
PORT_Assert(crlGenData && dataArr);
723
if (!crlGenData || !dataArr) {
727
if (!dataArr[0] || !dataArr[1]) {
728
PORT_SetError(SEC_ERROR_INVALID_ARGS);
729
crlgen_PrintError(crlGenData->parsedLineNum,
730
"insufficient number of arguments.\n");
733
lastRange = crlGenData->rangeTo - crlGenData->rangeFrom + 1;
735
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
740
ext = extCreator(arena, dataArr, &extCode);
742
crlgen_PrintError(crlGenData->parsedLineNum,
743
"got error while creating extension: %s\n",
748
for (i = 0;i < lastRange;i++) {
749
CRLGENEntryData * extData = NULL;
750
void *extHandle = NULL;
751
SECItem * certIdItem =
752
SEC_ASN1EncodeInteger(arena, NULL,
753
crlGenData->rangeFrom + i);
759
extData = crlgen_FindEntry(crlGenData, certIdItem);
761
crlgen_PrintError(crlGenData->parsedLineNum,
762
"can not add extension: crl entry "
763
"(serial number: %d) is not in the list yet.\n",
764
crlGenData->rangeFrom + i);
768
extHandle = extData->extHandle;
769
if (extHandle == NULL) {
770
extHandle = extData->extHandle =
771
CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
772
(CERTCrlEntry*)extData->entry);
774
rv = CERT_AddExtension (extHandle, extCode, ext,
775
(*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
777
if (rv == SECFailure) {
784
PORT_FreeArena(arena, PR_FALSE);
789
/* Commits all added entries and their's extensions into CRL. */
791
CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData *crlGenData)
796
SECStatus rv = SECSuccess;
799
PORT_Assert(crlGenData && crlGenData->signCrl && crlGenData->signCrl->arena);
800
if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
801
PORT_SetError(SEC_ERROR_INVALID_ARGS);
805
arena = crlGenData->signCrl->arena;
806
crl = &crlGenData->signCrl->crl;
808
mark = PORT_ArenaMark(arena);
810
if (crlGenData->crlExtHandle)
811
CERT_FinishExtensions(crlGenData->crlExtHandle);
813
size = crlGenData->entryDataHashTable->nentries;
816
crl->entries = PORT_ArenaZNewArray(arena, CERTCrlEntry*, size + 1);
820
struct commitData dt;
821
dt.entries = crl->entries;
823
PL_HashTableEnumerateEntries(crlGenData->entryDataHashTable,
824
&crlgen_CommitEntryData, &dt);
825
/* Last should be NULL */
826
crl->entries[size] = NULL;
830
if (rv != SECSuccess)
831
PORT_ArenaRelease(arena, mark);
835
/* Initializes extHandle with data from extensions array */
837
crlgen_InitExtensionHandle(void *extHandle,
838
CERTCertExtension **extensions)
840
CERTCertExtension *extension = NULL;
845
PORT_Assert(extHandle != NULL);
850
extension = *extensions;
852
SECOidTag oidTag = SECOID_FindOIDTag (&extension->id);
853
/* shell we skip unknown extensions? */
854
CERT_AddExtension (extHandle, oidTag, &extension->value,
855
(extension->critical.len != 0) ? PR_TRUE : PR_FALSE,
857
extension = *(++extensions);
862
/* Used for initialization of extension handles for crl and certs
863
* extensions from existing CRL data then modifying existing CRL.*/
865
CRLGEN_ExtHandleInit(CRLGENGeneratorData *crlGenData)
870
PORT_Assert(crlGenData && crlGenData->signCrl &&
871
crlGenData->entryDataHashTable);
872
if (!crlGenData || !crlGenData->signCrl ||
873
!crlGenData->entryDataHashTable) {
874
PORT_SetError(SEC_ERROR_INVALID_ARGS);
878
crl = &crlGenData->signCrl->crl;
879
crlGenData->crlExtHandle = CERT_StartCRLExtensions(crl);
880
crlgen_InitExtensionHandle(crlGenData->crlExtHandle,
882
crl->extensions = NULL;
885
CERTCrlEntry **entry = crl->entries;
887
PRUint64 sn = DER_GetInteger(&(*entry)->serialNumber);
888
CRLGENEntryData *extData =
889
crlgen_PlaceAnEntry(crlGenData, *entry, &(*entry)->serialNumber);
890
if ((*entry)->extensions) {
892
CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
893
(CERTCrlEntry*)extData->entry);
894
if (crlgen_InitExtensionHandle(extData->extHandle,
895
(*entry)->extensions) == SECFailure)
898
(*entry)->extensions = NULL;
900
maxSN = PR_MAX(maxSN, sn);
904
crlGenData->rangeFrom = crlGenData->rangeTo = maxSN + 1;
908
/*****************************************************************************
909
* Parser trigger functions start here
912
/* Sets new internal range value for add/rm certs.*/
914
crlgen_SetNewRangeField(CRLGENGeneratorData *crlGenData, char *value)
916
long rangeFrom = 0, rangeTo = 0;
917
char *dashPos = NULL;
919
PORT_Assert(crlGenData);
921
PORT_SetError(SEC_ERROR_INVALID_ARGS);
926
PORT_SetError(SEC_ERROR_INVALID_ARGS);
927
crlgen_PrintError(crlGenData->parsedLineNum,
928
"insufficient number of arguments.\n");
932
if ((dashPos = strchr(value, '-')) != NULL) {
933
char *rangeToS, *rangeFromS = value;
935
rangeFrom = atoi(rangeFromS);
938
rangeToS = (char*)(dashPos + 1);
939
rangeTo = atol(rangeToS);
941
rangeFrom = atol(value);
945
if (rangeFrom < 1 || rangeTo<rangeFrom) {
946
PORT_SetError(SEC_ERROR_INVALID_ARGS);
947
crlgen_PrintError(crlGenData->parsedLineNum,
948
"bad cert id range: %s.\n", value);
952
crlGenData->rangeFrom = rangeFrom;
953
crlGenData->rangeTo = rangeTo;
958
/* Changes issuer subject field in CRL. By default this data is taken from
959
* issuer cert subject field.Not yet implemented */
961
crlgen_SetIssuerField(CRLGENGeneratorData *crlGenData, char *value)
963
crlgen_PrintError(crlGenData->parsedLineNum,
964
"Can not change CRL issuer field.\n");
968
/* Encode and sets CRL thisUpdate and nextUpdate time fields*/
970
crlgen_SetTimeField(CRLGENGeneratorData *crlGenData, char *value,
971
PRBool setThisUpdate)
973
CERTSignedCrl *signCrl;
977
SECItem *timeDest = NULL;
979
PORT_Assert(crlGenData && crlGenData->signCrl &&
980
crlGenData->signCrl->arena);
981
if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
982
PORT_SetError(SEC_ERROR_INVALID_ARGS);
986
signCrl = crlGenData->signCrl;
987
arena = signCrl->arena;
991
PORT_SetError(SEC_ERROR_INVALID_ARGS);
992
crlgen_PrintError(crlGenData->parsedLineNum,
993
"insufficient number of arguments.\n");
996
length = PORT_Strlen(value);
998
if (setThisUpdate == PR_TRUE) {
999
timeDest = &crl->lastUpdate;
1001
timeDest = &crl->nextUpdate;
1004
timeDest->type = siGeneralizedTime;
1005
timeDest->data = PORT_ArenaAlloc(arena, length);
1006
if (!timeDest->data) {
1009
PORT_Memcpy(timeDest->data, value, length);
1010
timeDest->len = length;
1016
/* Adds new extension into CRL or added cert handles */
1018
crlgen_AddExtension(CRLGENGeneratorData *crlGenData, const char **extData)
1020
PORT_Assert(crlGenData && crlGenData->crlExtHandle);
1021
if (!crlGenData || !crlGenData->crlExtHandle) {
1022
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1026
if (extData == NULL || *extData == NULL) {
1027
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1028
crlgen_PrintError(crlGenData->parsedLineNum,
1029
"insufficient number of arguments.\n");
1032
if (!PORT_Strcmp(*extData, "authKeyId"))
1033
return crlgen_AddAuthKeyID(crlGenData, extData);
1034
else if (!PORT_Strcmp(*extData, "issuerAltNames"))
1035
return crlgen_AddIssuerAltNames(crlGenData, extData);
1036
else if (!PORT_Strcmp(*extData, "crlNumber"))
1037
return crlgen_AddCrlNumber(crlGenData, extData);
1038
else if (!PORT_Strcmp(*extData, "reasonCode"))
1039
return crlgen_AddEntryExtension(crlGenData, extData, "reasonCode",
1040
crlgen_CreateReasonCode);
1041
else if (!PORT_Strcmp(*extData, "invalidityDate"))
1042
return crlgen_AddEntryExtension(crlGenData, extData, "invalidityDate",
1043
crlgen_CreateInvalidityDate);
1045
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1046
crlgen_PrintError(crlGenData->parsedLineNum,
1047
"insufficient number of arguments.\n");
1054
/* Created CRLGENEntryData for cert with serial number certId and
1055
* adds it to entryDataHashTable. certId can be a single cert serial
1056
* number or an inclusive rage of certs */
1058
crlgen_AddCert(CRLGENGeneratorData *crlGenData,
1059
char *certId, char *revocationDate)
1061
CERTSignedCrl *signCrl;
1062
SECItem *certIdItem;
1064
PRUint64 rangeFrom = 0, rangeTo = 0, i = 0;
1065
int timeValLength = -1;
1066
SECStatus rv = SECFailure;
1070
PORT_Assert(crlGenData && crlGenData->signCrl &&
1071
crlGenData->signCrl->arena);
1072
if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
1073
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1077
signCrl = crlGenData->signCrl;
1078
arena = signCrl->arena;
1080
if (!certId || !revocationDate) {
1081
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1082
crlgen_PrintError(crlGenData->parsedLineNum,
1083
"insufficient number of arguments.\n");
1087
timeValLength = strlen(revocationDate);
1089
if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
1093
rangeFrom = crlGenData->rangeFrom;
1094
rangeTo = crlGenData->rangeTo;
1096
for (i = 0;i < rangeTo - rangeFrom + 1;i++) {
1097
CERTCrlEntry *entry;
1098
mark = PORT_ArenaMark(arena);
1099
entry = PORT_ArenaZNew(arena, CERTCrlEntry);
1100
if (entry == NULL) {
1104
certIdItem = SEC_ASN1EncodeInteger(arena, &entry->serialNumber,
1110
if (crlgen_FindEntry(crlGenData, certIdItem)) {
1111
crlgen_PrintError(crlGenData->parsedLineNum,
1112
"entry already exists. Use \"range\" "
1113
"and \"rmcert\" before adding a new one with the "
1114
"same serial number %ld\n", rangeFrom + i);
1118
entry->serialNumber.type = siBuffer;
1120
entry->revocationDate.type = siGeneralizedTime;
1122
entry->revocationDate.data =
1123
PORT_ArenaAlloc(arena, timeValLength);
1124
if (entry->revocationDate.data == NULL) {
1128
PORT_Memcpy(entry->revocationDate.data, revocationDate,
1129
timeValLength * sizeof(char));
1130
entry->revocationDate.len = timeValLength;
1133
entry->extensions = NULL;
1134
if (!crlgen_PlaceAnEntry(crlGenData, entry, certIdItem)) {
1143
PORT_ArenaRelease(arena, mark);
1149
/* Removes certs from entryDataHashTable which have certId serial number.
1150
* certId can have value of a range of certs */
1152
crlgen_RmCert(CRLGENGeneratorData *crlGenData, char *certId)
1157
PORT_Assert(crlGenData && certId);
1158
if (!crlGenData || !certId) {
1159
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1163
arena = crlGenData->signCrl->arena;
1165
if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
1170
for (i = 0;i < crlGenData->rangeTo - crlGenData->rangeFrom + 1;i++) {
1171
SECItem* certIdItem = SEC_ASN1EncodeInteger(NULL, NULL,
1172
crlGenData->rangeFrom + i);
1174
CRLGENEntryData *extData =
1175
crlgen_FindEntry(crlGenData, certIdItem);
1177
printf("Cert with id %s is not in the list\n", certId);
1179
crlgen_RmEntry(crlGenData, certIdItem);
1181
SECITEM_FreeItem(certIdItem, PR_TRUE);
1188
/*************************************************************************
1189
* Lex Parser Helper functions are used to store parsed information
1190
* in context related structures. Context(or state) is identified base on
1191
* a type of a instruction parser currently is going through. New context
1192
* is identified by first token in a line. It can be addcert context,
1193
* addext context, etc. */
1195
/* Updates CRL field depending on current context */
1197
crlgen_updateCrlFn_field(CRLGENGeneratorData *crlGenData, void *str)
1199
CRLGENCrlField *fieldStr = (CRLGENCrlField*)str;
1201
PORT_Assert(crlGenData);
1203
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1207
switch(crlGenData->contextId) {
1208
case CRLGEN_ISSUER_CONTEXT:
1209
crlgen_SetIssuerField(crlGenData, fieldStr->value);
1211
case CRLGEN_UPDATE_CONTEXT:
1212
return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_TRUE);
1214
case CRLGEN_NEXT_UPDATE_CONTEXT:
1215
return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_FALSE);
1217
case CRLGEN_CHANGE_RANGE_CONTEXT:
1218
return crlgen_SetNewRangeField(crlGenData, fieldStr->value);
1221
crlgen_PrintError(crlGenData->parsedLineNum,
1222
"syntax error (unknow token type: %d)\n",
1223
crlGenData->contextId);
1224
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1230
/* Sets parsed data for CRL field update into temporary structure */
1232
crlgen_setNextDataFn_field(CRLGENGeneratorData *crlGenData, void *str,
1233
void *data, unsigned short dtype)
1235
CRLGENCrlField *fieldStr = (CRLGENCrlField*)str;
1237
PORT_Assert(crlGenData);
1239
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1243
switch (crlGenData->contextId) {
1244
case CRLGEN_CHANGE_RANGE_CONTEXT:
1245
if (dtype != CRLGEN_TYPE_DIGIT || dtype != CRLGEN_TYPE_DIGIT_RANGE) {
1246
crlgen_PrintError(crlGenData->parsedLineNum,
1247
"range value should have "
1248
"numeric or numeric range values.\n");
1252
case CRLGEN_NEXT_UPDATE_CONTEXT:
1253
case CRLGEN_UPDATE_CONTEXT:
1254
if (dtype != CRLGEN_TYPE_ZDATE){
1255
crlgen_PrintError(crlGenData->parsedLineNum,
1256
"bad formated date. Should be "
1257
"YYYYMMDDHHMMSSZ.\n");
1262
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1263
crlgen_PrintError(crlGenData->parsedLineNum,
1264
"syntax error (unknow token type: %d).\n",
1265
crlGenData->contextId, data);
1268
fieldStr->value = PORT_Strdup(data);
1269
if (!fieldStr->value) {
1275
/* Triggers cert entries update depending on current context */
1277
crlgen_updateCrlFn_cert(CRLGENGeneratorData *crlGenData, void *str)
1279
CRLGENCertEntry *certStr = (CRLGENCertEntry*)str;
1281
PORT_Assert(crlGenData);
1283
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1287
switch(crlGenData->contextId) {
1288
case CRLGEN_ADD_CERT_CONTEXT:
1289
return crlgen_AddCert(crlGenData, certStr->certId,
1290
certStr->revocationTime);
1291
case CRLGEN_RM_CERT_CONTEXT:
1292
return crlgen_RmCert(crlGenData, certStr->certId);
1294
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1295
crlgen_PrintError(crlGenData->parsedLineNum,
1296
"syntax error (unknow token type: %d).\n",
1297
crlGenData->contextId);
1303
/* Sets parsed data for CRL entries update into temporary structure */
1305
crlgen_setNextDataFn_cert(CRLGENGeneratorData *crlGenData, void *str,
1306
void *data, unsigned short dtype)
1308
CRLGENCertEntry *certStr = (CRLGENCertEntry*)str;
1310
PORT_Assert(crlGenData);
1312
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1317
case CRLGEN_TYPE_DIGIT:
1318
case CRLGEN_TYPE_DIGIT_RANGE:
1319
certStr->certId = PORT_Strdup(data);
1320
if (!certStr->certId) {
1324
case CRLGEN_TYPE_DATE:
1325
case CRLGEN_TYPE_ZDATE:
1326
certStr->revocationTime = PORT_Strdup(data);
1327
if (!certStr->revocationTime) {
1332
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1333
crlgen_PrintError(crlGenData->parsedLineNum,
1334
"syntax error (unknow token type: %d).\n",
1335
crlGenData->contextId);
1341
/* Triggers cert entries/crl extension update */
1343
crlgen_updateCrlFn_extension(CRLGENGeneratorData *crlGenData, void *str)
1345
CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry*)str;
1347
return crlgen_AddExtension(crlGenData, (const char**)extStr->extData);
1350
/* Defines maximum number of fields extension may have */
1351
#define MAX_EXT_DATA_LENGTH 10
1353
/* Sets parsed extension data for CRL entries/CRL extensions update
1354
* into temporary structure */
1356
crlgen_setNextDataFn_extension(CRLGENGeneratorData *crlGenData, void *str,
1357
void *data, unsigned short dtype)
1359
CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry*)str;
1361
PORT_Assert(crlGenData);
1363
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1367
if (extStr->extData == NULL) {
1368
extStr->extData = PORT_ZNewArray(char *, MAX_EXT_DATA_LENGTH);
1369
if (!extStr->extData) {
1373
if (extStr->nextUpdatedData >= MAX_EXT_DATA_LENGTH) {
1374
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1375
crlgen_PrintError(crlGenData->parsedLineNum,
1376
"number of fields in extension "
1377
"exceeded maximum allowed data length: %d.\n",
1378
MAX_EXT_DATA_LENGTH);
1381
extStr->extData[extStr->nextUpdatedData] = PORT_Strdup(data);
1382
if (!extStr->extData[extStr->nextUpdatedData]) {
1385
extStr->nextUpdatedData += 1;
1391
/****************************************************************************************
1392
* Top level functions are triggered directly by parser.
1396
* crl generation script parser recreates a temporary data staructure
1397
* for each line it is going through. This function cleans temp structure.
1400
crlgen_destroyTempData(CRLGENGeneratorData *crlGenData)
1402
if (crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
1403
switch(crlGenData->contextId) {
1404
case CRLGEN_ISSUER_CONTEXT:
1405
case CRLGEN_UPDATE_CONTEXT:
1406
case CRLGEN_NEXT_UPDATE_CONTEXT:
1407
case CRLGEN_CHANGE_RANGE_CONTEXT:
1408
if (crlGenData->crlField->value)
1409
PORT_Free(crlGenData->crlField->value);
1410
PORT_Free(crlGenData->crlField);
1412
case CRLGEN_ADD_CERT_CONTEXT:
1413
case CRLGEN_RM_CERT_CONTEXT:
1414
if (crlGenData->certEntry->certId)
1415
PORT_Free(crlGenData->certEntry->certId);
1416
if (crlGenData->certEntry->revocationTime)
1417
PORT_Free(crlGenData->certEntry->revocationTime);
1418
PORT_Free(crlGenData->certEntry);
1420
case CRLGEN_ADD_EXTENSION_CONTEXT:
1421
if (crlGenData->extensionEntry->extData) {
1423
for (;i < crlGenData->extensionEntry->nextUpdatedData;i++)
1424
PORT_Free(*(crlGenData->extensionEntry->extData + i));
1425
PORT_Free(crlGenData->extensionEntry->extData);
1427
PORT_Free(crlGenData->extensionEntry);
1430
crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
1435
crlgen_updateCrl(CRLGENGeneratorData *crlGenData)
1437
SECStatus rv = SECSuccess;
1439
PORT_Assert(crlGenData);
1441
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1445
switch(crlGenData->contextId) {
1446
case CRLGEN_ISSUER_CONTEXT:
1447
case CRLGEN_UPDATE_CONTEXT:
1448
case CRLGEN_NEXT_UPDATE_CONTEXT:
1449
case CRLGEN_CHANGE_RANGE_CONTEXT:
1450
rv = crlGenData->crlField->updateCrlFn(crlGenData, crlGenData->crlField);
1452
case CRLGEN_RM_CERT_CONTEXT:
1453
case CRLGEN_ADD_CERT_CONTEXT:
1454
rv = crlGenData->certEntry->updateCrlFn(crlGenData, crlGenData->certEntry);
1456
case CRLGEN_ADD_EXTENSION_CONTEXT:
1457
rv = crlGenData->extensionEntry->
1458
updateCrlFn(crlGenData, crlGenData->extensionEntry);
1460
case CRLGEN_UNKNOWN_CONTEXT:
1463
crlgen_PrintError(crlGenData->parsedLineNum,
1464
"unknown lang context type code: %d.\n",
1465
crlGenData->contextId);
1469
/* Clrean structures after crl update */
1470
crlgen_destroyTempData(crlGenData);
1472
crlGenData->parsedLineNum += 1;
1478
crlgen_setNextData(CRLGENGeneratorData *crlGenData, void *data,
1479
unsigned short dtype)
1481
SECStatus rv = SECSuccess;
1483
PORT_Assert(crlGenData);
1485
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1489
switch(crlGenData->contextId) {
1490
case CRLGEN_ISSUER_CONTEXT:
1491
case CRLGEN_UPDATE_CONTEXT:
1492
case CRLGEN_NEXT_UPDATE_CONTEXT:
1493
case CRLGEN_CHANGE_RANGE_CONTEXT:
1494
rv = crlGenData->crlField->setNextDataFn(crlGenData, crlGenData->crlField,
1497
case CRLGEN_ADD_CERT_CONTEXT:
1498
case CRLGEN_RM_CERT_CONTEXT:
1499
rv = crlGenData->certEntry->setNextDataFn(crlGenData, crlGenData->certEntry,
1502
case CRLGEN_ADD_EXTENSION_CONTEXT:
1504
crlGenData->extensionEntry->
1505
setNextDataFn(crlGenData, crlGenData->extensionEntry, data, dtype);
1507
case CRLGEN_UNKNOWN_CONTEXT:
1510
crlgen_PrintError(crlGenData->parsedLineNum,
1511
"unknown context type: %d.\n",
1512
crlGenData->contextId);
1520
crlgen_createNewLangStruct(CRLGENGeneratorData *crlGenData,
1521
unsigned structType)
1523
PORT_Assert(crlGenData &&
1524
crlGenData->contextId == CRLGEN_UNKNOWN_CONTEXT);
1526
crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
1527
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1531
switch(structType) {
1532
case CRLGEN_ISSUER_CONTEXT:
1533
case CRLGEN_UPDATE_CONTEXT:
1534
case CRLGEN_NEXT_UPDATE_CONTEXT:
1535
case CRLGEN_CHANGE_RANGE_CONTEXT:
1536
crlGenData->crlField = PORT_New(CRLGENCrlField);
1537
if (!crlGenData->crlField) {
1540
crlGenData->contextId = structType;
1541
crlGenData->crlField->value = NULL;
1542
crlGenData->crlField->updateCrlFn = &crlgen_updateCrlFn_field;
1543
crlGenData->crlField->setNextDataFn = &crlgen_setNextDataFn_field;
1545
case CRLGEN_RM_CERT_CONTEXT:
1546
case CRLGEN_ADD_CERT_CONTEXT:
1547
crlGenData->certEntry = PORT_New(CRLGENCertEntry);
1548
if (!crlGenData->certEntry) {
1551
crlGenData->contextId = structType;
1552
crlGenData->certEntry->certId = 0;
1553
crlGenData->certEntry->revocationTime = NULL;
1554
crlGenData->certEntry->updateCrlFn = &crlgen_updateCrlFn_cert;
1555
crlGenData->certEntry->setNextDataFn = &crlgen_setNextDataFn_cert;
1557
case CRLGEN_ADD_EXTENSION_CONTEXT:
1558
crlGenData->extensionEntry = PORT_New(CRLGENExtensionEntry);
1559
if (!crlGenData->extensionEntry) {
1562
crlGenData->contextId = structType;
1563
crlGenData->extensionEntry->extData = NULL;
1564
crlGenData->extensionEntry->nextUpdatedData = 0;
1565
crlGenData->extensionEntry->updateCrlFn =
1566
&crlgen_updateCrlFn_extension;
1567
crlGenData->extensionEntry->setNextDataFn =
1568
&crlgen_setNextDataFn_extension;
1570
case CRLGEN_UNKNOWN_CONTEXT:
1573
crlgen_PrintError(crlGenData->parsedLineNum,
1574
"unknown context type: %d.\n", structType);
1582
/* Parser initialization function */
1583
CRLGENGeneratorData*
1584
CRLGEN_InitCrlGeneration(CERTSignedCrl *signCrl, PRFileDesc *src)
1586
CRLGENGeneratorData *crlGenData = NULL;
1588
PORT_Assert(signCrl && src);
1589
if (!signCrl || !src) {
1590
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1594
crlGenData = PORT_ZNew(CRLGENGeneratorData);
1599
crlGenData->entryDataHashTable =
1600
PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
1601
PL_CompareValues, NULL, NULL);
1602
if (!crlGenData->entryDataHashTable) {
1603
PORT_Free(crlGenData);
1607
crlGenData->src = src;
1608
crlGenData->parsedLineNum = 1;
1609
crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
1610
crlGenData->signCrl = signCrl;
1611
crlGenData->rangeFrom = 0;
1612
crlGenData->rangeTo = 0;
1613
crlGenData->crlExtHandle = NULL;
1621
CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData *crlGenData)
1625
if (crlGenData->src)
1626
PR_Close(crlGenData->src);
1627
PL_HashTableDestroy(crlGenData->entryDataHashTable);
1628
PORT_Free(crlGenData);