nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / cmd / crlutil / crlgen.c
blobe0d525e3b177842fd8f8a39701c877543ad8add9
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
12 * License.
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.
21 * Contributor(s):
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 ***** */
38 ** crlgen.c
40 ** utility for managing certificates revocation lists generation
45 #include <stdio.h>
46 #include <math.h>
48 #include "nspr.h"
49 #include "plgetopt.h"
50 #include "nss.h"
51 #include "secutil.h"
52 #include "cert.h"
53 #include "certi.h"
54 #include "certdb.h"
55 #include "pk11func.h"
56 #include "crlgen.h"
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
65 * inclined student.
67 PLHashNumber PR_CALLBACK
68 SECITEM_Hash ( const void *key)
70 const SECItem *item = (const SECItem *)key;
71 PLHashNumber rv = 0;
73 PRUint8 *data = (PRUint8 *)item->data;
74 PRUint32 i;
75 PRUint8 *rvc = (PRUint8 *)&rv;
77 for( i = 0; i < item->len; i++ ) {
78 rvc[ i % sizeof(rv) ] ^= *data;
79 data++;
82 return rv;
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.
91 PRIntn PR_CALLBACK
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.*/
103 static void
104 destroyEntryData(CRLGENEntryData *data)
106 if (!data)
107 return;
108 PORT_Assert(data->entry);
109 if (data->extHandle)
110 CERT_FinishExtensions(data->extHandle);
111 PORT_Free(data);
115 /* Prints error messages along with line number */
116 void
117 crlgen_PrintError(int line, char *msg, ...)
119 va_list args;
121 va_start(args, msg);
123 fprintf(stderr, "crlgen: (line: %d) ", line);
124 vfprintf(stderr, msg, args);
126 va_end(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)
134 return NULL;
135 return (CRLGENEntryData*)
136 PL_HashTableLookup(crlGenData->entryDataHashTable,
137 certId);
141 /* Removes CRLGENEntryData from hashtable according to certId
142 * - certId : cert serial number*/
143 static SECStatus
144 crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
146 CRLGENEntryData *data = NULL;
148 if (!crlGenData->entryDataHashTable)
149 return SECSuccess;
150 data = crlgen_FindEntry(crlGenData, certId);
151 if (!data)
152 return SECSuccess;
153 if (PL_HashTableRemove(crlGenData->entryDataHashTable, certId))
154 return SECSuccess;
155 destroyEntryData(data);
156 return SECFailure;
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 &&
169 entry);
170 if (!crlGenData || !crlGenData->entryDataHashTable || !entry) {
171 PORT_SetError(SEC_ERROR_INVALID_ARGS);
172 return NULL;
175 newData = PORT_ZNew(CRLGENEntryData);
176 if (!newData) {
177 return NULL;
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");
185 return NULL;
187 return newData;
190 /* Use this structure to keep pointer when commiting entries extensions */
191 struct commitData {
192 int pos;
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;
203 PORT_Assert(he);
204 if (!he) {
205 return HT_ENUMERATE_NEXT;
207 data = (CRLGENEntryData*)he->value;
209 PORT_Assert(data);
210 PORT_Assert(arg);
212 if (data) {
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 */
223 static SECStatus
224 crlgen_SetString(PRArenaPool *arena, const char *dataIn, SECItem *value)
226 SECItem item;
228 PORT_Assert(arena && dataIn);
229 if (!arena || !dataIn) {
230 PORT_SetError(SEC_ERROR_INVALID_ARGS);
231 return SECFailure;
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,
243 const char *data)
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;
251 int intValue;
252 char buffer[512];
253 void *mark;
255 if (!data)
256 return NULL;
257 PORT_Assert (arena);
258 if (!arena) {
259 PORT_SetError(SEC_ERROR_INVALID_ARGS);
260 return NULL;
263 mark = PORT_ArenaMark (arena);
265 nextChunk = data;
266 currData = data;
267 do {
268 int nameLen = 0;
269 char name[128];
270 const char *sepPrt = NULL;
271 nextChunk = PORT_Strchr(currData, '|');
272 if (!nextChunk)
273 nextChunk = data + strlen(data);
274 sepPrt = PORT_Strchr(currData, ':');
275 if (sepPrt == NULL || sepPrt >= nextChunk) {
276 *buffer = '\0';
277 sepPrt = nextChunk;
278 } else {
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"))
301 intValue = certURI;
302 else if (!PORT_Strcmp(name, "ipAddress"))
303 intValue = certIPAddress;
304 else if (!PORT_Strcmp(name, "registerID"))
305 intValue = certRegisterID;
306 else intValue = -1;
308 if (intValue >= certOtherName && intValue <= certRegisterID) {
309 if (namesList == NULL) {
310 namesList = current = tail = PORT_ArenaZNew(arena,
311 CERTGeneralName);
312 } else {
313 current = PORT_ArenaZNew(arena, CERTGeneralName);
315 if (current == NULL) {
316 rv = SECFailure;
317 break;
319 } else {
320 PORT_SetError(SEC_ERROR_INVALID_ARGS);
321 break;
323 current->type = intValue;
324 switch (current->type) {
325 case certURI:
326 case certDNSName:
327 case certRFC822Name:
328 current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer));
329 if (current->name.other.data == NULL) {
330 rv = SECFailure;
331 break;
333 PORT_Memcpy(current->name.other.data, buffer,
334 current->name.other.len = strlen(buffer));
335 break;
337 case certEDIPartyName:
338 case certIPAddress:
339 case certOtherName:
340 case certRegisterID:
341 case certX400Address: {
343 current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer) + 2);
344 if (current->name.other.data == NULL) {
345 rv = SECFailure;
346 break;
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;
354 break;
357 case certDirectoryName: {
358 CERTName *directoryName = NULL;
360 directoryName = CERT_AsciiToName (buffer);
361 if (!directoryName) {
362 rv = SECFailure;
363 break;
366 rv = CERT_CopyName (arena, &current->name.directoryName, directoryName);
367 CERT_DestroyName (directoryName);
369 break;
372 if (rv != SECSuccess)
373 break;
374 current->l.next = &(namesList->l);
375 current->l.prev = &(tail->l);
376 tail->l.next = &(current->l);
377 tail = current;
379 } while(nextChunk != data + strlen(data));
381 if (rv != SECSuccess) {
382 PORT_ArenaRelease (arena, mark);
383 namesList = NULL;
385 return (namesList);
388 /* Creates CERTGeneralName from parsed data for the Authority Key Extension */
389 static CERTGeneralName *
390 crlgen_DistinguishedName (PRArenaPool *arena, CRLGENGeneratorData *crlGenData,
391 const char *data)
393 CERTName *directoryName = NULL;
394 CERTGeneralName *current;
395 SECStatus rv = SECFailure;
396 void *mark;
398 if (!data)
399 return NULL;
400 PORT_Assert (arena);
401 if (!arena) {
402 PORT_SetError(SEC_ERROR_INVALID_ARGS);
403 return NULL;
406 mark = PORT_ArenaMark (arena);
408 current = PORT_ArenaZNew(arena, CERTGeneralName);
409 if (current == NULL) {
410 goto loser;
412 current->type = certDirectoryName;
413 current->l.next = &current->l;
414 current->l.prev = &current->l;
416 directoryName = CERT_AsciiToName ((char*)data);
417 if (!directoryName) {
418 goto loser;
421 rv = CERT_CopyName (arena, &current->name.directoryName, directoryName);
422 CERT_DestroyName (directoryName);
424 loser:
425 if (rv != SECSuccess) {
426 PORT_SetError (rv);
427 PORT_ArenaRelease (arena, mark);
428 current = NULL;
430 return (current);
434 /* Adding Authority Key ID extension to extension handle. */
435 static SECStatus
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) {
446 return SECFailure;
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");
455 return SECFailure;
458 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
459 if (!arena) {
460 return SECFailure;
463 authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID);
464 if (authKeyID == NULL) {
465 rv = SECFailure;
466 goto loser;
469 if (dataArr[3] == NULL) {
470 rv = crlgen_SetString (arena, dataArr[2], &authKeyID->keyID);
471 if (rv != SECSuccess)
472 goto loser;
473 } else {
474 rv = crlgen_SetString (arena, dataArr[3],
475 &authKeyID->authCertSerialNumber);
476 if (rv != SECSuccess)
477 goto loser;
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");
483 rv = SECFailure;
484 goto loser;
488 rv =
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);
493 loser:
494 if (arena)
495 PORT_FreeArena (arena, PR_FALSE);
496 return rv;
499 /* Creates and add Subject Alternative Names extension */
500 static SECStatus
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) {
512 return SECFailure;
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");
519 return SECFailure;
522 PORT_Assert(dataArr && crlGenData);
523 if (!crlGenData || !dataArr) {
524 return SECFailure;
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");
533 return SECFailure;
536 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
537 if (!arena) {
538 return SECFailure;
541 nameList = crlgen_GetGeneralName(arena, crlGenData, dataArr[2]);
542 if (nameList == NULL) {
543 crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
544 rv = SECFailure;
545 goto loser;
548 rv =
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);
553 loser:
554 if (arena)
555 PORT_FreeArena (arena, PR_FALSE);
556 return rv;
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 */
562 static SECStatus
563 crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
565 PRArenaPool *arena = NULL;
566 SECItem encodedItem;
567 void *extHandle = crlGenData->crlExtHandle;
568 void *dummy;
569 SECStatus rv = SECFailure;
570 int code = 0;
572 PORT_Assert(dataArr && crlGenData);
573 if (!crlGenData || !dataArr) {
574 goto loser;
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");
581 goto loser;
584 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
585 if (arena == NULL) {
586 goto loser;
589 code = atoi(dataArr[2]);
590 if (code == 0 && *dataArr[2] != '0') {
591 PORT_SetError(SEC_ERROR_INVALID_ARGS);
592 goto loser;
595 dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
596 if (!dummy) {
597 rv = SECFailure;
598 goto loser;
601 rv = CERT_AddExtension (extHandle, SEC_OID_X509_CRL_NUMBER, &encodedItem,
602 (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
603 PR_TRUE);
605 loser:
606 if (arena)
607 PORT_FreeArena(arena, PR_FALSE);
608 return rv;
613 /* Creates Cert Revocation Reason code extension. Encodes it and
614 * returns as SECItem structure */
615 static SECItem*
616 crlgen_CreateReasonCode(PRArenaPool *arena, const char **dataArr,
617 int *extCode)
619 SECItem *encodedItem;
620 void *dummy;
621 void *mark;
622 int code = 0;
624 PORT_Assert(arena && dataArr);
625 if (!arena || !dataArr) {
626 goto loser;
629 mark = PORT_ArenaMark(arena);
631 encodedItem = PORT_ArenaZNew (arena, SECItem);
632 if (encodedItem == NULL) {
633 goto loser;
636 if (dataArr[2] == NULL) {
637 PORT_SetError(SEC_ERROR_INVALID_ARGS);
638 goto loser;
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);
647 goto loser;
650 dummy = SEC_ASN1EncodeInteger(arena, encodedItem, code);
651 if (!dummy) {
652 goto loser;
655 *extCode = SEC_OID_X509_REASON_CODE;
656 return encodedItem;
658 loser:
659 PORT_ArenaRelease (arena, mark);
660 return NULL;
663 /* Creates Cert Invalidity Date extension. Encodes it and
664 * returns as SECItem structure */
665 static SECItem*
666 crlgen_CreateInvalidityDate(PRArenaPool *arena, const char **dataArr,
667 int *extCode)
669 SECItem *encodedItem;
670 int length = 0;
671 void *mark;
673 PORT_Assert(arena && dataArr);
674 if (!arena || !dataArr) {
675 goto loser;
678 mark = PORT_ArenaMark(arena);
680 encodedItem = PORT_ArenaZNew(arena, SECItem);
681 if (encodedItem == NULL) {
682 goto loser;
685 length = PORT_Strlen(dataArr[2]);
687 encodedItem->type = siGeneralizedTime;
688 encodedItem->data = PORT_ArenaAlloc(arena, length);
689 if (!encodedItem->data) {
690 goto loser;
693 PORT_Memcpy(encodedItem->data, dataArr[2], (encodedItem->len = length) *
694 sizeof(char));
696 *extCode = SEC_OID_X509_INVALID_DATE;
697 return encodedItem;
699 loser:
700 PORT_ArenaRelease(arena, mark);
701 return NULL;
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 */
707 static SECStatus
708 crlgen_AddEntryExtension(CRLGENGeneratorData *crlGenData,
709 const char **dataArr, char *extName,
710 SECItem* (*extCreator)(PRArenaPool *arena,
711 const char **dataArr,
712 int *extCode))
714 PRUint64 i = 0;
715 SECStatus rv = SECFailure;
716 int extCode = 0;
717 PRUint64 lastRange ;
718 SECItem *ext = NULL;
719 PRArenaPool *arena = NULL;
722 PORT_Assert(crlGenData && dataArr);
723 if (!crlGenData || !dataArr) {
724 goto loser;
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);
736 if (arena == NULL) {
737 goto loser;
740 ext = extCreator(arena, dataArr, &extCode);
741 if (ext == NULL) {
742 crlgen_PrintError(crlGenData->parsedLineNum,
743 "got error while creating extension: %s\n",
744 extName);
745 goto loser;
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);
754 if (!certIdItem) {
755 rv = SECFailure;
756 goto loser;
759 extData = crlgen_FindEntry(crlGenData, certIdItem);
760 if (!extData) {
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);
765 continue;
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,
776 PR_TRUE);
777 if (rv == SECFailure) {
778 goto loser;
782 loser:
783 if (arena)
784 PORT_FreeArena(arena, PR_FALSE);
785 return rv;
789 /* Commits all added entries and their's extensions into CRL. */
790 SECStatus
791 CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData *crlGenData)
793 int size = 0;
794 CERTCrl *crl;
795 PRArenaPool *arena;
796 SECStatus rv = SECSuccess;
797 void *mark;
799 PORT_Assert(crlGenData && crlGenData->signCrl && crlGenData->signCrl->arena);
800 if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
801 PORT_SetError(SEC_ERROR_INVALID_ARGS);
802 return SECFailure;
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;
814 crl->entries = NULL;
815 if (size) {
816 crl->entries = PORT_ArenaZNewArray(arena, CERTCrlEntry*, size + 1);
817 if (!crl->entries) {
818 rv = SECFailure;
819 } else {
820 struct commitData dt;
821 dt.entries = crl->entries;
822 dt.pos = 0;
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);
832 return rv;
835 /* Initializes extHandle with data from extensions array */
836 static SECStatus
837 crlgen_InitExtensionHandle(void *extHandle,
838 CERTCertExtension **extensions)
840 CERTCertExtension *extension = NULL;
842 if (!extensions)
843 return SECSuccess;
845 PORT_Assert(extHandle != NULL);
846 if (!extHandle) {
847 return SECFailure;
850 extension = *extensions;
851 while (extension) {
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,
856 PR_FALSE);
857 extension = *(++extensions);
859 return SECSuccess;
862 /* Used for initialization of extension handles for crl and certs
863 * extensions from existing CRL data then modifying existing CRL.*/
864 SECStatus
865 CRLGEN_ExtHandleInit(CRLGENGeneratorData *crlGenData)
867 CERTCrl *crl = NULL;
868 PRUint64 maxSN = 0;
870 PORT_Assert(crlGenData && crlGenData->signCrl &&
871 crlGenData->entryDataHashTable);
872 if (!crlGenData || !crlGenData->signCrl ||
873 !crlGenData->entryDataHashTable) {
874 PORT_SetError(SEC_ERROR_INVALID_ARGS);
875 return SECFailure;
878 crl = &crlGenData->signCrl->crl;
879 crlGenData->crlExtHandle = CERT_StartCRLExtensions(crl);
880 crlgen_InitExtensionHandle(crlGenData->crlExtHandle,
881 crl->extensions);
882 crl->extensions = NULL;
884 if (crl->entries) {
885 CERTCrlEntry **entry = crl->entries;
886 while (*entry) {
887 PRUint64 sn = DER_GetInteger(&(*entry)->serialNumber);
888 CRLGENEntryData *extData =
889 crlgen_PlaceAnEntry(crlGenData, *entry, &(*entry)->serialNumber);
890 if ((*entry)->extensions) {
891 extData->extHandle =
892 CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
893 (CERTCrlEntry*)extData->entry);
894 if (crlgen_InitExtensionHandle(extData->extHandle,
895 (*entry)->extensions) == SECFailure)
896 return SECFailure;
898 (*entry)->extensions = NULL;
899 entry++;
900 maxSN = PR_MAX(maxSN, sn);
904 crlGenData->rangeFrom = crlGenData->rangeTo = maxSN + 1;
905 return SECSuccess;
908 /*****************************************************************************
909 * Parser trigger functions start here
912 /* Sets new internal range value for add/rm certs.*/
913 static SECStatus
914 crlgen_SetNewRangeField(CRLGENGeneratorData *crlGenData, char *value)
916 long rangeFrom = 0, rangeTo = 0;
917 char *dashPos = NULL;
919 PORT_Assert(crlGenData);
920 if (!crlGenData) {
921 PORT_SetError(SEC_ERROR_INVALID_ARGS);
922 return SECFailure;
925 if (value == NULL) {
926 PORT_SetError(SEC_ERROR_INVALID_ARGS);
927 crlgen_PrintError(crlGenData->parsedLineNum,
928 "insufficient number of arguments.\n");
929 return SECFailure;
932 if ((dashPos = strchr(value, '-')) != NULL) {
933 char *rangeToS, *rangeFromS = value;
934 *dashPos = '\0';
935 rangeFrom = atoi(rangeFromS);
936 *dashPos = '-';
938 rangeToS = (char*)(dashPos + 1);
939 rangeTo = atol(rangeToS);
940 } else {
941 rangeFrom = atol(value);
942 rangeTo = rangeFrom;
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);
949 return SECFailure;
952 crlGenData->rangeFrom = rangeFrom;
953 crlGenData->rangeTo = rangeTo;
955 return SECSuccess;
958 /* Changes issuer subject field in CRL. By default this data is taken from
959 * issuer cert subject field.Not yet implemented */
960 static SECStatus
961 crlgen_SetIssuerField(CRLGENGeneratorData *crlGenData, char *value)
963 crlgen_PrintError(crlGenData->parsedLineNum,
964 "Can not change CRL issuer field.\n");
965 return SECFailure;
968 /* Encode and sets CRL thisUpdate and nextUpdate time fields*/
969 static SECStatus
970 crlgen_SetTimeField(CRLGENGeneratorData *crlGenData, char *value,
971 PRBool setThisUpdate)
973 CERTSignedCrl *signCrl;
974 PRArenaPool *arena;
975 CERTCrl *crl;
976 int length = 0;
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);
983 return SECFailure;
986 signCrl = crlGenData->signCrl;
987 arena = signCrl->arena;
988 crl = &signCrl->crl;
990 if (value == NULL) {
991 PORT_SetError(SEC_ERROR_INVALID_ARGS);
992 crlgen_PrintError(crlGenData->parsedLineNum,
993 "insufficient number of arguments.\n");
994 return SECFailure;
996 length = PORT_Strlen(value);
998 if (setThisUpdate == PR_TRUE) {
999 timeDest = &crl->lastUpdate;
1000 } else {
1001 timeDest = &crl->nextUpdate;
1004 timeDest->type = siGeneralizedTime;
1005 timeDest->data = PORT_ArenaAlloc(arena, length);
1006 if (!timeDest->data) {
1007 return SECFailure;
1009 PORT_Memcpy(timeDest->data, value, length);
1010 timeDest->len = length;
1012 return SECSuccess;
1016 /* Adds new extension into CRL or added cert handles */
1017 static SECStatus
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);
1023 return SECFailure;
1026 if (extData == NULL || *extData == NULL) {
1027 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1028 crlgen_PrintError(crlGenData->parsedLineNum,
1029 "insufficient number of arguments.\n");
1030 return SECFailure;
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);
1044 else {
1045 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1046 crlgen_PrintError(crlGenData->parsedLineNum,
1047 "insufficient number of arguments.\n");
1048 return SECFailure;
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 */
1057 static SECStatus
1058 crlgen_AddCert(CRLGENGeneratorData *crlGenData,
1059 char *certId, char *revocationDate)
1061 CERTSignedCrl *signCrl;
1062 SECItem *certIdItem;
1063 PRArenaPool *arena;
1064 PRUint64 rangeFrom = 0, rangeTo = 0, i = 0;
1065 int timeValLength = -1;
1066 SECStatus rv = SECFailure;
1067 void *mark;
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);
1074 return SECFailure;
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");
1084 return SECFailure;
1087 timeValLength = strlen(revocationDate);
1089 if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
1090 certId) {
1091 return 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) {
1101 goto loser;
1104 certIdItem = SEC_ASN1EncodeInteger(arena, &entry->serialNumber,
1105 rangeFrom + i);
1106 if (!certIdItem) {
1107 goto loser;
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);
1115 goto loser;
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) {
1125 goto loser;
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)) {
1135 goto loser;
1137 mark = NULL;
1140 rv = SECSuccess;
1141 loser:
1142 if (mark) {
1143 PORT_ArenaRelease(arena, mark);
1145 return rv;
1149 /* Removes certs from entryDataHashTable which have certId serial number.
1150 * certId can have value of a range of certs */
1151 static SECStatus
1152 crlgen_RmCert(CRLGENGeneratorData *crlGenData, char *certId)
1154 PRUint64 i = 0;
1155 PRArenaPool *arena;
1157 PORT_Assert(crlGenData && certId);
1158 if (!crlGenData || !certId) {
1159 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1160 return SECFailure;
1163 arena = crlGenData->signCrl->arena;
1165 if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
1166 certId) {
1167 return SECFailure;
1170 for (i = 0;i < crlGenData->rangeTo - crlGenData->rangeFrom + 1;i++) {
1171 SECItem* certIdItem = SEC_ASN1EncodeInteger(NULL, NULL,
1172 crlGenData->rangeFrom + i);
1173 if (certIdItem) {
1174 CRLGENEntryData *extData =
1175 crlgen_FindEntry(crlGenData, certIdItem);
1176 if (!extData) {
1177 printf("Cert with id %s is not in the list\n", certId);
1178 } else {
1179 crlgen_RmEntry(crlGenData, certIdItem);
1181 SECITEM_FreeItem(certIdItem, PR_TRUE);
1185 return SECSuccess;
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 */
1196 static SECStatus
1197 crlgen_updateCrlFn_field(CRLGENGeneratorData *crlGenData, void *str)
1199 CRLGENCrlField *fieldStr = (CRLGENCrlField*)str;
1201 PORT_Assert(crlGenData);
1202 if (!crlGenData) {
1203 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1204 return SECFailure;
1207 switch(crlGenData->contextId) {
1208 case CRLGEN_ISSUER_CONTEXT:
1209 crlgen_SetIssuerField(crlGenData, fieldStr->value);
1210 break;
1211 case CRLGEN_UPDATE_CONTEXT:
1212 return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_TRUE);
1213 break;
1214 case CRLGEN_NEXT_UPDATE_CONTEXT:
1215 return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_FALSE);
1216 break;
1217 case CRLGEN_CHANGE_RANGE_CONTEXT:
1218 return crlgen_SetNewRangeField(crlGenData, fieldStr->value);
1219 break;
1220 default:
1221 crlgen_PrintError(crlGenData->parsedLineNum,
1222 "syntax error (unknow token type: %d)\n",
1223 crlGenData->contextId);
1224 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1225 return SECFailure;
1227 return SECSuccess;
1230 /* Sets parsed data for CRL field update into temporary structure */
1231 static SECStatus
1232 crlgen_setNextDataFn_field(CRLGENGeneratorData *crlGenData, void *str,
1233 void *data, unsigned short dtype)
1235 CRLGENCrlField *fieldStr = (CRLGENCrlField*)str;
1237 PORT_Assert(crlGenData);
1238 if (!crlGenData) {
1239 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1240 return SECFailure;
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");
1249 return SECFailure;
1251 break;
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");
1258 return SECFailure;
1260 break;
1261 default:
1262 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1263 crlgen_PrintError(crlGenData->parsedLineNum,
1264 "syntax error (unknow token type: %d).\n",
1265 crlGenData->contextId, data);
1266 return SECFailure;
1268 fieldStr->value = PORT_Strdup(data);
1269 if (!fieldStr->value) {
1270 return SECFailure;
1272 return SECSuccess;
1275 /* Triggers cert entries update depending on current context */
1276 static SECStatus
1277 crlgen_updateCrlFn_cert(CRLGENGeneratorData *crlGenData, void *str)
1279 CRLGENCertEntry *certStr = (CRLGENCertEntry*)str;
1281 PORT_Assert(crlGenData);
1282 if (!crlGenData) {
1283 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1284 return SECFailure;
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);
1293 default:
1294 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1295 crlgen_PrintError(crlGenData->parsedLineNum,
1296 "syntax error (unknow token type: %d).\n",
1297 crlGenData->contextId);
1298 return SECFailure;
1303 /* Sets parsed data for CRL entries update into temporary structure */
1304 static SECStatus
1305 crlgen_setNextDataFn_cert(CRLGENGeneratorData *crlGenData, void *str,
1306 void *data, unsigned short dtype)
1308 CRLGENCertEntry *certStr = (CRLGENCertEntry*)str;
1310 PORT_Assert(crlGenData);
1311 if (!crlGenData) {
1312 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1313 return SECFailure;
1316 switch(dtype) {
1317 case CRLGEN_TYPE_DIGIT:
1318 case CRLGEN_TYPE_DIGIT_RANGE:
1319 certStr->certId = PORT_Strdup(data);
1320 if (!certStr->certId) {
1321 return SECFailure;
1323 break;
1324 case CRLGEN_TYPE_DATE:
1325 case CRLGEN_TYPE_ZDATE:
1326 certStr->revocationTime = PORT_Strdup(data);
1327 if (!certStr->revocationTime) {
1328 return SECFailure;
1330 break;
1331 default:
1332 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1333 crlgen_PrintError(crlGenData->parsedLineNum,
1334 "syntax error (unknow token type: %d).\n",
1335 crlGenData->contextId);
1336 return SECFailure;
1338 return SECSuccess;
1341 /* Triggers cert entries/crl extension update */
1342 static SECStatus
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 */
1355 static SECStatus
1356 crlgen_setNextDataFn_extension(CRLGENGeneratorData *crlGenData, void *str,
1357 void *data, unsigned short dtype)
1359 CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry*)str;
1361 PORT_Assert(crlGenData);
1362 if (!crlGenData) {
1363 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1364 return SECFailure;
1367 if (extStr->extData == NULL) {
1368 extStr->extData = PORT_ZNewArray(char *, MAX_EXT_DATA_LENGTH);
1369 if (!extStr->extData) {
1370 return SECFailure;
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);
1379 return SECFailure;
1381 extStr->extData[extStr->nextUpdatedData] = PORT_Strdup(data);
1382 if (!extStr->extData[extStr->nextUpdatedData]) {
1383 return SECFailure;
1385 extStr->nextUpdatedData += 1;
1387 return SECSuccess;
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.
1399 void
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);
1411 break;
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);
1419 break;
1420 case CRLGEN_ADD_EXTENSION_CONTEXT:
1421 if (crlGenData->extensionEntry->extData) {
1422 int i = 0;
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);
1428 break;
1430 crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
1434 SECStatus
1435 crlgen_updateCrl(CRLGENGeneratorData *crlGenData)
1437 SECStatus rv = SECSuccess;
1439 PORT_Assert(crlGenData);
1440 if (!crlGenData) {
1441 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1442 return SECFailure;
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);
1451 break;
1452 case CRLGEN_RM_CERT_CONTEXT:
1453 case CRLGEN_ADD_CERT_CONTEXT:
1454 rv = crlGenData->certEntry->updateCrlFn(crlGenData, crlGenData->certEntry);
1455 break;
1456 case CRLGEN_ADD_EXTENSION_CONTEXT:
1457 rv = crlGenData->extensionEntry->
1458 updateCrlFn(crlGenData, crlGenData->extensionEntry);
1459 break;
1460 case CRLGEN_UNKNOWN_CONTEXT:
1461 break;
1462 default:
1463 crlgen_PrintError(crlGenData->parsedLineNum,
1464 "unknown lang context type code: %d.\n",
1465 crlGenData->contextId);
1466 PORT_Assert(0);
1467 return SECFailure;
1469 /* Clrean structures after crl update */
1470 crlgen_destroyTempData(crlGenData);
1472 crlGenData->parsedLineNum += 1;
1474 return rv;
1477 SECStatus
1478 crlgen_setNextData(CRLGENGeneratorData *crlGenData, void *data,
1479 unsigned short dtype)
1481 SECStatus rv = SECSuccess;
1483 PORT_Assert(crlGenData);
1484 if (!crlGenData) {
1485 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1486 return SECFailure;
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,
1495 data, dtype);
1496 break;
1497 case CRLGEN_ADD_CERT_CONTEXT:
1498 case CRLGEN_RM_CERT_CONTEXT:
1499 rv = crlGenData->certEntry->setNextDataFn(crlGenData, crlGenData->certEntry,
1500 data, dtype);
1501 break;
1502 case CRLGEN_ADD_EXTENSION_CONTEXT:
1503 rv =
1504 crlGenData->extensionEntry->
1505 setNextDataFn(crlGenData, crlGenData->extensionEntry, data, dtype);
1506 break;
1507 case CRLGEN_UNKNOWN_CONTEXT:
1508 break;
1509 default:
1510 crlgen_PrintError(crlGenData->parsedLineNum,
1511 "unknown context type: %d.\n",
1512 crlGenData->contextId);
1513 PORT_Assert(0);
1514 return SECFailure;
1516 return rv;
1519 SECStatus
1520 crlgen_createNewLangStruct(CRLGENGeneratorData *crlGenData,
1521 unsigned structType)
1523 PORT_Assert(crlGenData &&
1524 crlGenData->contextId == CRLGEN_UNKNOWN_CONTEXT);
1525 if (!crlGenData ||
1526 crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
1527 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1528 return SECFailure;
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) {
1538 return SECFailure;
1540 crlGenData->contextId = structType;
1541 crlGenData->crlField->value = NULL;
1542 crlGenData->crlField->updateCrlFn = &crlgen_updateCrlFn_field;
1543 crlGenData->crlField->setNextDataFn = &crlgen_setNextDataFn_field;
1544 break;
1545 case CRLGEN_RM_CERT_CONTEXT:
1546 case CRLGEN_ADD_CERT_CONTEXT:
1547 crlGenData->certEntry = PORT_New(CRLGENCertEntry);
1548 if (!crlGenData->certEntry) {
1549 return SECFailure;
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;
1556 break;
1557 case CRLGEN_ADD_EXTENSION_CONTEXT:
1558 crlGenData->extensionEntry = PORT_New(CRLGENExtensionEntry);
1559 if (!crlGenData->extensionEntry) {
1560 return SECFailure;
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;
1569 break;
1570 case CRLGEN_UNKNOWN_CONTEXT:
1571 break;
1572 default:
1573 crlgen_PrintError(crlGenData->parsedLineNum,
1574 "unknown context type: %d.\n", structType);
1575 PORT_Assert(0);
1576 return SECFailure;
1578 return SECSuccess;
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);
1591 return NULL;
1594 crlGenData = PORT_ZNew(CRLGENGeneratorData);
1595 if (!crlGenData) {
1596 return NULL;
1599 crlGenData->entryDataHashTable =
1600 PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
1601 PL_CompareValues, NULL, NULL);
1602 if (!crlGenData->entryDataHashTable) {
1603 PORT_Free(crlGenData);
1604 return NULL;
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;
1615 PORT_SetError(0);
1617 return crlGenData;
1620 void
1621 CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData *crlGenData)
1623 if (!crlGenData)
1624 return;
1625 if (crlGenData->src)
1626 PR_Close(crlGenData->src);
1627 PL_HashTableDestroy(crlGenData->entryDataHashTable);
1628 PORT_Free(crlGenData);