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