security/nss/cmd/signtool/util.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial