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