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             goto loser;
390         }
391 
392         decodeOptions |= CRL_DECODE_DONT_COPY_DER;
393 
394         modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE,
395                                             decodeOptions);
396         if (!modCrl) {
397             SECU_PrintError(progName, "fail to decode CRL");
398             goto loser;
399         }
400 
401         if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)) {
402             /* If caCert is a v2 certificate, make sure that it
403              * can be used for crl signing purpose */
404             *cert = FindSigningCert(certHandle, modCrl, NULL);
405             if (!*cert) {
406                 goto loser;
407             }
408 
409             rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert,
410                                        PR_Now(), pwdata);
411             if (rv != SECSuccess) {
412                 SECU_PrintError(progName, "fail to verify signed data\n");
413                 goto loser;
414             }
415         }
416     } else {
417         modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE);
418         if (!modCrl) {
419             SECU_PrintError(progName, "fail to find crl %s in database\n",
420                             certNickName);
421             goto loser;
422         }
423     }
424 
425     signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
426     if (signCrl == NULL) {
427         SECU_PrintError(progName, "fail to allocate memory\n");
428         goto loser;
429     }
430 
431     rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl);
432     if (rv != SECSuccess) {
433         SECU_PrintError(progName, "unable to dublicate crl for "
434                                   "modification.");
435         goto loser;
436     }
437 
438     /* Make sure the update time is current. It can be modified later
439      * by "update <time>" command from crl generation script */
440     rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
441     if (rv != SECSuccess) {
442         SECU_PrintError(progName, "fail to encode current time\n");
443         goto loser;
444     }
445 
446     signCrl->arena = arena;
447     signCrl->referenceCount = 1;
448 
449 loser:
450     if (crlDER.data) {
451         SECITEM_FreeItem(&crlDER, PR_FALSE);
452     }
453     if (modArena && (!modCrl || modCrl->arena != modArena)) {
454         PORT_FreeArena(modArena, PR_FALSE);
455     }
456     if (modCrl)
457         SEC_DestroyCrl(modCrl);
458     if (rv != SECSuccess && signCrl) {
459         SEC_DestroyCrl(signCrl);
460         signCrl = NULL;
461     }
462     return signCrl;
463 }
464 
465 static CERTSignedCrl *
CreateNewCrl(PLArenaPool * arena,CERTCertDBHandle * certHandle,CERTCertificate * cert)466 CreateNewCrl(PLArenaPool *arena, CERTCertDBHandle *certHandle,
467              CERTCertificate *cert)
468 {
469     CERTSignedCrl *signCrl = NULL;
470     void *dummy = NULL;
471     SECStatus rv;
472     void *mark = NULL;
473 
474     /* if the CERTSignedCrl structure changes, this function will need to be
475        updated as well */
476     if (!cert || !arena) {
477         PORT_SetError(SEC_ERROR_INVALID_ARGS);
478         SECU_PrintError(progName, "invalid args for function "
479                                   "CreateNewCrl\n");
480         return NULL;
481     }
482 
483     mark = PORT_ArenaMark(arena);
484 
485     signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
486     if (signCrl == NULL) {
487         SECU_PrintError(progName, "fail to allocate memory\n");
488         return NULL;
489     }
490 
491     dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version,
492                                   SEC_CRL_VERSION_2);
493     /* set crl->version */
494     if (!dummy) {
495         SECU_PrintError(progName, "fail to create crl version data "
496                                   "container\n");
497         goto loser;
498     }
499 
500     /* copy SECItem name from cert */
501     rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject);
502     if (rv != SECSuccess) {
503         SECU_PrintError(progName, "fail to duplicate der name from "
504                                   "certificate.\n");
505         goto loser;
506     }
507 
508     /* copy CERTName name structure from cert issuer */
509     rv = CERT_CopyName(arena, &signCrl->crl.name, &cert->subject);
510     if (rv != SECSuccess) {
511         SECU_PrintError(progName, "fail to duplicate RD name from "
512                                   "certificate.\n");
513         goto loser;
514     }
515 
516     rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
517     if (rv != SECSuccess) {
518         SECU_PrintError(progName, "fail to encode current time\n");
519         goto loser;
520     }
521 
522     /* set fields */
523     signCrl->arena = arena;
524     signCrl->dbhandle = certHandle;
525     signCrl->crl.arena = arena;
526 
527     PORT_ArenaUnmark(arena, mark);
528 
529     return signCrl;
530 
531 loser:
532     PORT_ArenaRelease(arena, mark);
533     return NULL;
534 }
535 
536 static SECStatus
UpdateCrl(CERTSignedCrl * signCrl,PRFileDesc * inCrlInitFile)537 UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile)
538 {
539     CRLGENGeneratorData *crlGenData = NULL;
540     SECStatus rv;
541 
542     if (!signCrl || !inCrlInitFile) {
543         PORT_SetError(SEC_ERROR_INVALID_ARGS);
544         SECU_PrintError(progName, "invalid args for function "
545                                   "CreateNewCrl\n");
546         return SECFailure;
547     }
548 
549     crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile);
550     if (!crlGenData) {
551         SECU_PrintError(progName, "can not initialize parser structure.\n");
552         return SECFailure;
553     }
554 
555     rv = CRLGEN_ExtHandleInit(crlGenData);
556     if (rv == SECFailure) {
557         SECU_PrintError(progName, "can not initialize entries handle.\n");
558         goto loser;
559     }
560 
561     rv = CRLGEN_StartCrlGen(crlGenData);
562     if (rv != SECSuccess) {
563         SECU_PrintError(progName, "crl generation failed");
564         goto loser;
565     }
566 
567 loser:
568     /* CommitExtensionsAndEntries is partially responsible for freeing
569      * up memory that was used for CRL generation. Should be called regardless
570      * of previouse call status, but only after initialization of
571      * crlGenData was done. It will commit all changes that was done before
572      * an error has occurred.
573      */
574     if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) {
575         SECU_PrintError(progName, "crl generation failed");
576         rv = SECFailure;
577     }
578     CRLGEN_FinalizeCrlGeneration(crlGenData);
579     return rv;
580 }
581 
582 static SECStatus
SignAndStoreCrl(CERTSignedCrl * signCrl,CERTCertificate * cert,char * outFileName,SECOidTag hashAlgTag,int ascii,char * slotName,char * url,secuPWData * pwdata)583 SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert,
584                 char *outFileName, SECOidTag hashAlgTag, int ascii,
585                 char *slotName, char *url, secuPWData *pwdata)
586 {
587     PK11SlotInfo *slot = NULL;
588     PRFileDesc *outFile = NULL;
589     SECStatus rv;
590     SignAndEncodeFuncExitStat errCode;
591 
592     PORT_Assert(signCrl && (!ascii || outFileName));
593     if (!signCrl || (ascii && !outFileName)) {
594         SECU_PrintError(progName, "invalid args for function "
595                                   "SignAndStoreCrl\n");
596         return SECFailure;
597     }
598 
599     if (!slotName || !PL_strcmp(slotName, "internal"))
600         slot = PK11_GetInternalKeySlot();
601     else
602         slot = PK11_FindSlotByName(slotName);
603     if (!slot) {
604         SECU_PrintError(progName, "can not find requested slot");
605         return SECFailure;
606     }
607 
608     if (PK11_NeedLogin(slot)) {
609         rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
610         if (rv != SECSuccess)
611             goto loser;
612     }
613 
614     rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode);
615     if (rv != SECSuccess) {
616         char *errMsg = NULL;
617         switch (errCode) {
618             case noKeyFound:
619                 errMsg = "No private key found of signing cert";
620                 break;
621 
622             case noSignatureMatch:
623                 errMsg = "Key and Algorithm OId are do not match";
624                 break;
625 
626             default:
627             case failToEncode:
628                 errMsg = "Failed to encode crl structure";
629                 break;
630 
631             case failToSign:
632                 errMsg = "Failed to sign crl structure";
633                 break;
634 
635             case noMem:
636                 errMsg = "Can not allocate memory";
637                 break;
638         }
639         SECU_PrintError(progName, "%s\n", errMsg);
640         goto loser;
641     }
642 
643     if (outFileName) {
644         outFile = PR_Open(outFileName, PR_WRONLY | PR_CREATE_FILE, PR_IRUSR | PR_IWUSR);
645         if (!outFile) {
646             SECU_PrintError(progName, "unable to open \"%s\" for writing\n",
647                             outFileName);
648             goto loser;
649         }
650     }
651 
652     rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url);
653     if (rv != SECSuccess) {
654         SECU_PrintError(progName, "fail to save CRL\n");
655     }
656 
657 loser:
658     if (outFile)
659         PR_Close(outFile);
660     if (slot)
661         PK11_FreeSlot(slot);
662     return rv;
663 }
664 
665 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)666 GenerateCRL(CERTCertDBHandle *certHandle, char *certNickName,
667             PRFileDesc *inCrlInitFile, PRFileDesc *inFile,
668             char *outFileName, int ascii, char *slotName,
669             PRInt32 importOptions, char *alg, PRBool quiet,
670             PRInt32 decodeOptions, char *url, secuPWData *pwdata,
671             int modifyFlag)
672 {
673     CERTCertificate *cert = NULL;
674     CERTSignedCrl *signCrl = NULL;
675     PLArenaPool *arena = NULL;
676     SECStatus rv;
677     SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
678 
679     if (alg) {
680         hashAlgTag = SECU_StringToSignatureAlgTag(alg);
681         if (hashAlgTag == SEC_OID_UNKNOWN) {
682             SECU_PrintError(progName, "%s -Z:  %s is not a recognized type.\n",
683                             progName, alg);
684             return SECFailure;
685         }
686     } else {
687         hashAlgTag = SEC_OID_UNKNOWN;
688     }
689 
690     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
691     if (!arena) {
692         SECU_PrintError(progName, "fail to allocate memory\n");
693         return SECFailure;
694     }
695 
696     if (modifyFlag == PR_TRUE) {
697         signCrl = CreateModifiedCRLCopy(arena, certHandle, &cert, certNickName,
698                                         inFile, decodeOptions, importOptions,
699                                         pwdata);
700         if (signCrl == NULL) {
701             rv = SECFailure;
702             goto loser;
703         }
704     }
705 
706     if (!cert) {
707         cert = FindSigningCert(certHandle, signCrl, certNickName);
708         if (cert == NULL) {
709             rv = SECFailure;
710             goto loser;
711         }
712     }
713 
714     if (!signCrl) {
715         if (modifyFlag == PR_TRUE) {
716             if (!outFileName) {
717                 int len = strlen(certNickName) + 5;
718                 outFileName = PORT_ArenaAlloc(arena, len);
719                 PR_snprintf(outFileName, len, "%s.crl", certNickName);
720             }
721             SECU_PrintError(progName, "Will try to generate crl. "
722                                       "It will be saved in file: %s",
723                             outFileName);
724         }
725         signCrl = CreateNewCrl(arena, certHandle, cert);
726         if (!signCrl) {
727             rv = SECFailure;
728             goto loser;
729         }
730     }
731 
732     rv = UpdateCrl(signCrl, inCrlInitFile);
733     if (rv != SECSuccess) {
734         goto loser;
735     }
736 
737     rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii,
738                          slotName, url, pwdata);
739     if (rv != SECSuccess) {
740         goto loser;
741     }
742 
743     if (signCrl && !quiet) {
744         SECU_PrintCRLInfo(stdout, &signCrl->crl, "CRL Info:\n", 0);
745     }
746 
747 loser:
748     if (arena && (!signCrl || !signCrl->arena))
749         PORT_FreeArena(arena, PR_FALSE);
750     if (signCrl)
751         SEC_DestroyCrl(signCrl);
752     if (cert)
753         CERT_DestroyCertificate(cert);
754     return (rv);
755 }
756 
757 static void
Usage()758 Usage()
759 {
760     fprintf(stderr,
761             "Usage:  %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n"
762             "        %s -D -n nickname [-d keydir] [-P dbprefix]\n"
763             "        %s -S -i crl\n"
764             "        %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] "
765             "[-p pwd-file] -w [pwd-string]\n"
766             "        %s -E -t crlType [-d keydir] [-P dbprefix]\n"
767             "        %s -T\n"
768             "        %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] "
769             "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] "
770             "[-a] [-B]\n",
771             progName, progName, progName, progName, progName, progName, progName);
772 
773     fprintf(stderr, "%-15s List CRL\n", "-L");
774     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
775             "-n nickname");
776     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
777             "-d keydir");
778     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
779             "-P dbprefix");
780 
781     fprintf(stderr, "%-15s Delete a CRL from the cert database\n", "-D");
782     fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n",
783             "-n nickname");
784     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
785     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
786             "-d keydir");
787     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
788             "-P dbprefix");
789 
790     fprintf(stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E");
791     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
792     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
793             "-d keydir");
794     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
795             "-P dbprefix");
796 
797     fprintf(stderr, "%-15s Show contents of a CRL file (without database)\n", "-S");
798     fprintf(stderr, "%-20s Specify the file which contains the CRL to show\n",
799             "-i crl");
800 
801     fprintf(stderr, "%-15s Import a CRL to the cert database\n", "-I");
802     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
803             "-i crl");
804     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
805     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
806     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
807             "-d keydir");
808     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
809             "-P dbprefix");
810 #ifdef DEBUG
811     fprintf(stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T");
812 #endif
813     fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " ");
814     fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " ");
815     fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " ");
816     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
817     fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p");
818     fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>");
819     fprintf(stderr, "\n%-15s Create CRL\n", "-G");
820     fprintf(stderr, "%-15s Modify CRL\n", "-M");
821     fprintf(stderr, "%-20s Specify crl initialization file\n",
822             "-c crl-conf-file");
823     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
824             "-n nickname");
825     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
826             "-i crl");
827     fprintf(stderr, "%-20s Specify a CRL output file\n",
828             "-o crl-output-file");
829     fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n",
830             "-a");
831     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
832             "-d keydir");
833     fprintf(stderr, "%-20s Provide path to a default pwd file\n",
834             "-f pwd-file");
835     fprintf(stderr, "%-20s Provide db password in command line\n",
836             "-w pwd-string");
837     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
838             "-P dbprefix");
839     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
840     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
841 
842     exit(-1);
843 }
844 
845 int
main(int argc,char ** argv)846 main(int argc, char **argv)
847 {
848     CERTCertDBHandle *certHandle;
849     PRFileDesc *inFile;
850     PRFileDesc *inCrlInitFile = NULL;
851     int generateCRL;
852     int modifyCRL;
853     int listCRL;
854     int importCRL;
855     int showFileCRL;
856     int deleteCRL;
857     int rv;
858     char *nickName;
859     char *url;
860     char *dbPrefix = PORT_Strdup("");
861     char *alg = NULL;
862     char *outFile = NULL;
863     char *slotName = NULL;
864     int ascii = 0;
865     int crlType;
866     PLOptState *optstate;
867     PLOptStatus status;
868     SECStatus secstatus;
869     PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
870     PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
871     PRBool quiet = PR_FALSE;
872     PRBool test = PR_FALSE;
873     PRBool erase = PR_FALSE;
874     PRInt32 i = 0;
875     PRInt32 iterations = 1;
876     PRBool readonly = PR_FALSE;
877 
878     secuPWData pwdata = { PW_NONE, 0 };
879 
880     progName = strrchr(argv[0], '/');
881     progName = progName ? progName + 1 : argv[0];
882 
883     rv = 0;
884     deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = showFileCRL = 0;
885     inFile = NULL;
886     nickName = url = NULL;
887     certHandle = NULL;
888     crlType = SEC_CRL_TYPE;
889     /*
890      * Parse command line arguments
891      */
892     optstate = PL_CreateOptState(argc, argv, "sqBCDGILMSTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:");
893     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
894         switch (optstate->option) {
895             case '?':
896                 Usage();
897                 break;
898 
899             case 'T':
900                 test = PR_TRUE;
901                 break;
902 
903             case 'E':
904                 erase = PR_TRUE;
905                 break;
906 
907             case 'B':
908                 importOptions |= CRL_IMPORT_BYPASS_CHECKS;
909                 break;
910 
911             case 'G':
912                 generateCRL = 1;
913                 break;
914 
915             case 'M':
916                 modifyCRL = 1;
917                 break;
918 
919             case 'D':
920                 deleteCRL = 1;
921                 break;
922 
923             case 'I':
924                 importCRL = 1;
925                 break;
926 
927             case 'S':
928                 showFileCRL = 1;
929                 break;
930 
931             case 'C':
932             case 'L':
933                 listCRL = 1;
934                 break;
935 
936             case 'P':
937                 PORT_Free(dbPrefix);
938                 dbPrefix = PORT_Strdup(optstate->value);
939                 break;
940 
941             case 'Z':
942                 alg = PORT_Strdup(optstate->value);
943                 break;
944 
945             case 'a':
946                 ascii = 1;
947                 break;
948 
949             case 'c':
950                 inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
951                 if (!inCrlInitFile) {
952                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
953                                progName, optstate->value);
954                     rv = SECFailure;
955                     goto loser;
956                 }
957                 break;
958 
959             case 'd':
960                 SECU_ConfigDirectory(optstate->value);
961                 break;
962 
963             case 'f':
964                 pwdata.source = PW_FROMFILE;
965                 pwdata.data = PORT_Strdup(optstate->value);
966                 break;
967 
968             case 'h':
969                 slotName = PORT_Strdup(optstate->value);
970                 break;
971 
972             case 'i':
973                 inFile = PR_Open(optstate->value, PR_RDONLY, 0);
974                 if (!inFile) {
975                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
976                                progName, optstate->value);
977                     rv = SECFailure;
978                     goto loser;
979                 }
980                 break;
981 
982             case 'n':
983                 nickName = PORT_Strdup(optstate->value);
984                 break;
985 
986             case 'o':
987                 outFile = PORT_Strdup(optstate->value);
988                 break;
989 
990             case 'p':
991                 decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
992                 break;
993 
994             case 'r': {
995                 const char *str = optstate->value;
996                 if (str && atoi(str) > 0)
997                     iterations = atoi(str);
998             } break;
999 
1000             case 't': {
1001                 crlType = atoi(optstate->value);
1002                 if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
1003                     PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
1004                     rv = SECFailure;
1005                     goto loser;
1006                 }
1007                 break;
1008 
1009                 case 'q':
1010                     quiet = PR_TRUE;
1011                     break;
1012 
1013                 case 'w':
1014                     pwdata.source = PW_PLAINTEXT;
1015                     pwdata.data = PORT_Strdup(optstate->value);
1016                     break;
1017 
1018                 case 'u':
1019                     url = PORT_Strdup(optstate->value);
1020                     break;
1021             }
1022         }
1023     }
1024 
1025     if (deleteCRL && !nickName)
1026         Usage();
1027     if (importCRL && !inFile)
1028         Usage();
1029     if (showFileCRL && !inFile)
1030         Usage();
1031     if ((generateCRL && !nickName) ||
1032         (modifyCRL && !inFile && !nickName))
1033         Usage();
1034     if (!(listCRL || deleteCRL || importCRL || showFileCRL || generateCRL ||
1035           modifyCRL || test || erase))
1036         Usage();
1037 
1038     if (listCRL || showFileCRL) {
1039         readonly = PR_TRUE;
1040     }
1041 
1042     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
1043 
1044     PK11_SetPasswordFunc(SECU_GetModulePassword);
1045 
1046     if (showFileCRL) {
1047         rv = NSS_NoDB_Init(NULL);
1048         if (rv != SECSuccess) {
1049             goto loser;
1050         }
1051     } else {
1052         secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
1053                                    "secmod.db", readonly ? NSS_INIT_READONLY : 0);
1054         if (secstatus != SECSuccess) {
1055             SECU_PrintPRandOSError(progName);
1056             rv = SECFailure;
1057             goto loser;
1058         }
1059     }
1060 
1061     SECU_RegisterDynamicOids();
1062 
1063     certHandle = CERT_GetDefaultCertDB();
1064     if (certHandle == NULL) {
1065         SECU_PrintError(progName, "unable to open the cert db");
1066         rv = SECFailure;
1067         goto loser;
1068     }
1069 
1070     CRLGEN_InitCrlGenParserLock();
1071 
1072     for (i = 0; i < iterations; i++) {
1073         /* Read in the private key info */
1074         if (deleteCRL)
1075             DeleteCRL(certHandle, nickName, crlType);
1076         else if (listCRL) {
1077             rv = ListCRL(certHandle, nickName, crlType);
1078         } else if (importCRL) {
1079             rv = ImportCRL(certHandle, url, crlType, inFile, importOptions,
1080                            decodeOptions, &pwdata);
1081         } else if (showFileCRL) {
1082             rv = DumpCRL(inFile);
1083         } else if (generateCRL || modifyCRL) {
1084             if (!inCrlInitFile)
1085                 inCrlInitFile = PR_STDIN;
1086             rv = GenerateCRL(certHandle, nickName, inCrlInitFile,
1087                              inFile, outFile, ascii, slotName,
1088                              importOptions, alg, quiet,
1089                              decodeOptions, url, &pwdata,
1090                              modifyCRL);
1091         } else if (erase) {
1092             /* list and delete all CRLs */
1093             ListCRLNames(certHandle, crlType, PR_TRUE);
1094         }
1095 #ifdef DEBUG
1096         else if (test) {
1097             /* list and delete all CRLs */
1098             ListCRLNames(certHandle, crlType, PR_TRUE);
1099             /* list CRLs */
1100             ListCRLNames(certHandle, crlType, PR_FALSE);
1101             /* import CRL as a blob */
1102             rv = ImportCRL(certHandle, url, crlType, inFile, importOptions,
1103                            decodeOptions, &pwdata);
1104             /* list CRLs */
1105             ListCRLNames(certHandle, crlType, PR_FALSE);
1106         }
1107 #endif
1108     }
1109 
1110     CRLGEN_DestroyCrlGenParserLock();
1111 
1112 loser:
1113     PL_DestroyOptState(optstate);
1114 
1115     if (inFile) {
1116         PR_Close(inFile);
1117     }
1118     if (alg) {
1119         PORT_Free(alg);
1120     }
1121     if (slotName) {
1122         PORT_Free(slotName);
1123     }
1124     if (nickName) {
1125         PORT_Free(nickName);
1126     }
1127     if (outFile) {
1128         PORT_Free(outFile);
1129     }
1130     if (url) {
1131         PORT_Free(url);
1132     }
1133     if (pwdata.data) {
1134         PORT_Free(pwdata.data);
1135     }
1136 
1137     PORT_Free(dbPrefix);
1138 
1139     if (NSS_Shutdown() != SECSuccess) {
1140         rv = SECFailure;
1141     }
1142 
1143     return (rv != SECSuccess);
1144 }
1145