1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /*
6 ** crlgen.c
7 **
8 ** utility for managing certificates revocation lists generation
9 **
10 */
11 
12 #include <stdio.h>
13 #include <math.h>
14 
15 #include "nspr.h"
16 #include "plgetopt.h"
17 #include "nss.h"
18 #include "secutil.h"
19 #include "cert.h"
20 #include "certi.h"
21 #include "certdb.h"
22 #include "pk11func.h"
23 #include "crlgen.h"
24 
25 /* Destroys extHandle and data. data was create on heap.
26  * extHandle creaded by CERT_StartCRLEntryExtensions. entry
27  * was allocated on arena.*/
28 static void
destroyEntryData(CRLGENEntryData * data)29 destroyEntryData(CRLGENEntryData *data)
30 {
31     if (!data)
32         return;
33     PORT_Assert(data->entry);
34     if (data->extHandle)
35         CERT_FinishExtensions(data->extHandle);
36     PORT_Free(data);
37 }
38 
39 /* Prints error messages along with line number */
40 void
crlgen_PrintError(int line,char * msg,...)41 crlgen_PrintError(int line, char *msg, ...)
42 {
43     va_list args;
44 
45     va_start(args, msg);
46 
47     fprintf(stderr, "crlgen: (line: %d) ", line);
48     vfprintf(stderr, msg, args);
49 
50     va_end(args);
51 }
52 /* Finds CRLGENEntryData in hashtable according PRUint64 value
53  * - certId : cert serial number*/
54 static CRLGENEntryData *
crlgen_FindEntry(CRLGENGeneratorData * crlGenData,SECItem * certId)55 crlgen_FindEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
56 {
57     if (!crlGenData->entryDataHashTable || !certId)
58         return NULL;
59     return (CRLGENEntryData *)
60         PL_HashTableLookup(crlGenData->entryDataHashTable,
61                            certId);
62 }
63 
64 /* Removes CRLGENEntryData from hashtable according to certId
65  * - certId : cert serial number*/
66 static SECStatus
crlgen_RmEntry(CRLGENGeneratorData * crlGenData,SECItem * certId)67 crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
68 {
69     CRLGENEntryData *data = NULL;
70     SECStatus rv = SECSuccess;
71 
72     if (!crlGenData->entryDataHashTable) {
73         return SECSuccess;
74     }
75 
76     data = crlgen_FindEntry(crlGenData, certId);
77     if (!data) {
78         return SECSuccess;
79     }
80 
81     if (!PL_HashTableRemove(crlGenData->entryDataHashTable, certId)) {
82         rv = SECFailure;
83     }
84 
85     destroyEntryData(data);
86     return rv;
87 }
88 
89 /* Stores CRLGENEntryData in hashtable according to certId
90  * - certId : cert serial number*/
91 static CRLGENEntryData *
crlgen_PlaceAnEntry(CRLGENGeneratorData * crlGenData,CERTCrlEntry * entry,SECItem * certId)92 crlgen_PlaceAnEntry(CRLGENGeneratorData *crlGenData,
93                     CERTCrlEntry *entry, SECItem *certId)
94 {
95     CRLGENEntryData *newData = NULL;
96 
97     PORT_Assert(crlGenData && crlGenData->entryDataHashTable &&
98                 entry);
99     if (!crlGenData || !crlGenData->entryDataHashTable || !entry) {
100         PORT_SetError(SEC_ERROR_INVALID_ARGS);
101         return NULL;
102     }
103 
104     newData = PORT_ZNew(CRLGENEntryData);
105     if (!newData) {
106         return NULL;
107     }
108     newData->entry = entry;
109     newData->certId = certId;
110     if (!PL_HashTableAdd(crlGenData->entryDataHashTable,
111                          newData->certId, newData)) {
112         crlgen_PrintError(crlGenData->parsedLineNum,
113                           "Can not add entryData structure\n");
114         return NULL;
115     }
116     return newData;
117 }
118 
119 /* Use this structure to keep pointer when commiting entries extensions */
120 struct commitData {
121     int pos;
122     CERTCrlEntry **entries;
123 };
124 
125 /* HT PL_HashTableEnumerateEntries callback. Sorts hashtable entries of the
126  * table he. Returns value through arg parameter*/
127 static PRIntn PR_CALLBACK
crlgen_CommitEntryData(PLHashEntry * he,PRIntn i,void * arg)128 crlgen_CommitEntryData(PLHashEntry *he, PRIntn i, void *arg)
129 {
130     CRLGENEntryData *data = NULL;
131 
132     PORT_Assert(he);
133     if (!he) {
134         return HT_ENUMERATE_NEXT;
135     }
136     data = (CRLGENEntryData *)he->value;
137 
138     PORT_Assert(data);
139     PORT_Assert(arg);
140 
141     if (data) {
142         struct commitData *dt = (struct commitData *)arg;
143         dt->entries[dt->pos++] = data->entry;
144         destroyEntryData(data);
145     }
146     return HT_ENUMERATE_NEXT;
147 }
148 
149 /* Copy char * datainto allocated in arena SECItem */
150 static SECStatus
crlgen_SetString(PLArenaPool * arena,const char * dataIn,SECItem * value)151 crlgen_SetString(PLArenaPool *arena, const char *dataIn, SECItem *value)
152 {
153     SECItem item;
154 
155     PORT_Assert(arena && dataIn);
156     if (!arena || !dataIn) {
157         PORT_SetError(SEC_ERROR_INVALID_ARGS);
158         return SECFailure;
159     }
160 
161     item.data = (void *)dataIn;
162     item.len = PORT_Strlen(dataIn);
163 
164     return SECITEM_CopyItem(arena, value, &item);
165 }
166 
167 /* Creates CERTGeneralName from parsed data for the Authority Key Extension */
168 static CERTGeneralName *
crlgen_GetGeneralName(PLArenaPool * arena,CRLGENGeneratorData * crlGenData,const char * data)169 crlgen_GetGeneralName(PLArenaPool *arena, CRLGENGeneratorData *crlGenData,
170                       const char *data)
171 {
172     CERTGeneralName *namesList = NULL;
173     CERTGeneralName *current;
174     CERTGeneralName *tail = NULL;
175     SECStatus rv = SECSuccess;
176     const char *nextChunk = NULL;
177     const char *currData = NULL;
178     int intValue;
179     char buffer[512];
180     void *mark;
181 
182     if (!data)
183         return NULL;
184     PORT_Assert(arena);
185     if (!arena) {
186         PORT_SetError(SEC_ERROR_INVALID_ARGS);
187         return NULL;
188     }
189 
190     mark = PORT_ArenaMark(arena);
191 
192     nextChunk = data;
193     currData = data;
194     do {
195         int nameLen = 0;
196         char name[128];
197         const char *sepPrt = NULL;
198         nextChunk = PORT_Strchr(currData, '|');
199         if (!nextChunk)
200             nextChunk = data + strlen(data);
201         sepPrt = PORT_Strchr(currData, ':');
202         if (sepPrt == NULL || sepPrt >= nextChunk) {
203             *buffer = '\0';
204             sepPrt = nextChunk;
205         } else {
206             PORT_Memcpy(buffer, sepPrt + 1,
207                         (nextChunk - sepPrt - 1));
208             buffer[nextChunk - sepPrt - 1] = '\0';
209         }
210         nameLen = PR_MIN(sepPrt - currData, sizeof(name) - 1);
211         PORT_Memcpy(name, currData, nameLen);
212         name[nameLen] = '\0';
213         currData = nextChunk + 1;
214 
215         if (!PORT_Strcmp(name, "otherName"))
216             intValue = certOtherName;
217         else if (!PORT_Strcmp(name, "rfc822Name"))
218             intValue = certRFC822Name;
219         else if (!PORT_Strcmp(name, "dnsName"))
220             intValue = certDNSName;
221         else if (!PORT_Strcmp(name, "x400Address"))
222             intValue = certX400Address;
223         else if (!PORT_Strcmp(name, "directoryName"))
224             intValue = certDirectoryName;
225         else if (!PORT_Strcmp(name, "ediPartyName"))
226             intValue = certEDIPartyName;
227         else if (!PORT_Strcmp(name, "URI"))
228             intValue = certURI;
229         else if (!PORT_Strcmp(name, "ipAddress"))
230             intValue = certIPAddress;
231         else if (!PORT_Strcmp(name, "registerID"))
232             intValue = certRegisterID;
233         else
234             intValue = -1;
235 
236         if (intValue >= certOtherName && intValue <= certRegisterID) {
237             if (namesList == NULL) {
238                 namesList = current = tail = PORT_ArenaZNew(arena,
239                                                             CERTGeneralName);
240             } else {
241                 current = PORT_ArenaZNew(arena, CERTGeneralName);
242             }
243             if (current == NULL) {
244                 rv = SECFailure;
245                 break;
246             }
247         } else {
248             PORT_SetError(SEC_ERROR_INVALID_ARGS);
249             break;
250         }
251         current->type = intValue;
252         switch (current->type) {
253             case certURI:
254             case certDNSName:
255             case certRFC822Name:
256                 current->name.other.data = PORT_ArenaAlloc(arena, strlen(buffer));
257                 if (current->name.other.data == NULL) {
258                     rv = SECFailure;
259                     break;
260                 }
261                 PORT_Memcpy(current->name.other.data, buffer,
262                             current->name.other.len = strlen(buffer));
263                 break;
264 
265             case certEDIPartyName:
266             case certIPAddress:
267             case certOtherName:
268             case certRegisterID:
269             case certX400Address: {
270 
271                 current->name.other.data = PORT_ArenaAlloc(arena, strlen(buffer) + 2);
272                 if (current->name.other.data == NULL) {
273                     rv = SECFailure;
274                     break;
275                 }
276 
277                 PORT_Memcpy(current->name.other.data + 2, buffer, strlen(buffer));
278                 /* This may not be accurate for all cases.For now, use this tag type */
279                 current->name.other.data[0] = (char)(((current->type - 1) & 0x1f) | 0x80);
280                 current->name.other.data[1] = (char)strlen(buffer);
281                 current->name.other.len = strlen(buffer) + 2;
282                 break;
283             }
284 
285             case certDirectoryName: {
286                 CERTName *directoryName = NULL;
287 
288                 directoryName = CERT_AsciiToName(buffer);
289                 if (!directoryName) {
290                     rv = SECFailure;
291                     break;
292                 }
293 
294                 rv = CERT_CopyName(arena, &current->name.directoryName, directoryName);
295                 CERT_DestroyName(directoryName);
296 
297                 break;
298             }
299         }
300         if (rv != SECSuccess)
301             break;
302         current->l.next = &(namesList->l);
303         current->l.prev = &(tail->l);
304         tail->l.next = &(current->l);
305         tail = current;
306 
307     } while (nextChunk != data + strlen(data));
308 
309     if (rv != SECSuccess) {
310         PORT_ArenaRelease(arena, mark);
311         namesList = NULL;
312     }
313     return (namesList);
314 }
315 
316 /* Creates CERTGeneralName from parsed data for the Authority Key Extension */
317 static CERTGeneralName *
crlgen_DistinguishedName(PLArenaPool * arena,CRLGENGeneratorData * crlGenData,const char * data)318 crlgen_DistinguishedName(PLArenaPool *arena, CRLGENGeneratorData *crlGenData,
319                          const char *data)
320 {
321     CERTName *directoryName = NULL;
322     CERTGeneralName *current;
323     SECStatus rv = SECFailure;
324     void *mark;
325 
326     if (!data)
327         return NULL;
328     PORT_Assert(arena);
329     if (!arena) {
330         PORT_SetError(SEC_ERROR_INVALID_ARGS);
331         return NULL;
332     }
333 
334     mark = PORT_ArenaMark(arena);
335 
336     current = PORT_ArenaZNew(arena, CERTGeneralName);
337     if (current == NULL) {
338         goto loser;
339     }
340     current->type = certDirectoryName;
341     current->l.next = &current->l;
342     current->l.prev = &current->l;
343 
344     directoryName = CERT_AsciiToName((char *)data);
345     if (!directoryName) {
346         goto loser;
347     }
348 
349     rv = CERT_CopyName(arena, &current->name.directoryName, directoryName);
350     CERT_DestroyName(directoryName);
351 
352 loser:
353     if (rv != SECSuccess) {
354         PORT_SetError(rv);
355         PORT_ArenaRelease(arena, mark);
356         current = NULL;
357     }
358     return (current);
359 }
360 
361 /* Adding Authority Key ID extension to extension handle. */
362 static SECStatus
crlgen_AddAuthKeyID(CRLGENGeneratorData * crlGenData,const char ** dataArr)363 crlgen_AddAuthKeyID(CRLGENGeneratorData *crlGenData,
364                     const char **dataArr)
365 {
366     void *extHandle = NULL;
367     CERTAuthKeyID *authKeyID = NULL;
368     PLArenaPool *arena = NULL;
369     SECStatus rv = SECSuccess;
370 
371     PORT_Assert(dataArr && crlGenData);
372     if (!crlGenData || !dataArr) {
373         return SECFailure;
374     }
375 
376     extHandle = crlGenData->crlExtHandle;
377 
378     if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
379         PORT_SetError(SEC_ERROR_INVALID_ARGS);
380         crlgen_PrintError(crlGenData->parsedLineNum,
381                           "insufficient number of parameters.\n");
382         return SECFailure;
383     }
384 
385     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
386     if (!arena) {
387         return SECFailure;
388     }
389 
390     authKeyID = PORT_ArenaZNew(arena, CERTAuthKeyID);
391     if (authKeyID == NULL) {
392         rv = SECFailure;
393         goto loser;
394     }
395 
396     if (dataArr[3] == NULL) {
397         rv = crlgen_SetString(arena, dataArr[2], &authKeyID->keyID);
398         if (rv != SECSuccess)
399             goto loser;
400     } else {
401         rv = crlgen_SetString(arena, dataArr[3],
402                               &authKeyID->authCertSerialNumber);
403         if (rv != SECSuccess)
404             goto loser;
405 
406         authKeyID->authCertIssuer =
407             crlgen_DistinguishedName(arena, crlGenData, dataArr[2]);
408         if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError()) {
409             crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
410             rv = SECFailure;
411             goto loser;
412         }
413     }
414 
415     rv =
416         SECU_EncodeAndAddExtensionValue(arena, extHandle, authKeyID,
417                                         (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
418                                         SEC_OID_X509_AUTH_KEY_ID,
419                                         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeAuthKeyID);
420 loser:
421     if (arena)
422         PORT_FreeArena(arena, PR_FALSE);
423     return rv;
424 }
425 
426 /* Creates and add Subject Alternative Names extension */
427 static SECStatus
crlgen_AddIssuerAltNames(CRLGENGeneratorData * crlGenData,const char ** dataArr)428 crlgen_AddIssuerAltNames(CRLGENGeneratorData *crlGenData,
429                          const char **dataArr)
430 {
431     CERTGeneralName *nameList = NULL;
432     PLArenaPool *arena = NULL;
433     void *extHandle = NULL;
434     SECStatus rv = SECSuccess;
435 
436     PORT_Assert(dataArr && crlGenData);
437     if (!crlGenData || !dataArr) {
438         return SECFailure;
439     }
440 
441     if (!dataArr || !dataArr[0] || !dataArr[1] || !dataArr[2]) {
442         PORT_SetError(SEC_ERROR_INVALID_ARGS);
443         crlgen_PrintError(crlGenData->parsedLineNum,
444                           "insufficient number of arguments.\n");
445         return SECFailure;
446     }
447 
448     PORT_Assert(dataArr && crlGenData);
449     if (!crlGenData || !dataArr) {
450         return SECFailure;
451     }
452 
453     extHandle = crlGenData->crlExtHandle;
454 
455     if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
456         PORT_SetError(SEC_ERROR_INVALID_ARGS);
457         crlgen_PrintError(crlGenData->parsedLineNum,
458                           "insufficient number of parameters.\n");
459         return SECFailure;
460     }
461 
462     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
463     if (!arena) {
464         return SECFailure;
465     }
466 
467     nameList = crlgen_GetGeneralName(arena, crlGenData, dataArr[2]);
468     if (nameList == NULL) {
469         crlgen_PrintError(crlGenData->parsedLineNum, "syntax error.\n");
470         rv = SECFailure;
471         goto loser;
472     }
473 
474     rv =
475         SECU_EncodeAndAddExtensionValue(arena, extHandle, nameList,
476                                         (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
477                                         SEC_OID_X509_ISSUER_ALT_NAME,
478                                         (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeAltNameExtension);
479 loser:
480     if (arena)
481         PORT_FreeArena(arena, PR_FALSE);
482     return rv;
483 }
484 
485 /* Creates and adds CRLNumber extension to extension handle.
486  * Since, this is CRL extension, extension handle is the one
487  * related to CRL extensions */
488 static SECStatus
crlgen_AddCrlNumber(CRLGENGeneratorData * crlGenData,const char ** dataArr)489 crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
490 {
491     PLArenaPool *arena = NULL;
492     SECItem encodedItem;
493     void *dummy;
494     SECStatus rv = SECFailure;
495     int code = 0;
496 
497     PORT_Assert(dataArr && crlGenData);
498     if (!crlGenData || !dataArr) {
499         goto loser;
500     }
501 
502     if (!dataArr[0] || !dataArr[1] || !dataArr[2]) {
503         PORT_SetError(SEC_ERROR_INVALID_ARGS);
504         crlgen_PrintError(crlGenData->parsedLineNum,
505                           "insufficient number of arguments.\n");
506         goto loser;
507     }
508 
509     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
510     if (arena == NULL) {
511         goto loser;
512     }
513 
514     code = atoi(dataArr[2]);
515     if (code == 0 && *dataArr[2] != '0') {
516         PORT_SetError(SEC_ERROR_INVALID_ARGS);
517         goto loser;
518     }
519 
520     dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
521     if (!dummy) {
522         rv = SECFailure;
523         goto loser;
524     }
525 
526     rv = CERT_AddExtension(crlGenData->crlExtHandle, SEC_OID_X509_CRL_NUMBER,
527                            &encodedItem,
528                            (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
529                            PR_TRUE);
530 
531 loser:
532     if (arena)
533         PORT_FreeArena(arena, PR_FALSE);
534     return rv;
535 }
536 
537 /* Creates Cert Revocation Reason code extension. Encodes it and
538  * returns as SECItem structure */
539 static SECItem *
crlgen_CreateReasonCode(PLArenaPool * arena,const char ** dataArr,int * extCode)540 crlgen_CreateReasonCode(PLArenaPool *arena, const char **dataArr,
541                         int *extCode)
542 {
543     SECItem *encodedItem;
544     void *dummy;
545     void *mark = NULL;
546     int code = 0;
547 
548     PORT_Assert(arena && dataArr);
549     if (!arena || !dataArr) {
550         goto loser;
551     }
552 
553     mark = PORT_ArenaMark(arena);
554 
555     encodedItem = PORT_ArenaZNew(arena, SECItem);
556     if (encodedItem == NULL) {
557         goto loser;
558     }
559 
560     if (dataArr[2] == NULL) {
561         PORT_SetError(SEC_ERROR_INVALID_ARGS);
562         goto loser;
563     }
564 
565     code = atoi(dataArr[2]);
566     /* aACompromise(10) is the last possible of the values
567      * for the Reason Core Extension */
568     if ((code == 0 && *dataArr[2] != '0') || code > 10) {
569 
570         PORT_SetError(SEC_ERROR_INVALID_ARGS);
571         goto loser;
572     }
573 
574     dummy = SEC_ASN1EncodeInteger(arena, encodedItem, code);
575     if (!dummy) {
576         goto loser;
577     }
578 
579     *extCode = SEC_OID_X509_REASON_CODE;
580     return encodedItem;
581 
582 loser:
583     if (mark) {
584         PORT_ArenaRelease(arena, mark);
585     }
586     return NULL;
587 }
588 
589 /* Creates Cert Invalidity Date extension. Encodes it and
590  * returns as SECItem structure */
591 static SECItem *
crlgen_CreateInvalidityDate(PLArenaPool * arena,const char ** dataArr,int * extCode)592 crlgen_CreateInvalidityDate(PLArenaPool *arena, const char **dataArr,
593                             int *extCode)
594 {
595     SECItem *encodedItem;
596     int length = 0;
597     void *mark = NULL;
598 
599     PORT_Assert(arena && dataArr);
600     if (!arena || !dataArr) {
601         goto loser;
602     }
603 
604     mark = PORT_ArenaMark(arena);
605 
606     encodedItem = PORT_ArenaZNew(arena, SECItem);
607     if (encodedItem == NULL) {
608         goto loser;
609     }
610 
611     length = PORT_Strlen(dataArr[2]);
612 
613     encodedItem->type = siGeneralizedTime;
614     encodedItem->data = PORT_ArenaAlloc(arena, length);
615     if (!encodedItem->data) {
616         goto loser;
617     }
618 
619     PORT_Memcpy(encodedItem->data, dataArr[2], (encodedItem->len = length) * sizeof(char));
620 
621     *extCode = SEC_OID_X509_INVALID_DATE;
622     return encodedItem;
623 
624 loser:
625     if (mark) {
626         PORT_ArenaRelease(arena, mark);
627     }
628     return NULL;
629 }
630 
631 /* Creates(by calling extCreator function) and adds extension to a set
632  * of already added certs. Uses values of rangeFrom and rangeTo from
633  * CRLGENCrlGenCtl structure for identifying the inclusive set of certs */
634 static SECStatus
crlgen_AddEntryExtension(CRLGENGeneratorData * crlGenData,const char ** dataArr,char * extName,SECItem * (* extCreator)(PLArenaPool * arena,const char ** dataArr,int * extCode))635 crlgen_AddEntryExtension(CRLGENGeneratorData *crlGenData,
636                          const char **dataArr, char *extName,
637                          SECItem *(*extCreator)(PLArenaPool *arena,
638                                                 const char **dataArr,
639                                                 int *extCode))
640 {
641     PRUint64 i = 0;
642     SECStatus rv = SECFailure;
643     int extCode = 0;
644     PRUint64 lastRange;
645     SECItem *ext = NULL;
646     PLArenaPool *arena = NULL;
647 
648     PORT_Assert(crlGenData && dataArr);
649     if (!crlGenData || !dataArr) {
650         goto loser;
651     }
652 
653     if (!dataArr[0] || !dataArr[1]) {
654         PORT_SetError(SEC_ERROR_INVALID_ARGS);
655         crlgen_PrintError(crlGenData->parsedLineNum,
656                           "insufficient number of arguments.\n");
657     }
658 
659     lastRange = crlGenData->rangeTo - crlGenData->rangeFrom + 1;
660 
661     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
662     if (arena == NULL) {
663         goto loser;
664     }
665 
666     ext = extCreator(arena, dataArr, &extCode);
667     if (ext == NULL) {
668         crlgen_PrintError(crlGenData->parsedLineNum,
669                           "got error while creating extension: %s\n",
670                           extName);
671         goto loser;
672     }
673 
674     for (i = 0; i < lastRange; i++) {
675         CRLGENEntryData *extData = NULL;
676         void *extHandle = NULL;
677         SECItem *certIdItem =
678             SEC_ASN1EncodeInteger(arena, NULL,
679                                   crlGenData->rangeFrom + i);
680         if (!certIdItem) {
681             rv = SECFailure;
682             goto loser;
683         }
684 
685         extData = crlgen_FindEntry(crlGenData, certIdItem);
686         if (!extData) {
687             crlgen_PrintError(crlGenData->parsedLineNum,
688                               "can not add extension: crl entry "
689                               "(serial number: %d) is not in the list yet.\n",
690                               crlGenData->rangeFrom + i);
691             continue;
692         }
693 
694         extHandle = extData->extHandle;
695         if (extHandle == NULL) {
696             extHandle = extData->extHandle =
697                 CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
698                                              (CERTCrlEntry *)extData->entry);
699         }
700         rv = CERT_AddExtension(extHandle, extCode, ext,
701                                (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
702                                PR_TRUE);
703         if (rv == SECFailure) {
704             goto loser;
705         }
706     }
707 
708 loser:
709     if (arena)
710         PORT_FreeArena(arena, PR_FALSE);
711     return rv;
712 }
713 
714 /* Commits all added entries and their's extensions into CRL. */
715 SECStatus
CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData * crlGenData)716 CRLGEN_CommitExtensionsAndEntries(CRLGENGeneratorData *crlGenData)
717 {
718     int size = 0;
719     CERTCrl *crl;
720     PLArenaPool *arena;
721     SECStatus rv = SECSuccess;
722     void *mark;
723 
724     PORT_Assert(crlGenData && crlGenData->signCrl && crlGenData->signCrl->arena);
725     if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
726         PORT_SetError(SEC_ERROR_INVALID_ARGS);
727         return SECFailure;
728     }
729 
730     arena = crlGenData->signCrl->arena;
731     crl = &crlGenData->signCrl->crl;
732 
733     mark = PORT_ArenaMark(arena);
734 
735     if (crlGenData->crlExtHandle)
736         CERT_FinishExtensions(crlGenData->crlExtHandle);
737 
738     size = crlGenData->entryDataHashTable->nentries;
739     crl->entries = NULL;
740     if (size) {
741         crl->entries = PORT_ArenaZNewArray(arena, CERTCrlEntry *, size + 1);
742         if (!crl->entries) {
743             rv = SECFailure;
744         } else {
745             struct commitData dt;
746             dt.entries = crl->entries;
747             dt.pos = 0;
748             PL_HashTableEnumerateEntries(crlGenData->entryDataHashTable,
749                                          &crlgen_CommitEntryData, &dt);
750             /* Last should be NULL */
751             crl->entries[size] = NULL;
752         }
753     }
754 
755     if (rv != SECSuccess)
756         PORT_ArenaRelease(arena, mark);
757     return rv;
758 }
759 
760 /* Initializes extHandle with data from extensions array */
761 static SECStatus
crlgen_InitExtensionHandle(void * extHandle,CERTCertExtension ** extensions)762 crlgen_InitExtensionHandle(void *extHandle,
763                            CERTCertExtension **extensions)
764 {
765     CERTCertExtension *extension = NULL;
766 
767     if (!extensions)
768         return SECSuccess;
769 
770     PORT_Assert(extHandle != NULL);
771     if (!extHandle) {
772         return SECFailure;
773     }
774 
775     extension = *extensions;
776     while (extension) {
777         SECOidTag oidTag = SECOID_FindOIDTag(&extension->id);
778         /* shell we skip unknown extensions? */
779         CERT_AddExtension(extHandle, oidTag, &extension->value,
780                           (extension->critical.len != 0) ? PR_TRUE : PR_FALSE,
781                           PR_FALSE);
782         extension = *(++extensions);
783     }
784     return SECSuccess;
785 }
786 
787 /* Used for initialization of extension handles for crl and certs
788  * extensions from existing CRL data then modifying existing CRL.*/
789 SECStatus
CRLGEN_ExtHandleInit(CRLGENGeneratorData * crlGenData)790 CRLGEN_ExtHandleInit(CRLGENGeneratorData *crlGenData)
791 {
792     CERTCrl *crl = NULL;
793     PRUint64 maxSN = 0;
794 
795     PORT_Assert(crlGenData && crlGenData->signCrl &&
796                 crlGenData->entryDataHashTable);
797     if (!crlGenData || !crlGenData->signCrl ||
798         !crlGenData->entryDataHashTable) {
799         PORT_SetError(SEC_ERROR_INVALID_ARGS);
800         return SECFailure;
801     }
802 
803     crl = &crlGenData->signCrl->crl;
804     crlGenData->crlExtHandle = CERT_StartCRLExtensions(crl);
805     crlgen_InitExtensionHandle(crlGenData->crlExtHandle,
806                                crl->extensions);
807     crl->extensions = NULL;
808 
809     if (crl->entries) {
810         CERTCrlEntry **entry = crl->entries;
811         while (*entry) {
812             PRUint64 sn = DER_GetInteger(&(*entry)->serialNumber);
813             CRLGENEntryData *extData =
814                 crlgen_PlaceAnEntry(crlGenData, *entry, &(*entry)->serialNumber);
815             if ((*entry)->extensions) {
816                 extData->extHandle =
817                     CERT_StartCRLEntryExtensions(&crlGenData->signCrl->crl,
818                                                  (CERTCrlEntry *)extData->entry);
819                 if (crlgen_InitExtensionHandle(extData->extHandle,
820                                                (*entry)->extensions) == SECFailure)
821                     return SECFailure;
822             }
823             (*entry)->extensions = NULL;
824             entry++;
825             maxSN = PR_MAX(maxSN, sn);
826         }
827     }
828 
829     crlGenData->rangeFrom = crlGenData->rangeTo = maxSN + 1;
830     return SECSuccess;
831 }
832 
833 /*****************************************************************************
834  * Parser trigger functions start here
835  */
836 
837 /* Sets new internal range value for add/rm certs.*/
838 static SECStatus
crlgen_SetNewRangeField(CRLGENGeneratorData * crlGenData,char * value)839 crlgen_SetNewRangeField(CRLGENGeneratorData *crlGenData, char *value)
840 {
841     long rangeFrom = 0, rangeTo = 0;
842     char *dashPos = NULL;
843 
844     PORT_Assert(crlGenData);
845     if (!crlGenData) {
846         PORT_SetError(SEC_ERROR_INVALID_ARGS);
847         return SECFailure;
848     }
849 
850     if (value == NULL) {
851         PORT_SetError(SEC_ERROR_INVALID_ARGS);
852         crlgen_PrintError(crlGenData->parsedLineNum,
853                           "insufficient number of arguments.\n");
854         return SECFailure;
855     }
856 
857     if ((dashPos = strchr(value, '-')) != NULL) {
858         char *rangeToS, *rangeFromS = value;
859         *dashPos = '\0';
860         rangeFrom = atoi(rangeFromS);
861         *dashPos = '-';
862 
863         rangeToS = (char *)(dashPos + 1);
864         rangeTo = atol(rangeToS);
865     } else {
866         rangeFrom = atol(value);
867         rangeTo = rangeFrom;
868     }
869 
870     if (rangeFrom < 1 || rangeTo < rangeFrom) {
871         PORT_SetError(SEC_ERROR_INVALID_ARGS);
872         crlgen_PrintError(crlGenData->parsedLineNum,
873                           "bad cert id range: %s.\n", value);
874         return SECFailure;
875     }
876 
877     crlGenData->rangeFrom = rangeFrom;
878     crlGenData->rangeTo = rangeTo;
879 
880     return SECSuccess;
881 }
882 
883 /* Changes issuer subject field in CRL. By default this data is taken from
884  * issuer cert subject field.Not yet implemented */
885 static SECStatus
crlgen_SetIssuerField(CRLGENGeneratorData * crlGenData,char * value)886 crlgen_SetIssuerField(CRLGENGeneratorData *crlGenData, char *value)
887 {
888     crlgen_PrintError(crlGenData->parsedLineNum,
889                       "Can not change CRL issuer field.\n");
890     return SECFailure;
891 }
892 
893 /* Encode and sets CRL thisUpdate and nextUpdate time fields*/
894 static SECStatus
crlgen_SetTimeField(CRLGENGeneratorData * crlGenData,char * value,PRBool setThisUpdate)895 crlgen_SetTimeField(CRLGENGeneratorData *crlGenData, char *value,
896                     PRBool setThisUpdate)
897 {
898     CERTSignedCrl *signCrl;
899     PLArenaPool *arena;
900     CERTCrl *crl;
901     int length = 0;
902     SECItem *timeDest = NULL;
903 
904     PORT_Assert(crlGenData && crlGenData->signCrl &&
905                 crlGenData->signCrl->arena);
906     if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
907         PORT_SetError(SEC_ERROR_INVALID_ARGS);
908         return SECFailure;
909     }
910 
911     signCrl = crlGenData->signCrl;
912     arena = signCrl->arena;
913     crl = &signCrl->crl;
914 
915     if (value == NULL) {
916         PORT_SetError(SEC_ERROR_INVALID_ARGS);
917         crlgen_PrintError(crlGenData->parsedLineNum,
918                           "insufficient number of arguments.\n");
919         return SECFailure;
920     }
921     length = PORT_Strlen(value);
922 
923     if (setThisUpdate == PR_TRUE) {
924         timeDest = &crl->lastUpdate;
925     } else {
926         timeDest = &crl->nextUpdate;
927     }
928 
929     timeDest->type = siGeneralizedTime;
930     timeDest->data = PORT_ArenaAlloc(arena, length);
931     if (!timeDest->data) {
932         return SECFailure;
933     }
934     PORT_Memcpy(timeDest->data, value, length);
935     timeDest->len = length;
936 
937     return SECSuccess;
938 }
939 
940 /* Adds new extension into CRL or added cert handles */
941 static SECStatus
crlgen_AddExtension(CRLGENGeneratorData * crlGenData,const char ** extData)942 crlgen_AddExtension(CRLGENGeneratorData *crlGenData, const char **extData)
943 {
944     PORT_Assert(crlGenData && crlGenData->crlExtHandle);
945     if (!crlGenData || !crlGenData->crlExtHandle) {
946         PORT_SetError(SEC_ERROR_INVALID_ARGS);
947         return SECFailure;
948     }
949 
950     if (extData == NULL || *extData == NULL) {
951         PORT_SetError(SEC_ERROR_INVALID_ARGS);
952         crlgen_PrintError(crlGenData->parsedLineNum,
953                           "insufficient number of arguments.\n");
954         return SECFailure;
955     }
956     if (!PORT_Strcmp(*extData, "authKeyId"))
957         return crlgen_AddAuthKeyID(crlGenData, extData);
958     else if (!PORT_Strcmp(*extData, "issuerAltNames"))
959         return crlgen_AddIssuerAltNames(crlGenData, extData);
960     else if (!PORT_Strcmp(*extData, "crlNumber"))
961         return crlgen_AddCrlNumber(crlGenData, extData);
962     else if (!PORT_Strcmp(*extData, "reasonCode"))
963         return crlgen_AddEntryExtension(crlGenData, extData, "reasonCode",
964                                         crlgen_CreateReasonCode);
965     else if (!PORT_Strcmp(*extData, "invalidityDate"))
966         return crlgen_AddEntryExtension(crlGenData, extData, "invalidityDate",
967                                         crlgen_CreateInvalidityDate);
968     else {
969         PORT_SetError(SEC_ERROR_INVALID_ARGS);
970         crlgen_PrintError(crlGenData->parsedLineNum,
971                           "insufficient number of arguments.\n");
972         return SECFailure;
973     }
974 }
975 
976 /* Created CRLGENEntryData for cert with serial number certId and
977  * adds it to entryDataHashTable. certId can be a single cert serial
978  * number or an inclusive rage of certs */
979 static SECStatus
crlgen_AddCert(CRLGENGeneratorData * crlGenData,char * certId,char * revocationDate)980 crlgen_AddCert(CRLGENGeneratorData *crlGenData,
981                char *certId, char *revocationDate)
982 {
983     CERTSignedCrl *signCrl;
984     SECItem *certIdItem;
985     PLArenaPool *arena;
986     PRUint64 rangeFrom = 0, rangeTo = 0, i = 0;
987     int timeValLength = -1;
988     SECStatus rv = SECFailure;
989     void *mark;
990 
991     PORT_Assert(crlGenData && crlGenData->signCrl &&
992                 crlGenData->signCrl->arena);
993     if (!crlGenData || !crlGenData->signCrl || !crlGenData->signCrl->arena) {
994         PORT_SetError(SEC_ERROR_INVALID_ARGS);
995         return SECFailure;
996     }
997 
998     signCrl = crlGenData->signCrl;
999     arena = signCrl->arena;
1000 
1001     if (!certId || !revocationDate) {
1002         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1003         crlgen_PrintError(crlGenData->parsedLineNum,
1004                           "insufficient number of arguments.\n");
1005         return SECFailure;
1006     }
1007 
1008     timeValLength = strlen(revocationDate);
1009 
1010     if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
1011         certId) {
1012         return SECFailure;
1013     }
1014     rangeFrom = crlGenData->rangeFrom;
1015     rangeTo = crlGenData->rangeTo;
1016 
1017     for (i = 0; i < rangeTo - rangeFrom + 1; i++) {
1018         CERTCrlEntry *entry;
1019         mark = PORT_ArenaMark(arena);
1020         entry = PORT_ArenaZNew(arena, CERTCrlEntry);
1021         if (entry == NULL) {
1022             goto loser;
1023         }
1024 
1025         certIdItem = SEC_ASN1EncodeInteger(arena, &entry->serialNumber,
1026                                            rangeFrom + i);
1027         if (!certIdItem) {
1028             goto loser;
1029         }
1030 
1031         if (crlgen_FindEntry(crlGenData, certIdItem)) {
1032             crlgen_PrintError(crlGenData->parsedLineNum,
1033                               "entry already exists. Use \"range\" "
1034                               "and \"rmcert\" before adding a new one with the "
1035                               "same serial number %ld\n",
1036                               rangeFrom + i);
1037             goto loser;
1038         }
1039 
1040         entry->serialNumber.type = siBuffer;
1041 
1042         entry->revocationDate.type = siGeneralizedTime;
1043 
1044         entry->revocationDate.data =
1045             PORT_ArenaAlloc(arena, timeValLength);
1046         if (entry->revocationDate.data == NULL) {
1047             goto loser;
1048         }
1049 
1050         PORT_Memcpy(entry->revocationDate.data, revocationDate,
1051                     timeValLength * sizeof(char));
1052         entry->revocationDate.len = timeValLength;
1053 
1054         entry->extensions = NULL;
1055         if (!crlgen_PlaceAnEntry(crlGenData, entry, certIdItem)) {
1056             goto loser;
1057         }
1058         mark = NULL;
1059     }
1060 
1061     rv = SECSuccess;
1062 loser:
1063     if (mark) {
1064         PORT_ArenaRelease(arena, mark);
1065     }
1066     return rv;
1067 }
1068 
1069 /* Removes certs from entryDataHashTable which have certId serial number.
1070  * certId can have value of a range of certs */
1071 static SECStatus
crlgen_RmCert(CRLGENGeneratorData * crlGenData,char * certId)1072 crlgen_RmCert(CRLGENGeneratorData *crlGenData, char *certId)
1073 {
1074     PRUint64 i = 0;
1075 
1076     PORT_Assert(crlGenData && certId);
1077     if (!crlGenData || !certId) {
1078         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1079         return SECFailure;
1080     }
1081 
1082     if (crlgen_SetNewRangeField(crlGenData, certId) == SECFailure &&
1083         certId) {
1084         return SECFailure;
1085     }
1086 
1087     for (i = 0; i < crlGenData->rangeTo - crlGenData->rangeFrom + 1; i++) {
1088         SECItem *certIdItem = SEC_ASN1EncodeInteger(NULL, NULL,
1089                                                     crlGenData->rangeFrom + i);
1090         if (certIdItem) {
1091             CRLGENEntryData *extData =
1092                 crlgen_FindEntry(crlGenData, certIdItem);
1093             if (!extData) {
1094                 printf("Cert with id %s is not in the list\n", certId);
1095             } else {
1096                 crlgen_RmEntry(crlGenData, certIdItem);
1097             }
1098             SECITEM_FreeItem(certIdItem, PR_TRUE);
1099         }
1100     }
1101 
1102     return SECSuccess;
1103 }
1104 
1105 /*************************************************************************
1106  * Lex Parser Helper functions are used to store parsed information
1107  * in context related structures. Context(or state) is identified base on
1108  * a type of a instruction parser currently is going through. New context
1109  * is identified by first token in a line. It can be addcert context,
1110  * addext context, etc. */
1111 
1112 /* Updates CRL field depending on current context */
1113 static SECStatus
crlgen_updateCrlFn_field(CRLGENGeneratorData * crlGenData,void * str)1114 crlgen_updateCrlFn_field(CRLGENGeneratorData *crlGenData, void *str)
1115 {
1116     CRLGENCrlField *fieldStr = (CRLGENCrlField *)str;
1117 
1118     PORT_Assert(crlGenData);
1119     if (!crlGenData) {
1120         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1121         return SECFailure;
1122     }
1123 
1124     switch (crlGenData->contextId) {
1125         case CRLGEN_ISSUER_CONTEXT:
1126             crlgen_SetIssuerField(crlGenData, fieldStr->value);
1127             break;
1128         case CRLGEN_UPDATE_CONTEXT:
1129             return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_TRUE);
1130             break;
1131         case CRLGEN_NEXT_UPDATE_CONTEXT:
1132             return crlgen_SetTimeField(crlGenData, fieldStr->value, PR_FALSE);
1133             break;
1134         case CRLGEN_CHANGE_RANGE_CONTEXT:
1135             return crlgen_SetNewRangeField(crlGenData, fieldStr->value);
1136             break;
1137         default:
1138             crlgen_PrintError(crlGenData->parsedLineNum,
1139                               "syntax error (unknow token type: %d)\n",
1140                               crlGenData->contextId);
1141             PORT_SetError(SEC_ERROR_INVALID_ARGS);
1142             return SECFailure;
1143     }
1144     return SECSuccess;
1145 }
1146 
1147 /* Sets parsed data for CRL field update into temporary structure */
1148 static SECStatus
crlgen_setNextDataFn_field(CRLGENGeneratorData * crlGenData,void * str,void * data,unsigned short dtype)1149 crlgen_setNextDataFn_field(CRLGENGeneratorData *crlGenData, void *str,
1150                            void *data, unsigned short dtype)
1151 {
1152     CRLGENCrlField *fieldStr = (CRLGENCrlField *)str;
1153 
1154     PORT_Assert(crlGenData);
1155     if (!crlGenData) {
1156         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1157         return SECFailure;
1158     }
1159 
1160     switch (crlGenData->contextId) {
1161         case CRLGEN_CHANGE_RANGE_CONTEXT:
1162             if (dtype != CRLGEN_TYPE_DIGIT && dtype != CRLGEN_TYPE_DIGIT_RANGE) {
1163                 crlgen_PrintError(crlGenData->parsedLineNum,
1164                                   "range value should have "
1165                                   "numeric or numeric range values.\n");
1166                 return SECFailure;
1167             }
1168             break;
1169         case CRLGEN_NEXT_UPDATE_CONTEXT:
1170         case CRLGEN_UPDATE_CONTEXT:
1171             if (dtype != CRLGEN_TYPE_ZDATE) {
1172                 crlgen_PrintError(crlGenData->parsedLineNum,
1173                                   "bad formated date. Should be "
1174                                   "YYYYMMDDHHMMSSZ.\n");
1175                 return SECFailure;
1176             }
1177             break;
1178         default:
1179             PORT_SetError(SEC_ERROR_INVALID_ARGS);
1180             crlgen_PrintError(crlGenData->parsedLineNum,
1181                               "syntax error (unknow token type: %d).\n",
1182                               crlGenData->contextId, data);
1183             return SECFailure;
1184     }
1185     fieldStr->value = PORT_Strdup(data);
1186     if (!fieldStr->value) {
1187         return SECFailure;
1188     }
1189     return SECSuccess;
1190 }
1191 
1192 /* Triggers cert entries update depending on current context */
1193 static SECStatus
crlgen_updateCrlFn_cert(CRLGENGeneratorData * crlGenData,void * str)1194 crlgen_updateCrlFn_cert(CRLGENGeneratorData *crlGenData, void *str)
1195 {
1196     CRLGENCertEntry *certStr = (CRLGENCertEntry *)str;
1197 
1198     PORT_Assert(crlGenData);
1199     if (!crlGenData) {
1200         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1201         return SECFailure;
1202     }
1203 
1204     switch (crlGenData->contextId) {
1205         case CRLGEN_ADD_CERT_CONTEXT:
1206             return crlgen_AddCert(crlGenData, certStr->certId,
1207                                   certStr->revocationTime);
1208         case CRLGEN_RM_CERT_CONTEXT:
1209             return crlgen_RmCert(crlGenData, certStr->certId);
1210         default:
1211             PORT_SetError(SEC_ERROR_INVALID_ARGS);
1212             crlgen_PrintError(crlGenData->parsedLineNum,
1213                               "syntax error (unknow token type: %d).\n",
1214                               crlGenData->contextId);
1215             return SECFailure;
1216     }
1217 }
1218 
1219 /* Sets parsed data for CRL entries update into temporary structure */
1220 static SECStatus
crlgen_setNextDataFn_cert(CRLGENGeneratorData * crlGenData,void * str,void * data,unsigned short dtype)1221 crlgen_setNextDataFn_cert(CRLGENGeneratorData *crlGenData, void *str,
1222                           void *data, unsigned short dtype)
1223 {
1224     CRLGENCertEntry *certStr = (CRLGENCertEntry *)str;
1225 
1226     PORT_Assert(crlGenData);
1227     if (!crlGenData) {
1228         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1229         return SECFailure;
1230     }
1231 
1232     switch (dtype) {
1233         case CRLGEN_TYPE_DIGIT:
1234         case CRLGEN_TYPE_DIGIT_RANGE:
1235             certStr->certId = PORT_Strdup(data);
1236             if (!certStr->certId) {
1237                 return SECFailure;
1238             }
1239             break;
1240         case CRLGEN_TYPE_DATE:
1241         case CRLGEN_TYPE_ZDATE:
1242             certStr->revocationTime = PORT_Strdup(data);
1243             if (!certStr->revocationTime) {
1244                 return SECFailure;
1245             }
1246             break;
1247         default:
1248             PORT_SetError(SEC_ERROR_INVALID_ARGS);
1249             crlgen_PrintError(crlGenData->parsedLineNum,
1250                               "syntax error (unknow token type: %d).\n",
1251                               crlGenData->contextId);
1252             return SECFailure;
1253     }
1254     return SECSuccess;
1255 }
1256 
1257 /* Triggers cert entries/crl extension update */
1258 static SECStatus
crlgen_updateCrlFn_extension(CRLGENGeneratorData * crlGenData,void * str)1259 crlgen_updateCrlFn_extension(CRLGENGeneratorData *crlGenData, void *str)
1260 {
1261     CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry *)str;
1262 
1263     return crlgen_AddExtension(crlGenData, (const char **)extStr->extData);
1264 }
1265 
1266 /* Defines maximum number of fields extension may have */
1267 #define MAX_EXT_DATA_LENGTH 10
1268 
1269 /* Sets parsed extension data for CRL entries/CRL extensions update
1270  * into temporary structure */
1271 static SECStatus
crlgen_setNextDataFn_extension(CRLGENGeneratorData * crlGenData,void * str,void * data,unsigned short dtype)1272 crlgen_setNextDataFn_extension(CRLGENGeneratorData *crlGenData, void *str,
1273                                void *data, unsigned short dtype)
1274 {
1275     CRLGENExtensionEntry *extStr = (CRLGENExtensionEntry *)str;
1276 
1277     PORT_Assert(crlGenData);
1278     if (!crlGenData) {
1279         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1280         return SECFailure;
1281     }
1282 
1283     if (extStr->extData == NULL) {
1284         extStr->extData = PORT_ZNewArray(char *, MAX_EXT_DATA_LENGTH);
1285         if (!extStr->extData) {
1286             return SECFailure;
1287         }
1288     }
1289     if (extStr->nextUpdatedData >= MAX_EXT_DATA_LENGTH) {
1290         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1291         crlgen_PrintError(crlGenData->parsedLineNum,
1292                           "number of fields in extension "
1293                           "exceeded maximum allowed data length: %d.\n",
1294                           MAX_EXT_DATA_LENGTH);
1295         return SECFailure;
1296     }
1297     extStr->extData[extStr->nextUpdatedData] = PORT_Strdup(data);
1298     if (!extStr->extData[extStr->nextUpdatedData]) {
1299         return SECFailure;
1300     }
1301     extStr->nextUpdatedData += 1;
1302 
1303     return SECSuccess;
1304 }
1305 
1306 /****************************************************************************************
1307  * Top level functions are triggered directly by parser.
1308  */
1309 
1310 /*
1311  * crl generation script parser recreates a temporary data staructure
1312  * for each line it is going through. This function cleans temp structure.
1313  */
1314 void
crlgen_destroyTempData(CRLGENGeneratorData * crlGenData)1315 crlgen_destroyTempData(CRLGENGeneratorData *crlGenData)
1316 {
1317     if (crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
1318         switch (crlGenData->contextId) {
1319             case CRLGEN_ISSUER_CONTEXT:
1320             case CRLGEN_UPDATE_CONTEXT:
1321             case CRLGEN_NEXT_UPDATE_CONTEXT:
1322             case CRLGEN_CHANGE_RANGE_CONTEXT:
1323                 if (crlGenData->crlField->value)
1324                     PORT_Free(crlGenData->crlField->value);
1325                 PORT_Free(crlGenData->crlField);
1326                 break;
1327             case CRLGEN_ADD_CERT_CONTEXT:
1328             case CRLGEN_RM_CERT_CONTEXT:
1329                 if (crlGenData->certEntry->certId)
1330                     PORT_Free(crlGenData->certEntry->certId);
1331                 if (crlGenData->certEntry->revocationTime)
1332                     PORT_Free(crlGenData->certEntry->revocationTime);
1333                 PORT_Free(crlGenData->certEntry);
1334                 break;
1335             case CRLGEN_ADD_EXTENSION_CONTEXT:
1336                 if (crlGenData->extensionEntry->extData) {
1337                     int i = 0;
1338                     for (; i < crlGenData->extensionEntry->nextUpdatedData; i++)
1339                         PORT_Free(*(crlGenData->extensionEntry->extData + i));
1340                     PORT_Free(crlGenData->extensionEntry->extData);
1341                 }
1342                 PORT_Free(crlGenData->extensionEntry);
1343                 break;
1344         }
1345         crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
1346     }
1347 }
1348 
1349 SECStatus
crlgen_updateCrl(CRLGENGeneratorData * crlGenData)1350 crlgen_updateCrl(CRLGENGeneratorData *crlGenData)
1351 {
1352     SECStatus rv = SECSuccess;
1353 
1354     PORT_Assert(crlGenData);
1355     if (!crlGenData) {
1356         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1357         return SECFailure;
1358     }
1359 
1360     switch (crlGenData->contextId) {
1361         case CRLGEN_ISSUER_CONTEXT:
1362         case CRLGEN_UPDATE_CONTEXT:
1363         case CRLGEN_NEXT_UPDATE_CONTEXT:
1364         case CRLGEN_CHANGE_RANGE_CONTEXT:
1365             rv = crlGenData->crlField->updateCrlFn(crlGenData, crlGenData->crlField);
1366             break;
1367         case CRLGEN_RM_CERT_CONTEXT:
1368         case CRLGEN_ADD_CERT_CONTEXT:
1369             rv = crlGenData->certEntry->updateCrlFn(crlGenData, crlGenData->certEntry);
1370             break;
1371         case CRLGEN_ADD_EXTENSION_CONTEXT:
1372             rv = crlGenData->extensionEntry->updateCrlFn(crlGenData, crlGenData->extensionEntry);
1373             break;
1374         case CRLGEN_UNKNOWN_CONTEXT:
1375             break;
1376         default:
1377             crlgen_PrintError(crlGenData->parsedLineNum,
1378                               "unknown lang context type code: %d.\n",
1379                               crlGenData->contextId);
1380             PORT_Assert(0);
1381             return SECFailure;
1382     }
1383     /* Clrean structures after crl update */
1384     crlgen_destroyTempData(crlGenData);
1385 
1386     crlGenData->parsedLineNum += 1;
1387 
1388     return rv;
1389 }
1390 
1391 SECStatus
crlgen_setNextData(CRLGENGeneratorData * crlGenData,void * data,unsigned short dtype)1392 crlgen_setNextData(CRLGENGeneratorData *crlGenData, void *data,
1393                    unsigned short dtype)
1394 {
1395     SECStatus rv = SECSuccess;
1396 
1397     PORT_Assert(crlGenData);
1398     if (!crlGenData) {
1399         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1400         return SECFailure;
1401     }
1402 
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             rv = crlGenData->crlField->setNextDataFn(crlGenData, crlGenData->crlField,
1409                                                      data, dtype);
1410             break;
1411         case CRLGEN_ADD_CERT_CONTEXT:
1412         case CRLGEN_RM_CERT_CONTEXT:
1413             rv = crlGenData->certEntry->setNextDataFn(crlGenData, crlGenData->certEntry,
1414                                                       data, dtype);
1415             break;
1416         case CRLGEN_ADD_EXTENSION_CONTEXT:
1417             rv =
1418                 crlGenData->extensionEntry->setNextDataFn(crlGenData, crlGenData->extensionEntry, data, dtype);
1419             break;
1420         case CRLGEN_UNKNOWN_CONTEXT:
1421             break;
1422         default:
1423             crlgen_PrintError(crlGenData->parsedLineNum,
1424                               "unknown context type: %d.\n",
1425                               crlGenData->contextId);
1426             PORT_Assert(0);
1427             return SECFailure;
1428     }
1429     return rv;
1430 }
1431 
1432 SECStatus
crlgen_createNewLangStruct(CRLGENGeneratorData * crlGenData,unsigned structType)1433 crlgen_createNewLangStruct(CRLGENGeneratorData *crlGenData,
1434                            unsigned structType)
1435 {
1436     PORT_Assert(crlGenData &&
1437                 crlGenData->contextId == CRLGEN_UNKNOWN_CONTEXT);
1438     if (!crlGenData ||
1439         crlGenData->contextId != CRLGEN_UNKNOWN_CONTEXT) {
1440         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1441         return SECFailure;
1442     }
1443 
1444     switch (structType) {
1445         case CRLGEN_ISSUER_CONTEXT:
1446         case CRLGEN_UPDATE_CONTEXT:
1447         case CRLGEN_NEXT_UPDATE_CONTEXT:
1448         case CRLGEN_CHANGE_RANGE_CONTEXT:
1449             crlGenData->crlField = PORT_New(CRLGENCrlField);
1450             if (!crlGenData->crlField) {
1451                 return SECFailure;
1452             }
1453             crlGenData->contextId = structType;
1454             crlGenData->crlField->value = NULL;
1455             crlGenData->crlField->updateCrlFn = &crlgen_updateCrlFn_field;
1456             crlGenData->crlField->setNextDataFn = &crlgen_setNextDataFn_field;
1457             break;
1458         case CRLGEN_RM_CERT_CONTEXT:
1459         case CRLGEN_ADD_CERT_CONTEXT:
1460             crlGenData->certEntry = PORT_New(CRLGENCertEntry);
1461             if (!crlGenData->certEntry) {
1462                 return SECFailure;
1463             }
1464             crlGenData->contextId = structType;
1465             crlGenData->certEntry->certId = 0;
1466             crlGenData->certEntry->revocationTime = NULL;
1467             crlGenData->certEntry->updateCrlFn = &crlgen_updateCrlFn_cert;
1468             crlGenData->certEntry->setNextDataFn = &crlgen_setNextDataFn_cert;
1469             break;
1470         case CRLGEN_ADD_EXTENSION_CONTEXT:
1471             crlGenData->extensionEntry = PORT_New(CRLGENExtensionEntry);
1472             if (!crlGenData->extensionEntry) {
1473                 return SECFailure;
1474             }
1475             crlGenData->contextId = structType;
1476             crlGenData->extensionEntry->extData = NULL;
1477             crlGenData->extensionEntry->nextUpdatedData = 0;
1478             crlGenData->extensionEntry->updateCrlFn =
1479                 &crlgen_updateCrlFn_extension;
1480             crlGenData->extensionEntry->setNextDataFn =
1481                 &crlgen_setNextDataFn_extension;
1482             break;
1483         case CRLGEN_UNKNOWN_CONTEXT:
1484             break;
1485         default:
1486             crlgen_PrintError(crlGenData->parsedLineNum,
1487                               "unknown context type: %d.\n", structType);
1488             PORT_Assert(0);
1489             return SECFailure;
1490     }
1491     return SECSuccess;
1492 }
1493 
1494 /* Parser initialization function */
1495 CRLGENGeneratorData *
CRLGEN_InitCrlGeneration(CERTSignedCrl * signCrl,PRFileDesc * src)1496 CRLGEN_InitCrlGeneration(CERTSignedCrl *signCrl, PRFileDesc *src)
1497 {
1498     CRLGENGeneratorData *crlGenData = NULL;
1499 
1500     PORT_Assert(signCrl && src);
1501     if (!signCrl || !src) {
1502         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1503         return NULL;
1504     }
1505 
1506     crlGenData = PORT_ZNew(CRLGENGeneratorData);
1507     if (!crlGenData) {
1508         return NULL;
1509     }
1510 
1511     crlGenData->entryDataHashTable =
1512         PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
1513                         PL_CompareValues, NULL, NULL);
1514     if (!crlGenData->entryDataHashTable) {
1515         PORT_Free(crlGenData);
1516         return NULL;
1517     }
1518 
1519     crlGenData->src = src;
1520     crlGenData->parsedLineNum = 1;
1521     crlGenData->contextId = CRLGEN_UNKNOWN_CONTEXT;
1522     crlGenData->signCrl = signCrl;
1523     crlGenData->rangeFrom = 0;
1524     crlGenData->rangeTo = 0;
1525     crlGenData->crlExtHandle = NULL;
1526 
1527     PORT_SetError(0);
1528 
1529     return crlGenData;
1530 }
1531 
1532 void
CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData * crlGenData)1533 CRLGEN_FinalizeCrlGeneration(CRLGENGeneratorData *crlGenData)
1534 {
1535     if (!crlGenData)
1536         return;
1537     if (crlGenData->src)
1538         PR_Close(crlGenData->src);
1539     PL_HashTableDestroy(crlGenData->entryDataHashTable);
1540     PORT_Free(crlGenData);
1541 }
1542