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 #include "signtool.h"
6 #include "prio.h"
7 #include "prmem.h"
8 #include "prenv.h"
9 #include "nss.h"
10
11 static int is_dir(char *filename);
12
13 /***********************************************************
14 * Nasty hackish function definitions
15 */
16
17 long *mozilla_event_queue = 0;
18
19 #ifndef XP_WIN
20 char *
XP_GetString(int i)21 XP_GetString(int i)
22 {
23 /* nasty hackish cast to avoid changing the signature of
24 * JAR_init_callbacks() */
25 return (char *)SECU_Strerror(i);
26 }
27 #endif
28
29 void
FE_SetPasswordEnabled()30 FE_SetPasswordEnabled()
31 {
32 }
33
34 void /*MWContext*/ *
FE_GetInitContext(void)35 FE_GetInitContext(void)
36 {
37 return 0;
38 }
39
40 void /*MWContext*/ *
XP_FindSomeContext()41 XP_FindSomeContext()
42 {
43 /* No windows context in command tools */
44 return NULL;
45 }
46
47 void
ET_moz_CallFunction()48 ET_moz_CallFunction()
49 {
50 }
51
52 /*
53 * R e m o v e A l l A r c
54 *
55 * Remove .arc directories that are lingering
56 * from a previous run of signtool.
57 *
58 */
59 int
RemoveAllArc(char * tree)60 RemoveAllArc(char *tree)
61 {
62 PRDir *dir;
63 PRDirEntry *entry;
64 char *archive = NULL;
65 int retval = 0;
66
67 dir = PR_OpenDir(tree);
68 if (!dir)
69 return -1;
70
71 for (entry = PR_ReadDir(dir, 0); entry; entry = PR_ReadDir(dir,
72 0)) {
73
74 if (entry->name[0] == '.') {
75 continue;
76 }
77
78 if (archive)
79 PR_Free(archive);
80 archive = PR_smprintf("%s/%s", tree, entry->name);
81
82 if (PL_strcaserstr(entry->name, ".arc") ==
83 (entry->name + strlen(entry->name) - 4)) {
84
85 if (verbosity >= 0) {
86 PR_fprintf(outputFD, "removing: %s\n", archive);
87 }
88
89 if (rm_dash_r(archive)) {
90 PR_fprintf(errorFD, "Error removing %s\n", archive);
91 errorCount++;
92 retval = -1;
93 goto finish;
94 }
95 } else if (is_dir(archive)) {
96 if (RemoveAllArc(archive)) {
97 retval = -1;
98 goto finish;
99 }
100 }
101 }
102
103 finish:
104 PR_CloseDir(dir);
105 if (archive)
106 PR_Free(archive);
107
108 return retval;
109 }
110
111 /*
112 * r m _ d a s h _ r
113 *
114 * Remove a file, or a directory recursively.
115 *
116 */
117 int
rm_dash_r(char * path)118 rm_dash_r(char *path)
119 {
120 PRDir *dir;
121 PRDirEntry *entry;
122 PRFileInfo fileinfo;
123 char filename[FNSIZE];
124
125 if (PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) {
126 /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/
127 return -1;
128 }
129 if (fileinfo.type == PR_FILE_DIRECTORY) {
130
131 dir = PR_OpenDir(path);
132 if (!dir) {
133 PR_fprintf(errorFD, "Error: Unable to open directory %s.\n", path);
134 errorCount++;
135 return -1;
136 }
137
138 /* Recursively delete all entries in the directory */
139 while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
140 sprintf(filename, "%s/%s", path, entry->name);
141 if (rm_dash_r(filename)) {
142 PR_CloseDir(dir);
143 return -1;
144 }
145 }
146
147 if (PR_CloseDir(dir) != PR_SUCCESS) {
148 PR_fprintf(errorFD, "Error: Could not close %s.\n", path);
149 errorCount++;
150 return -1;
151 }
152
153 /* Delete the directory itself */
154 if (PR_RmDir(path) != PR_SUCCESS) {
155 PR_fprintf(errorFD, "Error: Unable to delete %s\n", path);
156 errorCount++;
157 return -1;
158 }
159 } else {
160 if (PR_Delete(path) != PR_SUCCESS) {
161 PR_fprintf(errorFD, "Error: Unable to delete %s\n", path);
162 errorCount++;
163 return -1;
164 }
165 }
166 return 0;
167 }
168
169 /*
170 * u s a g e
171 *
172 * Print some useful help information
173 *
174 */
175
176 void
Usage(void)177 Usage(void)
178 {
179 #define FPS PR_fprintf(outputFD,
180 FPS "%s %s -a signing tool for jar files\n", LONG_PROGRAM_NAME,NSS_VERSION);
181 FPS "\n\nType %s -H for more detailed descriptions\n", PROGRAM_NAME);
182 FPS "\nUsage: %s -k keyName [-b basename] [-c Compression Level]\n"
183 "\t\t [-d cert-dir] [-i installer script] [-m metafile] [-x name]\n"
184 "\t\t [-e extension] [-o] [-z] [-X] [--outfile] [--verbose value]\n"
185 "\t\t [--norecurse] [--leavearc] [-j directory] [-Z jarfile] [-O]\n"
186 "\t\t [-p password] directory-tree\n", PROGRAM_NAME);
187 FPS "\t%s -J -k keyName [-b basename] [-c Compression Level]\n"
188 "\t\t [-d cert-dir][-i installer script] [-m metafile] [-x name]\n"
189 "\t\t [-e extension] [-o] [-z] [-X] [--outfile] [--verbose value]\n"
190 "\t\t [--norecurse] [--leavearc] [-j directory] [-p password] [-O] \n"
191 "\t\t directory-tree\n", PROGRAM_NAME);
192 FPS "\t%s -h \n", PROGRAM_NAME);
193 FPS "\t%s -H \n", PROGRAM_NAME);
194 FPS "\t%s -l [-k keyName] [-d cert-dir] [--outfile] [-O] \n", PROGRAM_NAME);
195 FPS "\t%s -L [-k keyName] [-d cert-dir] [--outfile] [-O] \n", PROGRAM_NAME);
196 FPS "\t%s -M [--outfile] [-O] \n", PROGRAM_NAME);
197 FPS "\t%s -v [-d cert-dir] [--outfile] [-O] archive\n", PROGRAM_NAME);
198 FPS "\t%s -w [--outfile] [-O] archive\n" , PROGRAM_NAME);
199 FPS "\t%s -G nickname [--keysize|-s size] [-t |--token tokenname]\n"
200 "\t\t [--outfile] [-O] \n", PROGRAM_NAME);
201 FPS "\t%s -f filename\n" , PROGRAM_NAME);
202 exit(ERRX);
203 }
204
205 void
LongUsage(void)206 LongUsage(void)
207 {
208 FPS "%s %s -a signing tool for jar files\n", LONG_PROGRAM_NAME,NSS_VERSION);
209 FPS "\n%-20s Signs the directory-tree\n",
210 "signtool directory-tree");
211 FPS "%-30s Nickname (key) of the certificate to sign with\n",
212 " -k keyname");
213 FPS "%-30s Base filename for the .rsa and.sf files in the\n",
214 " -b basename");
215 FPS "%-30s META-INF directory\n"," ");
216 FPS "%-30s Set the compression level. 0-9, 0=none\n",
217 " -c CompressionLevel");
218 FPS "%-30s Certificate database directory containing cert*db\n",
219 " -d certificate directory");
220 FPS "%-30s and key*db\n"," ");
221 FPS "%-30s Name of the installer script for SmartUpdate\n",
222 " -i installer script");
223 FPS "%-30s Name of a metadata control file\n",
224 " -m metafile");
225 FPS "%-30s For optimizing the archive for size.\n",
226 " -o");
227 FPS "%-30s Omit Optional Headers\n"," ");
228 FPS "%-30s Excludes the specified directory or file from\n",
229 " -x directory or file name");
230 FPS "%-30s signing\n"," ");
231 FPS "%-30s To not store the signing time in digital\n",
232 " -z directory or file name");
233 FPS "%-30s signature\n"," ");
234 FPS "%-30s Create XPI Compatible Archive. It requires -Z\n",
235 " -X directory or file name");
236 FPS "%-30s option\n"," ");
237 FPS "%-30s Sign only files with the given extension\n",
238 " -e");
239 FPS "%-30s Causes the specified directory to be signed and\n",
240 " -j");
241 FPS "%-30s tags its entries as inline JavaScript\n"," ");
242 FPS "%-30s Creates a JAR file with the specified name.\n",
243 " -Z");
244 FPS "%-30s -Z option cannot be used with -J option\n"," ");
245 FPS "%-30s Specifies a password for the private-key database\n",
246 " -p");
247 FPS "%-30s (insecure)\n"," ");
248 FPS "%-30s File to receive redirected output\n",
249 " --outfile filename");
250 FPS "%-30s Sets the quantity of information generated in\n",
251 " --verbosity value");
252 FPS "%-30s operation\n"," ");
253 FPS "%-30s Blocks recursion into subdirectories\n",
254 " --norecurse");
255 FPS "%-30s Retains the temporary .arc (archive) directories\n",
256 " --leavearc");
257 FPS "%-30s -J option creates\n"," ");
258
259 FPS "\n%-20s Signs a directory of HTML files containing JavaScript and\n",
260 "-J" );
261 FPS "%-20s creates as many archive files as are in the HTML tags.\n"," ");
262
263 FPS "%-20s The options are same as without any command option given\n"," ");
264 FPS "%-20s above. -Z and -J options are not allowed together\n"," ");
265
266 FPS "\n%-20s Generates a new private-public key pair and corresponding\n",
267 "-G nickname");
268 FPS "%-20s object-signing certificates with the given nickname\n"," ");
269 FPS "%-30s Specifies the size of the key for generated \n",
270 " --keysize|-s keysize");
271 FPS "%-30s certificate\n"," ");
272 FPS "%-30s Specifies which available token should generate\n",
273 " --token|-t token name ");
274 FPS "%-30s the key and receive the certificate\n"," ");
275 FPS "%-30s Specifies a file to receive redirected output\n",
276 " --outfile filename ");
277
278 FPS "\n%-20s Display signtool help\n",
279 "-h ");
280
281 FPS "\n%-20s Display signtool help(Detailed)\n",
282 "-H ");
283
284 FPS "\n%-20s Lists signing certificates, including issuing CAs\n",
285 "-l ");
286 FPS "%-30s Certificate database directory containing cert*db\n",
287 " -d certificate directory");
288 FPS "%-30s and key*db\n"," ");
289
290 FPS "%-30s Specifies a file to receive redirected output\n",
291 " --outfile filename ");
292 FPS "%-30s Specifies the nickname (key) of the certificate\n",
293 " -k keyname");
294
295 FPS "\n%-20s Lists the certificates in your database\n",
296 "-L ");
297 FPS "%-30s Certificate database directory containing cert*db\n",
298 " -d certificate directory");
299 FPS "%-30s and key*db\n"," ");
300
301 FPS "%-30s Specifies a file to receive redirected output\n",
302 " --outfile filename ");
303 FPS "%-30s Specifies the nickname (key) of the certificate\n",
304 " -k keyname");
305
306 FPS "\n%-20s Lists the PKCS #11 modules available to signtool\n",
307 "-M ");
308
309 FPS "\n%-20s Displays the contents of an archive and verifies\n",
310 "-v archive");
311 FPS "%-20s cryptographic integrity\n"," ");
312 FPS "%-30s Certificate database directory containing cert*db\n",
313 " -d certificate directory");
314 FPS "%-30s and key*db\n"," ");
315 FPS "%-30s Specifies a file to receive redirected output\n",
316 " --outfile filename ");
317
318 FPS "\n%-20s Displays the names of signers in the archive\n",
319 "-w archive");
320 FPS "%-30s Specifies a file to receive redirected output\n",
321 " --outfile filename ");
322
323 FPS "\n%-30s Common option to all the above.\n",
324 " -O");
325 FPS "%-30s Enable OCSP checking\n"," ");
326
327 FPS "\n%-20s Specifies a text file containing options and arguments in\n",
328 "-f command-file");
329 FPS "%-20s keyword=value format. Commands are taken from this file\n"," ");
330
331 FPS "\n\n\n");
332 FPS "Example:\n");
333 FPS "%-10s -d \"certificate directory\" -k \"certnickname\" \\",
334 PROGRAM_NAME);
335 FPS "\n%-10s -p \"password\" -X -Z \"file.xpi\" directory-tree\n"," " );
336 FPS "Common syntax to create an XPInstall compatible"
337 " signed archive\n\n"," ");
338 FPS "\nCommand File Keywords and Example:\n");
339 FPS "\nKeyword\t\tValue\n");
340 FPS "basename\tSame as -b option\n");
341 FPS "compression\tSame as -c option\n");
342 FPS "certdir\t\tSame as -d option\n");
343 FPS "extension\tSame as -e option\n");
344 FPS "generate\tSame as -G option\n");
345 FPS "installscript\tSame as -i option\n");
346 FPS "javascriptdir\tSame as -j option\n");
347 FPS "htmldir\t\tSame as -J option\n");
348 FPS "certname\tNickname of certificate, as with -k option\n");
349 FPS "signdir\t\tThe directory to be signed, as with -k option\n");
350 FPS "list\t\tSame as -l option. Value is ignored,\n"
351 " \t\tbut = sign must be present\n");
352 FPS "listall\t\tSame as -L option. Value is ignored\n"
353 " \t\tbut = sign must be present\n");
354 FPS "metafile\tSame as -m option\n");
355 FPS "modules\t\tSame as -M option. Value is ignored,\n"
356 " \t\tbut = sign must be present\n");
357 FPS "optimize\tSame as -o option. Value is ignored,\n"
358 " \tbut = sign must be present\n");
359 FPS "ocsp\t\tSame as -O option\n");
360 FPS "password\tSame as -p option\n");
361 FPS "verify\t\tSame as -v option\n");
362 FPS "who\t\tSame as -w option\n");
363 FPS "exclude\t\tSame as -x option\n");
364 FPS "notime\t\tSame as -z option. Value is ignored,\n"
365 " \t\tbut = sign must be present\n");
366 FPS "jarfile\t\tSame as -Z option\n");
367 FPS "outfile\t\tSame as --outfile option. The argument\n");
368 FPS " \t\tis the name of a file to which output\n");
369 FPS " \t\tof a file and error messages will be \n");
370 FPS " \t\tredirected\n");
371 FPS "leavearc\tSame as --leavearc option\n");
372 FPS "verbosity\tSame as --verbosity option\n");
373 FPS "keysize\t\tSame as -s option\n");
374 FPS "token\t\tSame as -t option\n");
375 FPS "xpi\t\tSame as -X option\n");
376 FPS "\n\n");
377 FPS "Here's an example of the use of the command file. The command\n\n");
378 FPS " signtool -d c:\\netscape\\users\\james -k mycert -Z myjar.jar \\\n"
379 " signdir > output.txt\n\n");
380 FPS "becomes\n\n");
381 FPS " signtool -f somefile\n\n");
382 FPS "where somefile contains the following lines:\n\n");
383 FPS " certdir=c:\\netscape\\users\\james\n"," ");
384 FPS " certname=mycert\n"," ");
385 FPS " jarfile=myjar.jar\n"," ");
386 FPS " signdir=signdir\n"," ");
387 FPS " outfile=output.txt\n"," ");
388 exit(ERRX);
389 #undef FPS
390 }
391
392 /*
393 * p r i n t _ e r r o r
394 *
395 * For the undocumented -E function. If an older version
396 * of communicator gives you a numeric error, we can see what
397 * really happened without doing hex math.
398 *
399 */
400
401 void
print_error(int err)402 print_error(int err)
403 {
404 PR_fprintf(errorFD, "Error %d: %s\n", err, JAR_get_error(err));
405 errorCount++;
406 give_help(err);
407 }
408
409 /*
410 * o u t _ o f _ m e m o r y
411 *
412 * Out of memory, exit Signtool.
413 *
414 */
415 void
out_of_memory(void)416 out_of_memory(void)
417 {
418 PR_fprintf(errorFD, "%s: out of memory\n", PROGRAM_NAME);
419 errorCount++;
420 exit(ERRX);
421 }
422
423 /*
424 * V e r i f y C e r t D i r
425 *
426 * Validate that the specified directory
427 * contains a certificate database
428 *
429 */
430 void
VerifyCertDir(char * dir,char * keyName)431 VerifyCertDir(char *dir, char *keyName)
432 {
433 char fn[FNSIZE];
434
435 /* don't try verifying if we don't have a local directory */
436 if (strncmp(dir, "multiaccess:", sizeof("multiaccess:") - 1) == 0) {
437 return;
438 }
439 /* this function is truly evil. Tools and applications should not have
440 * any knowledge of actual cert databases! */
441 return;
442
443 /* This code is really broken because it makes underlying assumptions about
444 * how the NSS profile directory is laid out, but these names can change
445 * from release to release. */
446 sprintf(fn, "%s/cert8.db", dir);
447
448 if (PR_Access(fn, PR_ACCESS_EXISTS)) {
449 PR_fprintf(errorFD, "%s: No certificate database in \"%s\"\n",
450 PROGRAM_NAME, dir);
451 PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n",
452 PROGRAM_NAME);
453 errorCount++;
454 exit(ERRX);
455 }
456
457 if (verbosity >= 0) {
458 PR_fprintf(outputFD, "using certificate directory: %s\n", dir);
459 }
460
461 if (keyName == NULL)
462 return;
463
464 /* if the user gave the -k key argument, verify that
465 a key database already exists */
466
467 sprintf(fn, "%s/key3.db", dir);
468
469 if (PR_Access(fn, PR_ACCESS_EXISTS)) {
470 PR_fprintf(errorFD, "%s: No private key database in \"%s\"\n",
471 PROGRAM_NAME,
472 dir);
473 PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n",
474 PROGRAM_NAME);
475 errorCount++;
476 exit(ERRX);
477 }
478 }
479
480 /*
481 * f o r e a c h
482 *
483 * A recursive function to loop through all names in
484 * the specified directory, as well as all subdirectories.
485 *
486 * FIX: Need to see if all platforms allow multiple
487 * opendir's to be called.
488 *
489 */
490
foreach(char * dirname,char * prefix,int (* fn)(char * relpath,char * basedir,char * reldir,char * filename,void * arg),PRBool recurse,PRBool includeDirs,void * arg)491 int foreach (char *dirname, char *prefix,
492 int (*fn)(char *relpath, char *basedir, char *reldir, char *filename,
493 void *arg),
494 PRBool recurse, PRBool includeDirs, void *arg)
495 {
496 char newdir[FNSIZE];
497 int retval = 0;
498
499 PRDir *dir;
500 PRDirEntry *entry;
501
502 strcpy(newdir, dirname);
503 if (*prefix) {
504 strcat(newdir, "/");
505 strcat(newdir, prefix);
506 }
507
508 dir = PR_OpenDir(newdir);
509 if (!dir)
510 return -1;
511
512 for (entry = PR_ReadDir(dir, 0); entry; entry = PR_ReadDir(dir, 0)) {
513 if (strcmp(entry->name, ".") == 0 ||
514 strcmp(entry->name, "..") == 0) {
515 /* no infinite recursion, please */
516 continue;
517 }
518
519 /* can't sign self */
520 if (!strcmp(entry->name, "META-INF"))
521 continue;
522
523 /* -x option */
524 if (PL_HashTableLookup(excludeDirs, entry->name))
525 continue;
526
527 strcpy(newdir, dirname);
528 if (*dirname)
529 strcat(newdir, "/");
530
531 if (*prefix) {
532 strcat(newdir, prefix);
533 strcat(newdir, "/");
534 }
535 strcat(newdir, entry->name);
536
537 if (!is_dir(newdir) || includeDirs) {
538 char newpath[FNSIZE];
539
540 strcpy(newpath, prefix);
541 if (*newpath)
542 strcat(newpath, "/");
543 strcat(newpath, entry->name);
544
545 if ((*fn)(newpath, dirname, prefix, (char *)entry->name,
546 arg)) {
547 retval = -1;
548 break;
549 }
550 }
551
552 if (is_dir(newdir)) {
553 if (recurse) {
554 char newprefix[FNSIZE];
555
556 strcpy(newprefix, prefix);
557 if (*newprefix) {
558 strcat(newprefix, "/");
559 }
560 strcat(newprefix, entry->name);
561
562 if (foreach (dirname, newprefix, fn, recurse,
563 includeDirs, arg)) {
564 retval = -1;
565 break;
566 }
567 }
568 }
569 }
570
571 PR_CloseDir(dir);
572
573 return retval;
574 }
575
576 /*
577 * i s _ d i r
578 *
579 * Return 1 if file is a directory.
580 * Wonder if this runs on a mac, trust not.
581 *
582 */
583 static int
is_dir(char * filename)584 is_dir(char *filename)
585 {
586 PRFileInfo finfo;
587
588 if (PR_GetFileInfo(filename, &finfo) != PR_SUCCESS) {
589 printf("Unable to get information about %s\n", filename);
590 return 0;
591 }
592
593 return (finfo.type == PR_FILE_DIRECTORY);
594 }
595
596 /***************************************************************
597 *
598 * s e c E r r o r S t r i n g
599 *
600 * Returns an error string corresponding to the given error code.
601 * Doesn't cover all errors; returns a default for many.
602 * Returned string is only valid until the next call of this function.
603 */
604 const char *
secErrorString(long code)605 secErrorString(long code)
606 {
607 static char errstring[80]; /* dynamically constructed error string */
608 char *c; /* the returned string */
609
610 switch (code) {
611 case SEC_ERROR_IO:
612 c = "io error";
613 break;
614 case SEC_ERROR_LIBRARY_FAILURE:
615 c = "security library failure";
616 break;
617 case SEC_ERROR_BAD_DATA:
618 c = "bad data";
619 break;
620 case SEC_ERROR_OUTPUT_LEN:
621 c = "output length";
622 break;
623 case SEC_ERROR_INPUT_LEN:
624 c = "input length";
625 break;
626 case SEC_ERROR_INVALID_ARGS:
627 c = "invalid args";
628 break;
629 case SEC_ERROR_EXPIRED_CERTIFICATE:
630 c = "expired certificate";
631 break;
632 case SEC_ERROR_REVOKED_CERTIFICATE:
633 c = "revoked certificate";
634 break;
635 case SEC_ERROR_INADEQUATE_KEY_USAGE:
636 c = "inadequate key usage";
637 break;
638 case SEC_ERROR_INADEQUATE_CERT_TYPE:
639 c = "inadequate certificate type";
640 break;
641 case SEC_ERROR_UNTRUSTED_CERT:
642 c = "untrusted cert";
643 break;
644 case SEC_ERROR_NO_KRL:
645 c = "no key revocation list";
646 break;
647 case SEC_ERROR_KRL_BAD_SIGNATURE:
648 c = "key revocation list: bad signature";
649 break;
650 case SEC_ERROR_KRL_EXPIRED:
651 c = "key revocation list expired";
652 break;
653 case SEC_ERROR_REVOKED_KEY:
654 c = "revoked key";
655 break;
656 case SEC_ERROR_CRL_BAD_SIGNATURE:
657 c = "certificate revocation list: bad signature";
658 break;
659 case SEC_ERROR_CRL_EXPIRED:
660 c = "certificate revocation list expired";
661 break;
662 case SEC_ERROR_CRL_NOT_YET_VALID:
663 c = "certificate revocation list not yet valid";
664 break;
665 case SEC_ERROR_UNKNOWN_ISSUER:
666 c = "unknown issuer";
667 break;
668 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
669 c = "expired issuer certificate";
670 break;
671 case SEC_ERROR_BAD_SIGNATURE:
672 c = "bad signature";
673 break;
674 case SEC_ERROR_BAD_KEY:
675 c = "bad key";
676 break;
677 case SEC_ERROR_NOT_FORTEZZA_ISSUER:
678 c = "not fortezza issuer";
679 break;
680 case SEC_ERROR_CA_CERT_INVALID:
681 c = "Certificate Authority certificate invalid";
682 break;
683 case SEC_ERROR_EXTENSION_NOT_FOUND:
684 c = "extension not found";
685 break;
686 case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
687 c = "certificate not in name space";
688 break;
689 case SEC_ERROR_UNTRUSTED_ISSUER:
690 c = "untrusted issuer";
691 break;
692 default:
693 sprintf(errstring, "security error %ld", code);
694 c = errstring;
695 break;
696 }
697
698 return c;
699 }
700
701 /***************************************************************
702 *
703 * d i s p l a y V e r i f y L o g
704 *
705 * Prints the log of a cert verification.
706 */
707 void
displayVerifyLog(CERTVerifyLog * log)708 displayVerifyLog(CERTVerifyLog *log)
709 {
710 CERTVerifyLogNode *node;
711 CERTCertificate *cert;
712 char *name;
713
714 if (!log || (log->count <= 0)) {
715 return;
716 }
717
718 for (node = log->head; node != NULL; node = node->next) {
719
720 if (!(cert = node->cert)) {
721 continue;
722 }
723
724 /* Get a name for this cert */
725 if (cert->nickname != NULL) {
726 name = cert->nickname;
727 } else if (cert->emailAddr && cert->emailAddr[0]) {
728 name = cert->emailAddr;
729 } else {
730 name = cert->subjectName;
731 }
732
733 printf("%s%s:\n", name,
734 (node->depth > 0) ? " [Certificate Authority]" : "");
735
736 printf("\t%s\n", secErrorString(node->error));
737 }
738 }
739
740 /*
741 * J a r L i s t M o d u l e s
742 *
743 * Print a list of the PKCS11 modules that are
744 * available. This is useful for smartcard people to
745 * make sure they have the drivers loaded.
746 *
747 */
748 void
JarListModules(void)749 JarListModules(void)
750 {
751 int i;
752 int count = 0;
753
754 SECMODModuleList *modules = NULL;
755 static SECMODListLock *moduleLock = NULL;
756
757 SECMODModuleList *mlp;
758
759 if ((moduleLock = SECMOD_GetDefaultModuleListLock()) == NULL) {
760 /* this is the wrong text */
761 PR_fprintf(errorFD, "%s: unable to acquire lock on module list\n",
762 PROGRAM_NAME);
763 errorCount++;
764 exit(ERRX);
765 }
766
767 SECMOD_GetReadLock(moduleLock);
768
769 modules = SECMOD_GetDefaultModuleList();
770
771 if (modules == NULL) {
772 SECMOD_ReleaseReadLock(moduleLock);
773 PR_fprintf(errorFD, "%s: Can't get module list\n", PROGRAM_NAME);
774 errorCount++;
775 exit(ERRX);
776 }
777
778 PR_fprintf(outputFD, "\nListing of PKCS11 modules\n");
779 PR_fprintf(outputFD, "-----------------------------------------------\n");
780
781 for (mlp = modules; mlp != NULL; mlp = mlp->next) {
782 count++;
783 PR_fprintf(outputFD, "%3d. %s\n", count, mlp->module->commonName);
784
785 if (mlp->module->internal)
786 PR_fprintf(outputFD, " (this module is internally loaded)\n");
787 else
788 PR_fprintf(outputFD, " (this is an external module)\n");
789
790 if (mlp->module->dllName)
791 PR_fprintf(outputFD, " DLL name: %s\n",
792 mlp->module->dllName);
793
794 if (mlp->module->slotCount == 0)
795 PR_fprintf(outputFD, " slots: There are no slots attached to this module\n");
796 else
797 PR_fprintf(outputFD, " slots: %d slots attached\n",
798 mlp->module->slotCount);
799
800 if (mlp->module->loaded == 0)
801 PR_fprintf(outputFD, " status: Not loaded\n");
802 else
803 PR_fprintf(outputFD, " status: loaded\n");
804
805 for (i = 0; i < mlp->module->slotCount; i++) {
806 PK11SlotInfo *slot = mlp->module->slots[i];
807
808 PR_fprintf(outputFD, "\n");
809 PR_fprintf(outputFD, " slot: %s\n", PK11_GetSlotName(slot));
810 PR_fprintf(outputFD, " token: %s\n", PK11_GetTokenName(slot));
811 }
812 }
813
814 PR_fprintf(outputFD, "-----------------------------------------------\n");
815
816 if (count == 0)
817 PR_fprintf(outputFD,
818 "Warning: no modules were found (should have at least one)\n");
819
820 SECMOD_ReleaseReadLock(moduleLock);
821 }
822
823 /**********************************************************************
824 * c h o p
825 *
826 * Eliminates leading and trailing whitespace. Returns a pointer to the
827 * beginning of non-whitespace, or an empty string if it's all whitespace.
828 */
829 char *
chop(char * str)830 chop(char *str)
831 {
832 char *start, *end;
833
834 if (str) {
835 start = str;
836
837 /* Nip leading whitespace */
838 while (isspace(*start)) {
839 start++;
840 }
841
842 /* Nip trailing whitespace */
843 if (*start) {
844 end = start + strlen(start) - 1;
845 while (isspace(*end) && end > start) {
846 end--;
847 }
848 *(end + 1) = '\0';
849 }
850
851 return start;
852 } else {
853 return NULL;
854 }
855 }
856
857 /***********************************************************************
858 *
859 * F a t a l E r r o r
860 *
861 * Outputs an error message and bails out of the program.
862 */
863 void
FatalError(char * msg)864 FatalError(char *msg)
865 {
866 if (!msg)
867 msg = "";
868
869 PR_fprintf(errorFD, "FATAL ERROR: %s\n", msg);
870 errorCount++;
871 exit(ERRX);
872 }
873
874 /*************************************************************************
875 *
876 * I n i t C r y p t o
877 */
878 int
InitCrypto(char * cert_dir,PRBool readOnly)879 InitCrypto(char *cert_dir, PRBool readOnly)
880 {
881 SECStatus rv;
882 static int prior = 0;
883 PK11SlotInfo *slotinfo;
884
885 if (prior == 0) {
886 /* some functions such as OpenKeyDB expect this path to be
887 * implicitly set prior to calling */
888 if (readOnly) {
889 rv = NSS_Init(cert_dir);
890 } else {
891 rv = NSS_InitReadWrite(cert_dir);
892 }
893 if (rv != SECSuccess) {
894 SECU_PrintPRandOSError(PROGRAM_NAME);
895 exit(-1);
896 }
897
898 SECU_ConfigDirectory(cert_dir);
899
900 /* Been there done that */
901 prior++;
902
903 PK11_SetPasswordFunc(SECU_GetModulePassword);
904
905 /* Must login to FIPS before you do anything else */
906 if (PK11_IsFIPS()) {
907 slotinfo = PK11_GetInternalSlot();
908 if (!slotinfo) {
909 fprintf(stderr, "%s: Unable to get PKCS #11 Internal Slot."
910 "\n",
911 PROGRAM_NAME);
912 return -1;
913 }
914 if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/,
915 &pwdata) != SECSuccess) {
916 fprintf(stderr, "%s: Unable to authenticate to %s.\n",
917 PROGRAM_NAME, PK11_GetSlotName(slotinfo));
918 PK11_FreeSlot(slotinfo);
919 return -1;
920 }
921 PK11_FreeSlot(slotinfo);
922 }
923
924 /* Make sure there is a password set on the internal key slot */
925 slotinfo = PK11_GetInternalKeySlot();
926 if (!slotinfo) {
927 fprintf(stderr, "%s: Unable to get PKCS #11 Internal Key Slot."
928 "\n",
929 PROGRAM_NAME);
930 return -1;
931 }
932 if (PK11_NeedUserInit(slotinfo)) {
933 PR_fprintf(errorFD,
934 "\nWARNING: No password set on internal key database. Most operations will fail."
935 "\nYou must create a password.\n");
936 warningCount++;
937 }
938
939 /* Make sure we can authenticate to the key slot in FIPS mode */
940 if (PK11_IsFIPS()) {
941 if (PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/,
942 &pwdata) != SECSuccess) {
943 fprintf(stderr, "%s: Unable to authenticate to %s.\n",
944 PROGRAM_NAME, PK11_GetSlotName(slotinfo));
945 PK11_FreeSlot(slotinfo);
946 return -1;
947 }
948 }
949 PK11_FreeSlot(slotinfo);
950 }
951
952 return 0;
953 }
954
955 /* Windows foolishness is now in the secutil lib */
956
957 /*****************************************************************
958 * g e t _ d e f a u l t _ c e r t _ d i r
959 *
960 * Attempt to locate a certificate directory.
961 * Failing that, complain that the user needs to
962 * use the -d(irectory) parameter.
963 *
964 */
965 char *
get_default_cert_dir(void)966 get_default_cert_dir(void)
967 {
968 char *home;
969
970 char *cd = NULL;
971 static char db[FNSIZE];
972
973 #ifdef XP_UNIX
974 home = PR_GetEnvSecure("HOME");
975
976 if (home && *home) {
977 sprintf(db, "%s/.netscape", home);
978 cd = db;
979 }
980 #endif
981
982 #ifdef XP_PC
983 FILE *fp;
984
985 /* first check the environment override */
986
987 home = PR_GetEnvSecure("JAR_HOME");
988
989 if (home && *home) {
990 sprintf(db, "%s/cert7.db", home);
991
992 if ((fp = fopen(db, "r")) != NULL) {
993 fclose(fp);
994 cd = home;
995 }
996 }
997
998 /* try the old navigator directory */
999
1000 if (cd == NULL) {
1001 home = "c:/Program Files/Netscape/Navigator";
1002
1003 sprintf(db, "%s/cert7.db", home);
1004
1005 if ((fp = fopen(db, "r")) != NULL) {
1006 fclose(fp);
1007 cd = home;
1008 }
1009 }
1010
1011 /* Try the current directory, I wonder if this
1012 is really a good idea. Remember, Windows only.. */
1013
1014 if (cd == NULL) {
1015 home = ".";
1016
1017 sprintf(db, "%s/cert7.db", home);
1018
1019 if ((fp = fopen(db, "r")) != NULL) {
1020 fclose(fp);
1021 cd = home;
1022 }
1023 }
1024
1025 #endif
1026
1027 if (!cd) {
1028 PR_fprintf(errorFD,
1029 "You must specify the location of your certificate directory\n");
1030 PR_fprintf(errorFD,
1031 "with the -d option. Example: -d ~/.netscape in many cases with Unix.\n");
1032 errorCount++;
1033 exit(ERRX);
1034 }
1035
1036 return cd;
1037 }
1038
1039 /************************************************************************
1040 * g i v e _ h e l p
1041 */
1042 void
give_help(int status)1043 give_help(int status)
1044 {
1045 if (status == SEC_ERROR_UNKNOWN_ISSUER) {
1046 PR_fprintf(errorFD,
1047 "The Certificate Authority (CA) for this certificate\n");
1048 PR_fprintf(errorFD,
1049 "does not appear to be in your database. You should contact\n");
1050 PR_fprintf(errorFD,
1051 "the organization which issued this certificate to obtain\n");
1052 PR_fprintf(errorFD, "a copy of its CA Certificate.\n");
1053 }
1054 }
1055
1056 /**************************************************************************
1057 *
1058 * p r _ f g e t s
1059 *
1060 * fgets implemented with NSPR.
1061 */
1062 char *
pr_fgets(char * buf,int size,PRFileDesc * file)1063 pr_fgets(char *buf, int size, PRFileDesc *file)
1064 {
1065 int i;
1066 int status;
1067 char c;
1068
1069 i = 0;
1070 while (i < size - 1) {
1071 status = PR_Read(file, &c, 1);
1072 if (status == -1) {
1073 return NULL;
1074 } else if (status == 0) {
1075 if (i == 0) {
1076 return NULL;
1077 }
1078 break;
1079 }
1080 buf[i++] = c;
1081 if (c == '\n') {
1082 break;
1083 }
1084 }
1085 buf[i] = '\0';
1086
1087 return buf;
1088 }
1089