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