Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
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/. */
5 /*
6 ** certutil.c
7 **
8 ** utility for managing certificates and the cert database
9 **
10 */
11 /* test only */
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"
23 #define SEC_CERT_DB_EXISTS 0
24 #define SEC_CREATE_CERT_DB 1
26 static char *progName;
28 static CERTSignedCrl *FindCRL
29 (CERTCertDBHandle *certHandle, char *name, int type)
30 {
31 CERTSignedCrl *crl = NULL;
32 CERTCertificate *cert = NULL;
33 SECItem derName;
35 derName.data = NULL;
36 derName.len = 0;
38 cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name);
39 if (!cert) {
40 CERTName *certName = NULL;
41 PLArenaPool *arena = NULL;
43 certName = CERT_AsciiToName(name);
44 if (certName) {
45 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
46 if (arena) {
47 SECItem *nameItem =
48 SEC_ASN1EncodeItem (arena, NULL, (void *)certName,
49 SEC_ASN1_GET(CERT_NameTemplate));
50 if (nameItem) {
51 SECITEM_CopyItem(NULL, &derName, nameItem);
52 }
53 PORT_FreeArena(arena, PR_FALSE);
54 }
55 CERT_DestroyName(certName);
56 }
58 if (!derName.len || !derName.data) {
59 SECU_PrintError(progName, "could not find certificate named '%s'", name);
60 return ((CERTSignedCrl *)NULL);
61 }
62 } else {
63 SECITEM_CopyItem(NULL, &derName, &cert->derSubject);
64 CERT_DestroyCertificate (cert);
65 }
67 crl = SEC_FindCrlByName(certHandle, &derName, type);
68 if (crl ==NULL)
69 SECU_PrintError
70 (progName, "could not find %s's CRL", name);
71 if (derName.data) {
72 SECITEM_FreeItem(&derName, PR_FALSE);
73 }
74 return (crl);
75 }
77 static SECStatus DisplayCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType)
78 {
79 CERTSignedCrl *crl = NULL;
81 crl = FindCRL (certHandle, nickName, crlType);
83 if (crl) {
84 SECU_PrintCRLInfo (stdout, &crl->crl, "CRL Info:\n", 0);
85 SEC_DestroyCrl (crl);
86 return SECSuccess;
87 }
88 return SECFailure;
89 }
91 static void ListCRLNames (CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls)
92 {
93 CERTCrlHeadNode *crlList = NULL;
94 CERTCrlNode *crlNode = NULL;
95 CERTName *name = NULL;
96 PLArenaPool *arena = NULL;
97 SECStatus rv;
99 do {
100 arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
101 if (arena == NULL) {
102 fprintf(stderr, "%s: fail to allocate memory\n", progName);
103 break;
104 }
106 name = PORT_ArenaZAlloc (arena, sizeof(*name));
107 if (name == NULL) {
108 fprintf(stderr, "%s: fail to allocate memory\n", progName);
109 break;
110 }
111 name->arena = arena;
113 rv = SEC_LookupCrls (certHandle, &crlList, crlType);
114 if (rv != SECSuccess) {
115 fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName,
116 SECU_Strerror(PORT_GetError()));
117 break;
118 }
120 /* just in case */
121 if (!crlList)
122 break;
124 crlNode = crlList->first;
126 fprintf (stdout, "\n");
127 fprintf (stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type");
128 while (crlNode) {
129 char* asciiname = NULL;
130 CERTCertificate *cert = NULL;
131 if (crlNode->crl && &crlNode->crl->crl.derName) {
132 cert = CERT_FindCertByName(certHandle,
133 &crlNode->crl->crl.derName);
134 if (!cert) {
135 SECU_PrintError(progName, "could not find signing "
136 "certificate in database");
137 }
138 }
139 if (cert) {
140 char* certName = NULL;
141 if (cert->nickname && PORT_Strlen(cert->nickname) > 0) {
142 certName = cert->nickname;
143 } else if (cert->emailAddr && PORT_Strlen(cert->emailAddr) > 0) {
144 certName = cert->emailAddr;
145 }
146 if (certName) {
147 asciiname = PORT_Strdup(certName);
148 }
149 CERT_DestroyCertificate(cert);
150 }
152 if (!asciiname) {
153 name = &crlNode->crl->crl.name;
154 if (!name){
155 SECU_PrintError(progName, "fail to get the CRL "
156 "issuer name");
157 continue;
158 }
159 asciiname = CERT_NameToAscii(name);
160 }
161 fprintf (stdout, "%-40s %-5s\n", asciiname, "CRL");
162 if (asciiname) {
163 PORT_Free(asciiname);
164 }
165 if ( PR_TRUE == deletecrls) {
166 CERTSignedCrl* acrl = NULL;
167 SECItem* issuer = &crlNode->crl->crl.derName;
168 acrl = SEC_FindCrlByName(certHandle, issuer, crlType);
169 if (acrl)
170 {
171 SEC_DeletePermCRL(acrl);
172 SEC_DestroyCrl(acrl);
173 }
174 }
175 crlNode = crlNode->next;
176 }
178 } while (0);
179 if (crlList)
180 PORT_FreeArena (crlList->arena, PR_FALSE);
181 PORT_FreeArena (arena, PR_FALSE);
182 }
184 static SECStatus ListCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType)
185 {
186 if (nickName == NULL) {
187 ListCRLNames (certHandle, crlType, PR_FALSE);
188 return SECSuccess;
189 }
191 return DisplayCRL (certHandle, nickName, crlType);
192 }
196 static SECStatus DeleteCRL (CERTCertDBHandle *certHandle, char *name, int type)
197 {
198 CERTSignedCrl *crl = NULL;
199 SECStatus rv = SECFailure;
201 crl = FindCRL (certHandle, name, type);
202 if (!crl) {
203 SECU_PrintError
204 (progName, "could not find the issuer %s's CRL", name);
205 return SECFailure;
206 }
207 rv = SEC_DeletePermCRL (crl);
208 SEC_DestroyCrl(crl);
209 if (rv != SECSuccess) {
210 SECU_PrintError(progName, "fail to delete the issuer %s's CRL "
211 "from the perm database (reason: %s)",
212 name, SECU_Strerror(PORT_GetError()));
213 return SECFailure;
214 }
215 return (rv);
216 }
218 SECStatus ImportCRL (CERTCertDBHandle *certHandle, char *url, int type,
219 PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions,
220 secuPWData *pwdata)
221 {
222 CERTSignedCrl *crl = NULL;
223 SECItem crlDER;
224 PK11SlotInfo* slot = NULL;
225 int rv;
226 #if defined(DEBUG_jp96085)
227 PRIntervalTime starttime, endtime, elapsed;
228 PRUint32 mins, secs, msecs;
229 #endif
231 crlDER.data = NULL;
234 /* Read in the entire file specified with the -f argument */
235 rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
236 if (rv != SECSuccess) {
237 SECU_PrintError(progName, "unable to read input file");
238 return (SECFailure);
239 }
241 decodeOptions |= CRL_DECODE_DONT_COPY_DER;
243 slot = PK11_GetInternalKeySlot();
245 if (PK11_NeedLogin(slot)) {
246 rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
247 if (rv != SECSuccess)
248 goto loser;
249 }
251 #if defined(DEBUG_jp96085)
252 starttime = PR_IntervalNow();
253 #endif
254 crl = PK11_ImportCRL(slot, &crlDER, url, type,
255 NULL, importOptions, NULL, decodeOptions);
256 #if defined(DEBUG_jp96085)
257 endtime = PR_IntervalNow();
258 elapsed = endtime - starttime;
259 mins = PR_IntervalToSeconds(elapsed) / 60;
260 secs = PR_IntervalToSeconds(elapsed) % 60;
261 msecs = PR_IntervalToMilliseconds(elapsed) % 1000;
262 printf("Elapsed : %2d:%2d.%3d\n", mins, secs, msecs);
263 #endif
264 if (!crl) {
265 const char *errString;
267 rv = SECFailure;
268 errString = SECU_Strerror(PORT_GetError());
269 if ( errString && PORT_Strlen (errString) == 0)
270 SECU_PrintError (progName,
271 "CRL is not imported (error: input CRL is not up to date.)");
272 else
273 SECU_PrintError (progName, "unable to import CRL");
274 } else {
275 SEC_DestroyCrl (crl);
276 }
277 loser:
278 if (slot) {
279 PK11_FreeSlot(slot);
280 }
281 return (rv);
282 }
284 SECStatus DumpCRL(PRFileDesc *inFile)
285 {
286 int rv;
287 PLArenaPool *arena = NULL;
288 CERTSignedCrl *newCrl = NULL;
290 SECItem crlDER;
291 crlDER.data = NULL;
293 /* Read in the entire file specified with the -f argument */
294 rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
295 if (rv != SECSuccess) {
296 SECU_PrintError(progName, "unable to read input file");
297 return (SECFailure);
298 }
300 rv = SEC_ERROR_NO_MEMORY;
301 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
302 if (!arena)
303 return rv;
305 newCrl = CERT_DecodeDERCrlWithFlags(arena, &crlDER, SEC_CRL_TYPE,
306 CRL_DECODE_DEFAULT_OPTIONS);
307 if (!newCrl)
308 return SECFailure;
310 SECU_PrintCRLInfo (stdout, &newCrl->crl, "CRL file contents", 0);
312 PORT_FreeArena (arena, PR_FALSE);
313 return rv;
314 }
316 static CERTCertificate*
317 FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl,
318 char *certNickName)
319 {
320 CERTCertificate *cert = NULL, *certTemp = NULL;
321 SECStatus rv = SECFailure;
322 CERTAuthKeyID* authorityKeyID = NULL;
323 SECItem* subject = NULL;
325 PORT_Assert(certHandle != NULL);
326 if (!certHandle || (!signCrl && !certNickName)) {
327 SECU_PrintError(progName, "invalid args for function "
328 "FindSigningCert \n");
329 return NULL;
330 }
332 if (signCrl) {
333 #if 0
334 authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl);
335 #endif
336 subject = &signCrl->crl.derName;
337 } else {
338 certTemp = CERT_FindCertByNickname(certHandle, certNickName);
339 if (!certTemp) {
340 SECU_PrintError(progName, "could not find certificate \"%s\" "
341 "in database", certNickName);
342 goto loser;
343 }
344 subject = &certTemp->derSubject;
345 }
347 cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now());
348 if (!cert) {
349 SECU_PrintError(progName, "could not find signing certificate "
350 "in database");
351 goto loser;
352 } else {
353 rv = SECSuccess;
354 }
356 loser:
357 if (certTemp)
358 CERT_DestroyCertificate(certTemp);
359 if (cert && rv != SECSuccess)
360 CERT_DestroyCertificate(cert);
361 return cert;
362 }
364 static CERTSignedCrl*
365 CreateModifiedCRLCopy(PLArenaPool *arena, CERTCertDBHandle *certHandle,
366 CERTCertificate **cert, char *certNickName,
367 PRFileDesc *inFile, PRInt32 decodeOptions,
368 PRInt32 importOptions)
369 {
370 SECItem crlDER = {0, NULL, 0};
371 CERTSignedCrl *signCrl = NULL;
372 CERTSignedCrl *modCrl = NULL;
373 PLArenaPool *modArena = NULL;
374 SECStatus rv = SECSuccess;
376 if (!arena || !certHandle || !certNickName) {
377 PORT_SetError(SEC_ERROR_INVALID_ARGS);
378 SECU_PrintError(progName, "CreateModifiedCRLCopy: invalid args\n");
379 return NULL;
380 }
382 modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
383 if (!modArena) {
384 SECU_PrintError(progName, "fail to allocate memory\n");
385 return NULL;
386 }
388 if (inFile != NULL) {
389 rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
390 if (rv != SECSuccess) {
391 SECU_PrintError(progName, "unable to read input file");
392 PORT_FreeArena(modArena, PR_FALSE);
393 goto loser;
394 }
396 decodeOptions |= CRL_DECODE_DONT_COPY_DER;
398 modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE,
399 decodeOptions);
400 if (!modCrl) {
401 SECU_PrintError(progName, "fail to decode CRL");
402 goto loser;
403 }
405 if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){
406 /* If caCert is a v2 certificate, make sure that it
407 * can be used for crl signing purpose */
408 *cert = FindSigningCert(certHandle, modCrl, NULL);
409 if (!*cert) {
410 goto loser;
411 }
413 rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert,
414 PR_Now(), NULL);
415 if (rv != SECSuccess) {
416 SECU_PrintError(progName, "fail to verify signed data\n");
417 goto loser;
418 }
419 }
420 } else {
421 modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE);
422 if (!modCrl) {
423 SECU_PrintError(progName, "fail to find crl %s in database\n",
424 certNickName);
425 goto loser;
426 }
427 }
429 signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
430 if (signCrl == NULL) {
431 SECU_PrintError(progName, "fail to allocate memory\n");
432 goto loser;
433 }
435 rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl);
436 if (rv != SECSuccess) {
437 SECU_PrintError(progName, "unable to dublicate crl for "
438 "modification.");
439 goto loser;
440 }
442 /* Make sure the update time is current. It can be modified later
443 * by "update <time>" command from crl generation script */
444 rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
445 if (rv != SECSuccess) {
446 SECU_PrintError(progName, "fail to encode current time\n");
447 goto loser;
448 }
450 signCrl->arena = arena;
452 loser:
453 if (crlDER.data) {
454 SECITEM_FreeItem(&crlDER, 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 }
466 static CERTSignedCrl*
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;
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 }
484 mark = PORT_ArenaMark(arena);
486 signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
487 if (signCrl == NULL) {
488 SECU_PrintError(progName, "fail to allocate memory\n");
489 return NULL;
490 }
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 }
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 }
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 }
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 }
523 /* set fields */
524 signCrl->arena = arena;
525 signCrl->dbhandle = certHandle;
526 signCrl->crl.arena = arena;
528 return signCrl;
530 loser:
531 PORT_ArenaRelease(arena, mark);
532 return NULL;
533 }
536 static SECStatus
537 UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile)
538 {
539 CRLGENGeneratorData *crlGenData = NULL;
540 SECStatus rv;
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 }
549 crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile);
550 if (!crlGenData) {
551 SECU_PrintError(progName, "can not initialize parser structure.\n");
552 return SECFailure;
553 }
555 rv = CRLGEN_ExtHandleInit(crlGenData);
556 if (rv == SECFailure) {
557 SECU_PrintError(progName, "can not initialize entries handle.\n");
558 goto loser;
559 }
561 rv = CRLGEN_StartCrlGen(crlGenData);
562 if (rv != SECSuccess) {
563 SECU_PrintError(progName, "crl generation failed");
564 goto loser;
565 }
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 }
582 static SECStatus
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;
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 }
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 }
608 if (PK11_NeedLogin(slot)) {
609 rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
610 if (rv != SECSuccess)
611 goto loser;
612 }
614 rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode);
615 if (rv != SECSuccess) {
616 char* errMsg = NULL;
617 switch (errCode)
618 {
619 case noKeyFound:
620 errMsg = "No private key found of signing cert";
621 break;
623 case noSignatureMatch:
624 errMsg = "Key and Algorithm OId are do not match";
625 break;
627 default:
628 case failToEncode:
629 errMsg = "Failed to encode crl structure";
630 break;
632 case failToSign:
633 errMsg = "Failed to sign crl structure";
634 break;
636 case noMem:
637 errMsg = "Can not allocate memory";
638 break;
639 }
640 SECU_PrintError(progName, "%s\n", errMsg);
641 goto loser;
642 }
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 }
653 rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url);
654 if (rv != SECSuccess) {
655 SECU_PrintError(progName, "fail to save CRL\n");
656 }
658 loser:
659 if (outFile)
660 PR_Close(outFile);
661 if (slot)
662 PK11_FreeSlot(slot);
663 return rv;
664 }
666 static SECStatus
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;
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 }
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 }
697 if (modifyFlag == PR_TRUE) {
698 signCrl = CreateModifiedCRLCopy(arena, certHandle, &cert, certNickName,
699 inFile, decodeOptions, importOptions);
700 if (signCrl == NULL) {
701 goto loser;
702 }
703 }
705 if (!cert) {
706 cert = FindSigningCert(certHandle, signCrl, certNickName);
707 if (cert == NULL) {
708 goto loser;
709 }
710 }
712 if (!signCrl) {
713 if (modifyFlag == PR_TRUE) {
714 if (!outFileName) {
715 int len = strlen(certNickName) + 5;
716 outFileName = PORT_ArenaAlloc(arena, len);
717 PR_snprintf(outFileName, len, "%s.crl", certNickName);
718 }
719 SECU_PrintError(progName, "Will try to generate crl. "
720 "It will be saved in file: %s",
721 outFileName);
722 }
723 signCrl = CreateNewCrl(arena, certHandle, cert);
724 if (!signCrl)
725 goto loser;
726 }
728 rv = UpdateCrl(signCrl, inCrlInitFile);
729 if (rv != SECSuccess) {
730 goto loser;
731 }
733 rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii,
734 slotName, url, pwdata);
735 if (rv != SECSuccess) {
736 goto loser;
737 }
739 if (signCrl && !quiet) {
740 SECU_PrintCRLInfo (stdout, &signCrl->crl, "CRL Info:\n", 0);
741 }
743 loser:
744 if (arena && (!signCrl || !signCrl->arena))
745 PORT_FreeArena (arena, PR_FALSE);
746 if (signCrl)
747 SEC_DestroyCrl (signCrl);
748 if (cert)
749 CERT_DestroyCertificate (cert);
750 return (rv);
751 }
753 static void Usage(char *progName)
754 {
755 fprintf(stderr,
756 "Usage: %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n"
757 " %s -D -n nickname [-d keydir] [-P dbprefix]\n"
758 " %s -S -i crl\n"
759 " %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] "
760 "[-p pwd-file] -w [pwd-string]\n"
761 " %s -E -t crlType [-d keydir] [-P dbprefix]\n"
762 " %s -T\n"
763 " %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] "
764 "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] "
765 "[-a] [-B]\n",
766 progName, progName, progName, progName, progName, progName, progName);
768 fprintf (stderr, "%-15s List CRL\n", "-L");
769 fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
770 "-n nickname");
771 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
772 "-d keydir");
773 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
774 "-P dbprefix");
776 fprintf (stderr, "%-15s Delete a CRL from the cert database\n", "-D");
777 fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n",
778 "-n nickname");
779 fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
780 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
781 "-d keydir");
782 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
783 "-P dbprefix");
785 fprintf (stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E");
786 fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
787 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
788 "-d keydir");
789 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
790 "-P dbprefix");
792 fprintf (stderr, "%-15s Show contents of a CRL file (without database)\n", "-S");
793 fprintf(stderr, "%-20s Specify the file which contains the CRL to show\n",
794 "-i crl");
796 fprintf (stderr, "%-15s Import a CRL to the cert database\n", "-I");
797 fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
798 "-i crl");
799 fprintf(stderr, "%-20s Specify the url.\n", "-u url");
800 fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
801 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
802 "-d keydir");
803 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
804 "-P dbprefix");
805 #ifdef DEBUG
806 fprintf (stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T");
807 #endif
808 fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " ");
809 fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " ");
810 fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " ");
811 fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
812 fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p");
813 fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>");
814 fprintf(stderr, "\n%-15s Create CRL\n", "-G");
815 fprintf(stderr, "%-15s Modify CRL\n", "-M");
816 fprintf(stderr, "%-20s Specify crl initialization file\n",
817 "-c crl-conf-file");
818 fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
819 "-n nickname");
820 fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
821 "-i crl");
822 fprintf(stderr, "%-20s Specify a CRL output file\n",
823 "-o crl-output-file");
824 fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n",
825 "-a");
826 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
827 "-d keydir");
828 fprintf(stderr, "%-20s Provide path to a default pwd file\n",
829 "-f pwd-file");
830 fprintf(stderr, "%-20s Provide db password in command line\n",
831 "-w pwd-string");
832 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
833 "-P dbprefix");
834 fprintf(stderr, "%-20s Specify the url.\n", "-u url");
835 fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
837 exit(-1);
838 }
840 int main(int argc, char **argv)
841 {
842 CERTCertDBHandle *certHandle;
843 PRFileDesc *inFile;
844 PRFileDesc *inCrlInitFile = NULL;
845 int generateCRL;
846 int modifyCRL;
847 int listCRL;
848 int importCRL;
849 int showFileCRL;
850 int deleteCRL;
851 int rv;
852 char *nickName;
853 char *url;
854 char *dbPrefix = "";
855 char *alg = NULL;
856 char *outFile = NULL;
857 char *slotName = NULL;
858 int ascii = 0;
859 int crlType;
860 PLOptState *optstate;
861 PLOptStatus status;
862 SECStatus secstatus;
863 PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
864 PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
865 PRBool quiet = PR_FALSE;
866 PRBool test = PR_FALSE;
867 PRBool erase = PR_FALSE;
868 PRInt32 i = 0;
869 PRInt32 iterations = 1;
870 PRBool readonly = PR_FALSE;
872 secuPWData pwdata = { PW_NONE, 0 };
874 progName = strrchr(argv[0], '/');
875 progName = progName ? progName+1 : argv[0];
877 rv = 0;
878 deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = showFileCRL = 0;
879 inFile = NULL;
880 nickName = url = NULL;
881 certHandle = NULL;
882 crlType = SEC_CRL_TYPE;
883 /*
884 * Parse command line arguments
885 */
886 optstate = PL_CreateOptState(argc, argv, "sqBCDGILMSTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:");
887 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
888 switch (optstate->option) {
889 case '?':
890 Usage(progName);
891 break;
893 case 'T':
894 test = PR_TRUE;
895 break;
897 case 'E':
898 erase = PR_TRUE;
899 break;
901 case 'B':
902 importOptions |= CRL_IMPORT_BYPASS_CHECKS;
903 break;
905 case 'G':
906 generateCRL = 1;
907 break;
909 case 'M':
910 modifyCRL = 1;
911 break;
913 case 'D':
914 deleteCRL = 1;
915 break;
917 case 'I':
918 importCRL = 1;
919 break;
921 case 'S':
922 showFileCRL = 1;
923 break;
925 case 'C':
926 case 'L':
927 listCRL = 1;
928 break;
930 case 'P':
931 dbPrefix = strdup(optstate->value);
932 break;
934 case 'Z':
935 alg = strdup(optstate->value);
936 break;
938 case 'a':
939 ascii = 1;
940 break;
942 case 'c':
943 inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
944 if (!inCrlInitFile) {
945 PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
946 progName, optstate->value);
947 PL_DestroyOptState(optstate);
948 return -1;
949 }
950 break;
952 case 'd':
953 SECU_ConfigDirectory(optstate->value);
954 break;
956 case 'f':
957 pwdata.source = PW_FROMFILE;
958 pwdata.data = strdup(optstate->value);
959 break;
961 case 'h':
962 slotName = strdup(optstate->value);
963 break;
965 case 'i':
966 inFile = PR_Open(optstate->value, PR_RDONLY, 0);
967 if (!inFile) {
968 PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
969 progName, optstate->value);
970 PL_DestroyOptState(optstate);
971 return -1;
972 }
973 break;
975 case 'n':
976 nickName = strdup(optstate->value);
977 break;
979 case 'o':
980 outFile = strdup(optstate->value);
981 break;
983 case 'p':
984 decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
985 break;
987 case 'r': {
988 const char* str = optstate->value;
989 if (str && atoi(str)>0)
990 iterations = atoi(str);
991 }
992 break;
994 case 't': {
995 crlType = atoi(optstate->value);
996 if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
997 PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
998 PL_DestroyOptState(optstate);
999 return -1;
1000 }
1001 break;
1003 case 'q':
1004 quiet = PR_TRUE;
1005 break;
1007 case 'w':
1008 pwdata.source = PW_PLAINTEXT;
1009 pwdata.data = strdup(optstate->value);
1010 break;
1012 case 'u':
1013 url = strdup(optstate->value);
1014 break;
1016 }
1017 }
1018 }
1019 PL_DestroyOptState(optstate);
1021 if (deleteCRL && !nickName) Usage (progName);
1022 if (importCRL && !inFile) Usage (progName);
1023 if (showFileCRL && !inFile) Usage (progName);
1024 if ((generateCRL && !nickName) ||
1025 (modifyCRL && !inFile && !nickName)) Usage (progName);
1026 if (!(listCRL || deleteCRL || importCRL || showFileCRL || generateCRL ||
1027 modifyCRL || test || erase)) Usage (progName);
1029 if (listCRL || showFileCRL) {
1030 readonly = PR_TRUE;
1031 }
1033 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
1035 PK11_SetPasswordFunc(SECU_GetModulePassword);
1037 if (showFileCRL) {
1038 NSS_NoDB_Init(NULL);
1039 }
1040 else {
1041 secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
1042 "secmod.db", readonly ? NSS_INIT_READONLY : 0);
1043 if (secstatus != SECSuccess) {
1044 SECU_PrintPRandOSError(progName);
1045 return -1;
1046 }
1047 }
1049 SECU_RegisterDynamicOids();
1051 certHandle = CERT_GetDefaultCertDB();
1052 if (certHandle == NULL) {
1053 SECU_PrintError(progName, "unable to open the cert db");
1054 /*ignoring return value of NSS_Shutdown() as code returns -1*/
1055 (void) NSS_Shutdown();
1056 return (-1);
1057 }
1059 CRLGEN_InitCrlGenParserLock();
1061 for (i=0; i<iterations; i++) {
1062 /* Read in the private key info */
1063 if (deleteCRL)
1064 DeleteCRL (certHandle, nickName, crlType);
1065 else if (listCRL) {
1066 rv = ListCRL (certHandle, nickName, crlType);
1067 }
1068 else if (importCRL) {
1069 rv = ImportCRL (certHandle, url, crlType, inFile, importOptions,
1070 decodeOptions, &pwdata);
1071 }
1072 else if (showFileCRL) {
1073 rv = DumpCRL (inFile);
1074 } else if (generateCRL || modifyCRL) {
1075 if (!inCrlInitFile)
1076 inCrlInitFile = PR_STDIN;
1077 rv = GenerateCRL (certHandle, nickName, inCrlInitFile,
1078 inFile, outFile, ascii, slotName,
1079 importOptions, alg, quiet,
1080 decodeOptions, url, &pwdata,
1081 modifyCRL);
1082 }
1083 else if (erase) {
1084 /* list and delete all CRLs */
1085 ListCRLNames (certHandle, crlType, PR_TRUE);
1086 }
1087 #ifdef DEBUG
1088 else if (test) {
1089 /* list and delete all CRLs */
1090 ListCRLNames (certHandle, crlType, PR_TRUE);
1091 /* list CRLs */
1092 ListCRLNames (certHandle, crlType, PR_FALSE);
1093 /* import CRL as a blob */
1094 rv = ImportCRL (certHandle, url, crlType, inFile, importOptions,
1095 decodeOptions, &pwdata);
1096 /* list CRLs */
1097 ListCRLNames (certHandle, crlType, PR_FALSE);
1098 }
1099 #endif
1100 }
1102 CRLGEN_DestroyCrlGenParserLock();
1104 if (NSS_Shutdown() != SECSuccess) {
1105 rv = SECFailure;
1106 }
1108 return (rv != SECSuccess);
1109 }