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 ** certutil.c
7 **
8 ** utility for managing certificates and the cert database
9 **
10 */
11 /* test only */
12 
13 #include "nspr.h"
14 #include "plgetopt.h"
15 #include "secutil.h"
16 #include "cert.h"
17 #include "certi.h"
18 #include "certdb.h"
19 #include "nss.h"
20 #include "pk11func.h"
21 #include "crlgen.h"
22 
23 #define SEC_CERT_DB_EXISTS 0
24 #define SEC_CREATE_CERT_DB 1
25 
26 static char *progName;
27 
28 static CERTSignedCrl *
FindCRL(CERTCertDBHandle * certHandle,char * name,int type)29 FindCRL(CERTCertDBHandle *certHandle, char *name, int type)
30 {
31     CERTSignedCrl *crl = NULL;
32     CERTCertificate *cert = NULL;
33     SECItem derName;
34 
35     derName.data = NULL;
36     derName.len = 0;
37 
38     cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name);
39     if (!cert) {
40         CERTName *certName = NULL;
41         PLArenaPool *arena = NULL;
42         SECStatus rv = SECSuccess;
43 
44         certName = CERT_AsciiToName(name);
45         if (certName) {
46             arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
47             if (arena) {
48                 SECItem *nameItem =
49                     SEC_ASN1EncodeItem(arena, NULL, (void *)certName,
50                                        SEC_ASN1_GET(CERT_NameTemplate));
51                 if (nameItem) {
52                     rv = SECITEM_CopyItem(NULL, &derName, nameItem);
53                 }
54                 PORT_FreeArena(arena, PR_FALSE);
55             }
56             CERT_DestroyName(certName);
57         }
58 
59         if (rv != SECSuccess) {
60             SECU_PrintError(progName, "SECITEM_CopyItem failed, out of memory");
61             return ((CERTSignedCrl *)NULL);
62         }
63 
64         if (!derName.len || !derName.data) {
65             SECU_PrintError(progName, "could not find certificate named '%s'", name);
66             return ((CERTSignedCrl *)NULL);
67         }
68     } else {
69         SECStatus rv = SECITEM_CopyItem(NULL, &derName, &cert->derSubject);
70         CERT_DestroyCertificate(cert);
71         if (rv != SECSuccess) {
72             return ((CERTSignedCrl *)NULL);
73         }
74     }
75 
76     crl = SEC_FindCrlByName(certHandle, &derName, type);
77     if (crl == NULL)
78         SECU_PrintError(progName, "could not find %s's CRL", name);
79     if (derName.data) {
80         SECITEM_FreeItem(&derName, PR_FALSE);
81     }
82     return (crl);
83 }
84 
85 static SECStatus
DisplayCRL(CERTCertDBHandle * certHandle,char * nickName,int crlType)86 DisplayCRL(CERTCertDBHandle *certHandle, char *nickName, int crlType)
87 {
88     CERTSignedCrl *crl = NULL;
89 
90     crl = FindCRL(certHandle, nickName, crlType);
91 
92     if (crl) {
93         SECU_PrintCRLInfo(stdout, &crl->crl, "CRL Info:\n", 0);
94         SEC_DestroyCrl(crl);
95         return SECSuccess;
96     }
97     return SECFailure;
98 }
99 
100 static void
ListCRLNames(CERTCertDBHandle * certHandle,int crlType,PRBool deletecrls)101 ListCRLNames(CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls)
102 {
103     CERTCrlHeadNode *crlList = NULL;
104     CERTCrlNode *crlNode = NULL;
105     CERTName *name = NULL;
106     PLArenaPool *arena = NULL;
107     SECStatus rv;
108 
109     do {
110         arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
111         if (arena == NULL) {
112             fprintf(stderr, "%s: fail to allocate memory\n", progName);
113             break;
114         }
115 
116         name = PORT_ArenaZAlloc(arena, sizeof(*name));
117         if (name == NULL) {
118             fprintf(stderr, "%s: fail to allocate memory\n", progName);
119             break;
120         }
121         name->arena = arena;
122 
123         rv = SEC_LookupCrls(certHandle, &crlList, crlType);
124         if (rv != SECSuccess) {
125             fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName,
126                     SECU_Strerror(PORT_GetError()));
127             break;
128         }
129 
130         /* just in case */
131         if (!crlList)
132             break;
133 
134         crlNode = crlList->first;
135 
136         fprintf(stdout, "\n");
137         fprintf(stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type");
138         while (crlNode) {
139             char *asciiname = NULL;
140             CERTCertificate *cert = NULL;
141             if (crlNode->crl && crlNode->crl->crl.derName.data != NULL) {
142                 cert = CERT_FindCertByName(certHandle,
143                                            &crlNode->crl->crl.derName);
144                 if (!cert) {
145                     SECU_PrintError(progName, "could not find signing "
146                                               "certificate in database");
147                 }
148             }
149             if (cert) {
150                 char *certName = NULL;
151                 if (cert->nickname && PORT_Strlen(cert->nickname) > 0) {
152                     certName = cert->nickname;
153                 } else if (cert->emailAddr && PORT_Strlen(cert->emailAddr) > 0) {
154                     certName = cert->emailAddr;
155                 }
156                 if (certName) {
157                     asciiname = PORT_Strdup(certName);
158                 }
159                 CERT_DestroyCertificate(cert);
160             }
161 
162             if (!asciiname) {
163                 name = &crlNode->crl->crl.name;
164                 if (!name) {
165                     SECU_PrintError(progName, "fail to get the CRL "
166                                               "issuer name");
167                     continue;
168                 }
169                 asciiname = CERT_NameToAscii(name);
170             }
171             fprintf(stdout, "%-40s %-5s\n", asciiname, "CRL");
172             if (asciiname) {
173                 PORT_Free(asciiname);
174             }
175             if (PR_TRUE == deletecrls) {
176                 CERTSignedCrl *acrl = NULL;
177                 SECItem *issuer = &crlNode->crl->crl.derName;
178                 acrl = SEC_FindCrlByName(certHandle, issuer, crlType);
179                 if (acrl) {
180                     SEC_DeletePermCRL(acrl);
181                     SEC_DestroyCrl(acrl);
182                 }
183             }
184             crlNode = crlNode->next;
185         }
186 
187     } while (0);
188     if (crlList)
189         PORT_FreeArena(crlList->arena, PR_FALSE);
190     PORT_FreeArena(arena, PR_FALSE);
191 }
192 
193 static SECStatus
ListCRL(CERTCertDBHandle * certHandle,char * nickName,int crlType)194 ListCRL(CERTCertDBHandle *certHandle, char *nickName, int crlType)
195 {
196     if (nickName == NULL) {
197         ListCRLNames(certHandle, crlType, PR_FALSE);
198         return SECSuccess;
199     }
200 
201     return DisplayCRL(certHandle, nickName, crlType);
202 }
203 
204 static SECStatus
DeleteCRL(CERTCertDBHandle * certHandle,char * name,int type)205 DeleteCRL(CERTCertDBHandle *certHandle, char *name, int type)
206 {
207     CERTSignedCrl *crl = NULL;
208     SECStatus rv = SECFailure;
209 
210     crl = FindCRL(certHandle, name, type);
211     if (!crl) {
212         SECU_PrintError(progName, "could not find the issuer %s's CRL", name);
213         return SECFailure;
214     }
215     rv = SEC_DeletePermCRL(crl);
216     SEC_DestroyCrl(crl);
217     if (rv != SECSuccess) {
218         SECU_PrintError(progName, "fail to delete the issuer %s's CRL "
219                                   "from the perm database (reason: %s)",
220                         name, SECU_Strerror(PORT_GetError()));
221         return SECFailure;
222     }
223     return (rv);
224 }
225 
226 SECStatus
ImportCRL(CERTCertDBHandle * certHandle,char * url,int type,PRFileDesc * inFile,PRInt32 importOptions,PRInt32 decodeOptions,secuPWData * pwdata)227 ImportCRL(CERTCertDBHandle *certHandle, char *url, int type,
228           PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions,
229           secuPWData *pwdata)
230 {
231     CERTSignedCrl *crl = NULL;
232     SECItem crlDER;
233     PK11SlotInfo *slot = NULL;
234     int rv;
235 
236     crlDER.data = NULL;
237 
238     /* Read in the entire file specified with the -f argument */
239     rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
240     if (rv != SECSuccess) {
241         SECU_PrintError(progName, "unable to read input file");
242         return (SECFailure);
243     }
244 
245     decodeOptions |= CRL_DECODE_DONT_COPY_DER;
246 
247     slot = PK11_GetInternalKeySlot();
248 
249     if (PK11_NeedLogin(slot)) {
250         rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
251         if (rv != SECSuccess)
252             goto loser;
253     }
254 
255     crl = PK11_ImportCRL(slot, &crlDER, url, type,
256                          NULL, importOptions, NULL, decodeOptions);
257 
258     if (!crl) {
259         const char *errString;
260 
261         rv = SECFailure;
262         errString = SECU_Strerror(PORT_GetError());
263         if (errString && PORT_Strlen(errString) == 0)
264             SECU_PrintError(progName,
265                             "CRL is not imported (error: input CRL is not up to date.)");
266         else
267             SECU_PrintError(progName, "unable to import CRL");
268     } else {
269         SEC_DestroyCrl(crl);
270     }
271 loser:
272     if (slot) {
273         PK11_FreeSlot(slot);
274     }
275     SECITEM_FreeItem(&crlDER, PR_FALSE);
276     return (rv);
277 }
278 
279 SECStatus
DumpCRL(PRFileDesc * inFile)280 DumpCRL(PRFileDesc *inFile)
281 {
282     int rv;
283     PLArenaPool *arena = NULL;
284     CERTSignedCrl *newCrl = NULL;
285 
286     SECItem crlDER;
287     crlDER.data = NULL;
288 
289     /* Read in the entire file specified with the -f argument */
290     rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
291     if (rv != SECSuccess) {
292         SECU_PrintError(progName, "unable to read input file");
293         return (SECFailure);
294     }
295 
296     rv = SEC_ERROR_NO_MEMORY;
297     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
298     if (!arena)
299         return rv;
300 
301     newCrl = CERT_DecodeDERCrlWithFlags(arena, &crlDER, SEC_CRL_TYPE,
302                                         CRL_DECODE_DEFAULT_OPTIONS);
303     if (!newCrl)
304         return SECFailure;
305 
306     SECU_PrintCRLInfo(stdout, &newCrl->crl, "CRL file contents", 0);
307 
308     PORT_FreeArena(arena, PR_FALSE);
309     return rv;
310 }
311 
312 static CERTCertificate *
FindSigningCert(CERTCertDBHandle * certHandle,CERTSignedCrl * signCrl,char * certNickName)313 FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl,
314                 char *certNickName)
315 {
316     CERTCertificate *cert = NULL, *certTemp = NULL;
317     SECStatus rv = SECFailure;
318     CERTAuthKeyID *authorityKeyID = NULL;
319     SECItem *subject = NULL;
320 
321     PORT_Assert(certHandle != NULL);
322     if (!certHandle || (!signCrl && !certNickName)) {
323         SECU_PrintError(progName, "invalid args for function "
324                                   "FindSigningCert \n");
325         return NULL;
326     }
327 
328     if (signCrl) {
329 #if 0
330         authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl);
331 #endif
332         subject = &signCrl->crl.derName;
333     } else {
334         certTemp = CERT_FindCertByNickname(certHandle, certNickName);
335         if (!certTemp) {
336             SECU_PrintError(progName, "could not find certificate \"%s\" "
337                                       "in database",
338                             certNickName);
339             goto loser;
340         }
341         subject = &certTemp->derSubject;
342     }
343 
344     cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now());
345     if (!cert) {
346         SECU_PrintError(progName, "could not find signing certificate "
347                                   "in database");
348         goto loser;
349     } else {
350         rv = SECSuccess;
351     }
352 
353 loser:
354     if (certTemp)
355         CERT_DestroyCertificate(certTemp);
356     if (cert && rv != SECSuccess)
357         CERT_DestroyCertificate(cert);
358     return cert;
359 }
360 
361 static CERTSignedCrl *
CreateModifiedCRLCopy(PLArenaPool * arena,CERTCertDBHandle * certHandle,CERTCertificate ** cert,char * certNickName,PRFileDesc * inFile,PRInt32 decodeOptions,PRInt32 importOptions,secuPWData * pwdata)362 CreateModifiedCRLCopy(PLArenaPool *arena, CERTCertDBHandle *certHandle,
363                       CERTCertificate **cert, char *certNickName,
364                       PRFileDesc *inFile, PRInt32 decodeOptions,
365                       PRInt32 importOptions, secuPWData *pwdata)
366 {
367     SECItem crlDER = { 0, NULL, 0 };
368     CERTSignedCrl *signCrl = NULL;
369     CERTSignedCrl *modCrl = NULL;
370     PLArenaPool *modArena = NULL;
371     SECStatus rv = SECSuccess;
372 
373     if (!arena || !certHandle || !certNickName) {
374         PORT_SetError(SEC_ERROR_INVALID_ARGS);
375         SECU_PrintError(progName, "CreateModifiedCRLCopy: invalid args\n");
376         return NULL;
377     }
378 
379     modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
380     if (!modArena) {
381         SECU_PrintError(progName, "fail to allocate memory\n");
382         return NULL;
383     }
384 
385     if (inFile != NULL) {
386         rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
387         if (rv != SECSuccess) {
388             SECU_PrintError(progName, "unable to read input file");
389             PORT_FreeArena(modArena, PR_FALSE);
390             goto loser;
391         }
392 
393         decodeOptions |= CRL_DECODE_DONT_COPY_DER;
394 
395         modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE,
396                                             decodeOptions);
397         if (!modCrl) {
398             SECU_PrintError(progName, "fail to decode CRL");
399             goto loser;
400         }
401 
402         if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)) {
403             /* If caCert is a v2 certificate, make sure that it
404              * can be used for crl signing purpose */
405             *cert = FindSigningCert(certHandle, modCrl, NULL);
406             if (!*cert) {
407                 goto loser;
408             }
409 
410             rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert,
411                                        PR_Now(), pwdata);
412             if (rv != SECSuccess) {
413                 SECU_PrintError(progName, "fail to verify signed data\n");
414                 goto loser;
415             }
416         }
417     } else {
418         modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE);
419         if (!modCrl) {
420             SECU_PrintError(progName, "fail to find crl %s in database\n",
421                             certNickName);
422             goto loser;
423         }
424     }
425 
426     signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
427     if (signCrl == NULL) {
428         SECU_PrintError(progName, "fail to allocate memory\n");
429         goto loser;
430     }
431 
432     rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl);
433     if (rv != SECSuccess) {
434         SECU_PrintError(progName, "unable to dublicate crl for "
435                                   "modification.");
436         goto loser;
437     }
438 
439     /* Make sure the update time is current. It can be modified later
440      * by "update <time>" command from crl generation script */
441     rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
442     if (rv != SECSuccess) {
443         SECU_PrintError(progName, "fail to encode current time\n");
444         goto loser;
445     }
446 
447     signCrl->arena = arena;
448     signCrl->referenceCount = 1;
449 
450 loser:
451     if (crlDER.data) {
452         SECITEM_FreeItem(&crlDER, PR_FALSE);
453     }
454     if (modArena && (!modCrl || modCrl->arena != modArena)) {
455         PORT_FreeArena(modArena, PR_FALSE);
456     }
457     if (modCrl)
458         SEC_DestroyCrl(modCrl);
459     if (rv != SECSuccess && signCrl) {
460         SEC_DestroyCrl(signCrl);
461         signCrl = NULL;
462     }
463     return signCrl;
464 }
465 
466 static CERTSignedCrl *
CreateNewCrl(PLArenaPool * arena,CERTCertDBHandle * certHandle,CERTCertificate * cert)467 CreateNewCrl(PLArenaPool *arena, CERTCertDBHandle *certHandle,
468              CERTCertificate *cert)
469 {
470     CERTSignedCrl *signCrl = NULL;
471     void *dummy = NULL;
472     SECStatus rv;
473     void *mark = NULL;
474 
475     /* if the CERTSignedCrl structure changes, this function will need to be
476        updated as well */
477     if (!cert || !arena) {
478         PORT_SetError(SEC_ERROR_INVALID_ARGS);
479         SECU_PrintError(progName, "invalid args for function "
480                                   "CreateNewCrl\n");
481         return NULL;
482     }
483 
484     mark = PORT_ArenaMark(arena);
485 
486     signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
487     if (signCrl == NULL) {
488         SECU_PrintError(progName, "fail to allocate memory\n");
489         return NULL;
490     }
491 
492     dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version,
493                                   SEC_CRL_VERSION_2);
494     /* set crl->version */
495     if (!dummy) {
496         SECU_PrintError(progName, "fail to create crl version data "
497                                   "container\n");
498         goto loser;
499     }
500 
501     /* copy SECItem name from cert */
502     rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject);
503     if (rv != SECSuccess) {
504         SECU_PrintError(progName, "fail to duplicate der name from "
505                                   "certificate.\n");
506         goto loser;
507     }
508 
509     /* copy CERTName name structure from cert issuer */
510     rv = CERT_CopyName(arena, &signCrl->crl.name, &cert->subject);
511     if (rv != SECSuccess) {
512         SECU_PrintError(progName, "fail to duplicate RD name from "
513                                   "certificate.\n");
514         goto loser;
515     }
516 
517     rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
518     if (rv != SECSuccess) {
519         SECU_PrintError(progName, "fail to encode current time\n");
520         goto loser;
521     }
522 
523     /* set fields */
524     signCrl->arena = arena;
525     signCrl->dbhandle = certHandle;
526     signCrl->crl.arena = arena;
527 
528     PORT_ArenaUnmark(arena, mark);
529 
530     return signCrl;
531 
532 loser:
533     PORT_ArenaRelease(arena, mark);
534     return NULL;
535 }
536 
537 static SECStatus
UpdateCrl(CERTSignedCrl * signCrl,PRFileDesc * inCrlInitFile)538 UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile)
539 {
540     CRLGENGeneratorData *crlGenData = NULL;
541     SECStatus rv;
542 
543     if (!signCrl || !inCrlInitFile) {
544         PORT_SetError(SEC_ERROR_INVALID_ARGS);
545         SECU_PrintError(progName, "invalid args for function "
546                                   "CreateNewCrl\n");
547         return SECFailure;
548     }
549 
550     crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile);
551     if (!crlGenData) {
552         SECU_PrintError(progName, "can not initialize parser structure.\n");
553         return SECFailure;
554     }
555 
556     rv = CRLGEN_ExtHandleInit(crlGenData);
557     if (rv == SECFailure) {
558         SECU_PrintError(progName, "can not initialize entries handle.\n");
559         goto loser;
560     }
561 
562     rv = CRLGEN_StartCrlGen(crlGenData);
563     if (rv != SECSuccess) {
564         SECU_PrintError(progName, "crl generation failed");
565         goto loser;
566     }
567 
568 loser:
569     /* CommitExtensionsAndEntries is partially responsible for freeing
570      * up memory that was used for CRL generation. Should be called regardless
571      * of previouse call status, but only after initialization of
572      * crlGenData was done. It will commit all changes that was done before
573      * an error has occurred.
574      */
575     if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) {
576         SECU_PrintError(progName, "crl generation failed");
577         rv = SECFailure;
578     }
579     CRLGEN_FinalizeCrlGeneration(crlGenData);
580     return rv;
581 }
582 
583 static SECStatus
SignAndStoreCrl(CERTSignedCrl * signCrl,CERTCertificate * cert,char * outFileName,SECOidTag hashAlgTag,int ascii,char * slotName,char * url,secuPWData * pwdata)584 SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert,
585                 char *outFileName, SECOidTag hashAlgTag, int ascii,
586                 char *slotName, char *url, secuPWData *pwdata)
587 {
588     PK11SlotInfo *slot = NULL;
589     PRFileDesc *outFile = NULL;
590     SECStatus rv;
591     SignAndEncodeFuncExitStat errCode;
592 
593     PORT_Assert(signCrl && (!ascii || outFileName));
594     if (!signCrl || (ascii && !outFileName)) {
595         SECU_PrintError(progName, "invalid args for function "
596                                   "SignAndStoreCrl\n");
597         return SECFailure;
598     }
599 
600     if (!slotName || !PL_strcmp(slotName, "internal"))
601         slot = PK11_GetInternalKeySlot();
602     else
603         slot = PK11_FindSlotByName(slotName);
604     if (!slot) {
605         SECU_PrintError(progName, "can not find requested slot");
606         return SECFailure;
607     }
608 
609     if (PK11_NeedLogin(slot)) {
610         rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
611         if (rv != SECSuccess)
612             goto loser;
613     }
614 
615     rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode);
616     if (rv != SECSuccess) {
617         char *errMsg = NULL;
618         switch (errCode) {
619             case noKeyFound:
620                 errMsg = "No private key found of signing cert";
621                 break;
622 
623             case noSignatureMatch:
624                 errMsg = "Key and Algorithm OId are do not match";
625                 break;
626 
627             default:
628             case failToEncode:
629                 errMsg = "Failed to encode crl structure";
630                 break;
631 
632             case failToSign:
633                 errMsg = "Failed to sign crl structure";
634                 break;
635 
636             case noMem:
637                 errMsg = "Can not allocate memory";
638                 break;
639         }
640         SECU_PrintError(progName, "%s\n", errMsg);
641         goto loser;
642     }
643 
644     if (outFileName) {
645         outFile = PR_Open(outFileName, PR_WRONLY | PR_CREATE_FILE, PR_IRUSR | PR_IWUSR);
646         if (!outFile) {
647             SECU_PrintError(progName, "unable to open \"%s\" for writing\n",
648                             outFileName);
649             goto loser;
650         }
651     }
652 
653     rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url);
654     if (rv != SECSuccess) {
655         SECU_PrintError(progName, "fail to save CRL\n");
656     }
657 
658 loser:
659     if (outFile)
660         PR_Close(outFile);
661     if (slot)
662         PK11_FreeSlot(slot);
663     return rv;
664 }
665 
666 static SECStatus
GenerateCRL(CERTCertDBHandle * certHandle,char * certNickName,PRFileDesc * inCrlInitFile,PRFileDesc * inFile,char * outFileName,int ascii,char * slotName,PRInt32 importOptions,char * alg,PRBool quiet,PRInt32 decodeOptions,char * url,secuPWData * pwdata,int modifyFlag)667 GenerateCRL(CERTCertDBHandle *certHandle, char *certNickName,
668             PRFileDesc *inCrlInitFile, PRFileDesc *inFile,
669             char *outFileName, int ascii, char *slotName,
670             PRInt32 importOptions, char *alg, PRBool quiet,
671             PRInt32 decodeOptions, char *url, secuPWData *pwdata,
672             int modifyFlag)
673 {
674     CERTCertificate *cert = NULL;
675     CERTSignedCrl *signCrl = NULL;
676     PLArenaPool *arena = NULL;
677     SECStatus rv;
678     SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
679 
680     if (alg) {
681         hashAlgTag = SECU_StringToSignatureAlgTag(alg);
682         if (hashAlgTag == SEC_OID_UNKNOWN) {
683             SECU_PrintError(progName, "%s -Z:  %s is not a recognized type.\n",
684                             progName, alg);
685             return SECFailure;
686         }
687     } else {
688         hashAlgTag = SEC_OID_UNKNOWN;
689     }
690 
691     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
692     if (!arena) {
693         SECU_PrintError(progName, "fail to allocate memory\n");
694         return SECFailure;
695     }
696 
697     if (modifyFlag == PR_TRUE) {
698         signCrl = CreateModifiedCRLCopy(arena, certHandle, &cert, certNickName,
699                                         inFile, decodeOptions, importOptions,
700                                         pwdata);
701         if (signCrl == NULL) {
702             rv = SECFailure;
703             goto loser;
704         }
705     }
706 
707     if (!cert) {
708         cert = FindSigningCert(certHandle, signCrl, certNickName);
709         if (cert == NULL) {
710             rv = SECFailure;
711             goto loser;
712         }
713     }
714 
715     if (!signCrl) {
716         if (modifyFlag == PR_TRUE) {
717             if (!outFileName) {
718                 int len = strlen(certNickName) + 5;
719                 outFileName = PORT_ArenaAlloc(arena, len);
720                 PR_snprintf(outFileName, len, "%s.crl", certNickName);
721             }
722             SECU_PrintError(progName, "Will try to generate crl. "
723                                       "It will be saved in file: %s",
724                             outFileName);
725         }
726         signCrl = CreateNewCrl(arena, certHandle, cert);
727         if (!signCrl) {
728             rv = SECFailure;
729             goto loser;
730         }
731     }
732 
733     rv = UpdateCrl(signCrl, inCrlInitFile);
734     if (rv != SECSuccess) {
735         goto loser;
736     }
737 
738     rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii,
739                          slotName, url, pwdata);
740     if (rv != SECSuccess) {
741         goto loser;
742     }
743 
744     if (signCrl && !quiet) {
745         SECU_PrintCRLInfo(stdout, &signCrl->crl, "CRL Info:\n", 0);
746     }
747 
748 loser:
749     if (arena && (!signCrl || !signCrl->arena))
750         PORT_FreeArena(arena, PR_FALSE);
751     if (signCrl)
752         SEC_DestroyCrl(signCrl);
753     if (cert)
754         CERT_DestroyCertificate(cert);
755     return (rv);
756 }
757 
758 static void
Usage()759 Usage()
760 {
761     fprintf(stderr,
762             "Usage:  %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n"
763             "        %s -D -n nickname [-d keydir] [-P dbprefix]\n"
764             "        %s -S -i crl\n"
765             "        %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] "
766             "[-p pwd-file] -w [pwd-string]\n"
767             "        %s -E -t crlType [-d keydir] [-P dbprefix]\n"
768             "        %s -T\n"
769             "        %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] "
770             "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] "
771             "[-a] [-B]\n",
772             progName, progName, progName, progName, progName, progName, progName);
773 
774     fprintf(stderr, "%-15s List CRL\n", "-L");
775     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
776             "-n nickname");
777     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
778             "-d keydir");
779     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
780             "-P dbprefix");
781 
782     fprintf(stderr, "%-15s Delete a CRL from the cert database\n", "-D");
783     fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n",
784             "-n nickname");
785     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
786     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
787             "-d keydir");
788     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
789             "-P dbprefix");
790 
791     fprintf(stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E");
792     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
793     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
794             "-d keydir");
795     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
796             "-P dbprefix");
797 
798     fprintf(stderr, "%-15s Show contents of a CRL file (without database)\n", "-S");
799     fprintf(stderr, "%-20s Specify the file which contains the CRL to show\n",
800             "-i crl");
801 
802     fprintf(stderr, "%-15s Import a CRL to the cert database\n", "-I");
803     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
804             "-i crl");
805     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
806     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
807     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
808             "-d keydir");
809     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
810             "-P dbprefix");
811 #ifdef DEBUG
812     fprintf(stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T");
813 #endif
814     fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " ");
815     fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " ");
816     fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " ");
817     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
818     fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p");
819     fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>");
820     fprintf(stderr, "\n%-15s Create CRL\n", "-G");
821     fprintf(stderr, "%-15s Modify CRL\n", "-M");
822     fprintf(stderr, "%-20s Specify crl initialization file\n",
823             "-c crl-conf-file");
824     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
825             "-n nickname");
826     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
827             "-i crl");
828     fprintf(stderr, "%-20s Specify a CRL output file\n",
829             "-o crl-output-file");
830     fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n",
831             "-a");
832     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
833             "-d keydir");
834     fprintf(stderr, "%-20s Provide path to a default pwd file\n",
835             "-f pwd-file");
836     fprintf(stderr, "%-20s Provide db password in command line\n",
837             "-w pwd-string");
838     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
839             "-P dbprefix");
840     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
841     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
842 
843     exit(-1);
844 }
845 
846 int
main(int argc,char ** argv)847 main(int argc, char **argv)
848 {
849     CERTCertDBHandle *certHandle;
850     PRFileDesc *inFile;
851     PRFileDesc *inCrlInitFile = NULL;
852     int generateCRL;
853     int modifyCRL;
854     int listCRL;
855     int importCRL;
856     int showFileCRL;
857     int deleteCRL;
858     int rv;
859     char *nickName;
860     char *url;
861     char *dbPrefix = PORT_Strdup("");
862     char *alg = NULL;
863     char *outFile = NULL;
864     char *slotName = NULL;
865     int ascii = 0;
866     int crlType;
867     PLOptState *optstate;
868     PLOptStatus status;
869     SECStatus secstatus;
870     PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
871     PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
872     PRBool quiet = PR_FALSE;
873     PRBool test = PR_FALSE;
874     PRBool erase = PR_FALSE;
875     PRInt32 i = 0;
876     PRInt32 iterations = 1;
877     PRBool readonly = PR_FALSE;
878 
879     secuPWData pwdata = { PW_NONE, 0 };
880 
881     progName = strrchr(argv[0], '/');
882     progName = progName ? progName + 1 : argv[0];
883 
884     rv = 0;
885     deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = showFileCRL = 0;
886     inFile = NULL;
887     nickName = url = NULL;
888     certHandle = NULL;
889     crlType = SEC_CRL_TYPE;
890     /*
891      * Parse command line arguments
892      */
893     optstate = PL_CreateOptState(argc, argv, "sqBCDGILMSTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:");
894     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
895         switch (optstate->option) {
896             case '?':
897                 Usage();
898                 break;
899 
900             case 'T':
901                 test = PR_TRUE;
902                 break;
903 
904             case 'E':
905                 erase = PR_TRUE;
906                 break;
907 
908             case 'B':
909                 importOptions |= CRL_IMPORT_BYPASS_CHECKS;
910                 break;
911 
912             case 'G':
913                 generateCRL = 1;
914                 break;
915 
916             case 'M':
917                 modifyCRL = 1;
918                 break;
919 
920             case 'D':
921                 deleteCRL = 1;
922                 break;
923 
924             case 'I':
925                 importCRL = 1;
926                 break;
927 
928             case 'S':
929                 showFileCRL = 1;
930                 break;
931 
932             case 'C':
933             case 'L':
934                 listCRL = 1;
935                 break;
936 
937             case 'P':
938                 PORT_Free(dbPrefix);
939                 dbPrefix = PORT_Strdup(optstate->value);
940                 break;
941 
942             case 'Z':
943                 alg = PORT_Strdup(optstate->value);
944                 break;
945 
946             case 'a':
947                 ascii = 1;
948                 break;
949 
950             case 'c':
951                 inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
952                 if (!inCrlInitFile) {
953                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
954                                progName, optstate->value);
955                     rv = SECFailure;
956                     goto loser;
957                 }
958                 break;
959 
960             case 'd':
961                 SECU_ConfigDirectory(optstate->value);
962                 break;
963 
964             case 'f':
965                 pwdata.source = PW_FROMFILE;
966                 pwdata.data = PORT_Strdup(optstate->value);
967                 break;
968 
969             case 'h':
970                 slotName = PORT_Strdup(optstate->value);
971                 break;
972 
973             case 'i':
974                 inFile = PR_Open(optstate->value, PR_RDONLY, 0);
975                 if (!inFile) {
976                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
977                                progName, optstate->value);
978                     rv = SECFailure;
979                     goto loser;
980                 }
981                 break;
982 
983             case 'n':
984                 nickName = PORT_Strdup(optstate->value);
985                 break;
986 
987             case 'o':
988                 outFile = PORT_Strdup(optstate->value);
989                 break;
990 
991             case 'p':
992                 decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
993                 break;
994 
995             case 'r': {
996                 const char *str = optstate->value;
997                 if (str && atoi(str) > 0)
998                     iterations = atoi(str);
999             } break;
1000 
1001             case 't': {
1002                 crlType = atoi(optstate->value);
1003                 if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
1004                     PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
1005                     rv = SECFailure;
1006                     goto loser;
1007                 }
1008                 break;
1009 
1010                 case 'q':
1011                     quiet = PR_TRUE;
1012                     break;
1013 
1014                 case 'w':
1015                     pwdata.source = PW_PLAINTEXT;
1016                     pwdata.data = PORT_Strdup(optstate->value);
1017                     break;
1018 
1019                 case 'u':
1020                     url = PORT_Strdup(optstate->value);
1021                     break;
1022             }
1023         }
1024     }
1025 
1026     if (deleteCRL && !nickName)
1027         Usage();
1028     if (importCRL && !inFile)
1029         Usage();
1030     if (showFileCRL && !inFile)
1031         Usage();
1032     if ((generateCRL && !nickName) ||
1033         (modifyCRL && !inFile && !nickName))
1034         Usage();
1035     if (!(listCRL || deleteCRL || importCRL || showFileCRL || generateCRL ||
1036           modifyCRL || test || erase))
1037         Usage();
1038 
1039     if (listCRL || showFileCRL) {
1040         readonly = PR_TRUE;
1041     }
1042 
1043     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
1044 
1045     PK11_SetPasswordFunc(SECU_GetModulePassword);
1046 
1047     if (showFileCRL) {
1048         NSS_NoDB_Init(NULL);
1049     } else {
1050         secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
1051                                    "secmod.db", readonly ? NSS_INIT_READONLY : 0);
1052         if (secstatus != SECSuccess) {
1053             SECU_PrintPRandOSError(progName);
1054             rv = SECFailure;
1055             goto loser;
1056         }
1057     }
1058 
1059     SECU_RegisterDynamicOids();
1060 
1061     certHandle = CERT_GetDefaultCertDB();
1062     if (certHandle == NULL) {
1063         SECU_PrintError(progName, "unable to open the cert db");
1064         rv = SECFailure;
1065         goto loser;
1066     }
1067 
1068     CRLGEN_InitCrlGenParserLock();
1069 
1070     for (i = 0; i < iterations; i++) {
1071         /* Read in the private key info */
1072         if (deleteCRL)
1073             DeleteCRL(certHandle, nickName, crlType);
1074         else if (listCRL) {
1075             rv = ListCRL(certHandle, nickName, crlType);
1076         } else if (importCRL) {
1077             rv = ImportCRL(certHandle, url, crlType, inFile, importOptions,
1078                            decodeOptions, &pwdata);
1079         } else if (showFileCRL) {
1080             rv = DumpCRL(inFile);
1081         } else if (generateCRL || modifyCRL) {
1082             if (!inCrlInitFile)
1083                 inCrlInitFile = PR_STDIN;
1084             rv = GenerateCRL(certHandle, nickName, inCrlInitFile,
1085                              inFile, outFile, ascii, slotName,
1086                              importOptions, alg, quiet,
1087                              decodeOptions, url, &pwdata,
1088                              modifyCRL);
1089         } else if (erase) {
1090             /* list and delete all CRLs */
1091             ListCRLNames(certHandle, crlType, PR_TRUE);
1092         }
1093 #ifdef DEBUG
1094         else if (test) {
1095             /* list and delete all CRLs */
1096             ListCRLNames(certHandle, crlType, PR_TRUE);
1097             /* list CRLs */
1098             ListCRLNames(certHandle, crlType, PR_FALSE);
1099             /* import CRL as a blob */
1100             rv = ImportCRL(certHandle, url, crlType, inFile, importOptions,
1101                            decodeOptions, &pwdata);
1102             /* list CRLs */
1103             ListCRLNames(certHandle, crlType, PR_FALSE);
1104         }
1105 #endif
1106     }
1107 
1108     CRLGEN_DestroyCrlGenParserLock();
1109 
1110 loser:
1111     PL_DestroyOptState(optstate);
1112 
1113     if (inFile) {
1114         PR_Close(inFile);
1115     }
1116     if (alg) {
1117         PORT_Free(alg);
1118     }
1119     if (slotName) {
1120         PORT_Free(slotName);
1121     }
1122     if (nickName) {
1123         PORT_Free(nickName);
1124     }
1125     if (outFile) {
1126         PORT_Free(outFile);
1127     }
1128     if (url) {
1129         PORT_Free(url);
1130     }
1131     if (pwdata.data) {
1132         PORT_Free(pwdata.data);
1133     }
1134 
1135     PORT_Free(dbPrefix);
1136 
1137     if (NSS_Shutdown() != SECSuccess) {
1138         rv = SECFailure;
1139     }
1140 
1141     return (rv != SECSuccess);
1142 }
1143