security/nss/cmd/signtool/sign.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 "zip.h"
michael@0 7 #include "prmem.h"
michael@0 8 #include "blapi.h"
michael@0 9 #include "sechash.h" /* for HASH_GetHashObject() */
michael@0 10
michael@0 11 static int create_pk7 (char *dir, char *keyName, int *keyType);
michael@0 12 static int jar_find_key_type (CERTCertificate *cert);
michael@0 13 static int manifesto (char *dirname, char *install_script, PRBool recurse);
michael@0 14 static int manifesto_fn(char *relpath, char *basedir, char *reldir,
michael@0 15 char *filename, void *arg);
michael@0 16 static int manifesto_xpi_fn(char *relpath, char *basedir, char *reldir,
michael@0 17 char *filename, void *arg);
michael@0 18 static int sign_all_arc_fn(char *relpath, char *basedir, char *reldir,
michael@0 19 char *filename, void *arg);
michael@0 20 static int add_meta (FILE *fp, char *name);
michael@0 21 static int SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert);
michael@0 22 static int generate_SF_file (char *manifile, char *who);
michael@0 23 static int calculate_MD5_range (FILE *fp, long r1, long r2,
michael@0 24 JAR_Digest *dig);
michael@0 25 static void SignOut (void *arg, const char *buf, unsigned long len);
michael@0 26
michael@0 27 static char *metafile = NULL;
michael@0 28 static int optimize = 0;
michael@0 29 static FILE *mf;
michael@0 30 static ZIPfile *zipfile = NULL;
michael@0 31
michael@0 32 /*
michael@0 33 * S i g n A r c h i v e
michael@0 34 *
michael@0 35 * Sign an individual archive tree. A directory
michael@0 36 * called META-INF is created underneath this.
michael@0 37 *
michael@0 38 */
michael@0 39 int
michael@0 40 SignArchive(char *tree, char *keyName, char *zip_file, int javascript,
michael@0 41 char *meta_file, char *install_script, int _optimize, PRBool recurse)
michael@0 42 {
michael@0 43 int status;
michael@0 44 char tempfn [FNSIZE], fullfn [FNSIZE];
michael@0 45 int keyType = rsaKey;
michael@0 46
michael@0 47 metafile = meta_file;
michael@0 48 optimize = _optimize;
michael@0 49
michael@0 50 /* To create XPI compatible Archive manifesto() must be run before
michael@0 51 * the zipfile is opened. This is so the signed files are not added
michael@0 52 * the archive before the crucial rsa/dsa file*/
michael@0 53 if (xpi_arc) {
michael@0 54 manifesto (tree, install_script, recurse);
michael@0 55 }
michael@0 56
michael@0 57 if (zip_file) {
michael@0 58 zipfile = JzipOpen(zip_file, NULL /*no comment*/);
michael@0 59 }
michael@0 60
michael@0 61 /*Sign and add files to the archive normally with manifesto()*/
michael@0 62 if (!xpi_arc) {
michael@0 63 manifesto (tree, install_script, recurse);
michael@0 64 }
michael@0 65
michael@0 66 if (keyName) {
michael@0 67 status = create_pk7 (tree, keyName, &keyType);
michael@0 68 if (status < 0) {
michael@0 69 PR_fprintf(errorFD, "the tree \"%s\" was NOT SUCCESSFULLY SIGNED\n",
michael@0 70 tree);
michael@0 71 errorCount++;
michael@0 72 exit (ERRX);
michael@0 73 }
michael@0 74 }
michael@0 75
michael@0 76 /* Add the rsa/dsa file as the first file in the archive. This is crucial
michael@0 77 * for a XPInstall compatible archive */
michael@0 78 if (xpi_arc) {
michael@0 79 if (verbosity >= 0) {
michael@0 80 PR_fprintf(outputFD, "%s \n", XPI_TEXT);
michael@0 81 }
michael@0 82
michael@0 83 /* rsa/dsa to zip */
michael@0 84 sprintf (tempfn, "META-INF/%s.%s", base, (keyType == dsaKey ?
michael@0 85 "dsa" : "rsa"));
michael@0 86 sprintf (fullfn, "%s/%s", tree, tempfn);
michael@0 87 JzipAdd(fullfn, tempfn, zipfile, compression_level);
michael@0 88
michael@0 89 /* Loop through all files & subdirectories, add to archive */
michael@0 90 foreach (tree, "", manifesto_xpi_fn, recurse, PR_FALSE /*include dirs */,
michael@0 91 (void * )NULL);
michael@0 92 }
michael@0 93 /* mf to zip */
michael@0 94 strcpy (tempfn, "META-INF/manifest.mf");
michael@0 95 sprintf (fullfn, "%s/%s", tree, tempfn);
michael@0 96 JzipAdd(fullfn, tempfn, zipfile, compression_level);
michael@0 97
michael@0 98 /* sf to zip */
michael@0 99 sprintf (tempfn, "META-INF/%s.sf", base);
michael@0 100 sprintf (fullfn, "%s/%s", tree, tempfn);
michael@0 101 JzipAdd(fullfn, tempfn, zipfile, compression_level);
michael@0 102
michael@0 103 /* Add the rsa/dsa file to the zip archive normally */
michael@0 104 if (!xpi_arc) {
michael@0 105 /* rsa/dsa to zip */
michael@0 106 sprintf (tempfn, "META-INF/%s.%s", base, (keyType == dsaKey ?
michael@0 107 "dsa" : "rsa"));
michael@0 108 sprintf (fullfn, "%s/%s", tree, tempfn);
michael@0 109 JzipAdd(fullfn, tempfn, zipfile, compression_level);
michael@0 110 }
michael@0 111
michael@0 112 JzipClose(zipfile);
michael@0 113
michael@0 114 if (verbosity >= 0) {
michael@0 115 if (javascript) {
michael@0 116 PR_fprintf(outputFD, "jarfile \"%s\" signed successfully\n",
michael@0 117 zip_file);
michael@0 118 } else {
michael@0 119 PR_fprintf(outputFD, "tree \"%s\" signed successfully\n",
michael@0 120 tree);
michael@0 121 }
michael@0 122 }
michael@0 123
michael@0 124 return 0;
michael@0 125 }
michael@0 126
michael@0 127
michael@0 128 typedef struct {
michael@0 129 char *keyName;
michael@0 130 int javascript;
michael@0 131 char *metafile;
michael@0 132 char *install_script;
michael@0 133 int optimize;
michael@0 134 } SignArcInfo;
michael@0 135
michael@0 136 /*
michael@0 137 * S i g n A l l A r c
michael@0 138 *
michael@0 139 * Javascript may generate multiple .arc directories, one
michael@0 140 * for each jar archive needed. Sign them all.
michael@0 141 *
michael@0 142 */
michael@0 143 int
michael@0 144 SignAllArc(char *jartree, char *keyName, int javascript, char *metafile,
michael@0 145 char *install_script, int optimize, PRBool recurse)
michael@0 146 {
michael@0 147 SignArcInfo info;
michael@0 148
michael@0 149 info.keyName = keyName;
michael@0 150 info.javascript = javascript;
michael@0 151 info.metafile = metafile;
michael@0 152 info.install_script = install_script;
michael@0 153 info.optimize = optimize;
michael@0 154
michael@0 155 return foreach(jartree, "", sign_all_arc_fn, recurse,
michael@0 156 PR_TRUE /*include dirs*/, (void * )&info);
michael@0 157 }
michael@0 158
michael@0 159
michael@0 160 static int
michael@0 161 sign_all_arc_fn(char *relpath, char *basedir, char *reldir, char *filename,
michael@0 162 void *arg)
michael@0 163 {
michael@0 164 char *zipfile = NULL;
michael@0 165 char *arc = NULL, *archive = NULL;
michael@0 166 int retval = 0;
michael@0 167 SignArcInfo * infop = (SignArcInfo * )arg;
michael@0 168
michael@0 169 /* Make sure there is one and only one ".arc" in the relative path,
michael@0 170 * and that it is at the end of the path (don't sign .arcs within .arcs) */
michael@0 171 if ( (PL_strcaserstr(relpath, ".arc") == relpath + strlen(relpath) -
michael@0 172 4) &&
michael@0 173 (PL_strcasestr(relpath, ".arc") == relpath + strlen(relpath) - 4) ) {
michael@0 174
michael@0 175 if (!infop) {
michael@0 176 PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME);
michael@0 177 errorCount++;
michael@0 178 retval = -1;
michael@0 179 goto finish;
michael@0 180 }
michael@0 181 archive = PR_smprintf("%s/%s", basedir, relpath);
michael@0 182
michael@0 183 zipfile = PL_strdup(archive);
michael@0 184 arc = PORT_Strrchr (zipfile, '.');
michael@0 185
michael@0 186 if (arc == NULL) {
michael@0 187 PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME);
michael@0 188 errorCount++;
michael@0 189 retval = -1;
michael@0 190 goto finish;
michael@0 191 }
michael@0 192
michael@0 193 PL_strcpy (arc, ".jar");
michael@0 194
michael@0 195 if (verbosity >= 0) {
michael@0 196 PR_fprintf(outputFD, "\nsigning: %s\n", zipfile);
michael@0 197 }
michael@0 198 retval = SignArchive(archive, infop->keyName, zipfile,
michael@0 199 infop->javascript, infop->metafile, infop->install_script,
michael@0 200 infop->optimize, PR_TRUE /* recurse */);
michael@0 201 }
michael@0 202 finish:
michael@0 203 if (archive)
michael@0 204 PR_Free(archive);
michael@0 205 if (zipfile)
michael@0 206 PR_Free(zipfile);
michael@0 207
michael@0 208 return retval;
michael@0 209 }
michael@0 210
michael@0 211
michael@0 212 /*********************************************************************
michael@0 213 *
michael@0 214 * c r e a t e _ p k 7
michael@0 215 */
michael@0 216 static int
michael@0 217 create_pk7 (char *dir, char *keyName, int *keyType)
michael@0 218 {
michael@0 219 int status = 0;
michael@0 220 char *file_ext;
michael@0 221
michael@0 222 CERTCertificate * cert;
michael@0 223 CERTCertDBHandle * db;
michael@0 224
michael@0 225 FILE * in, *out;
michael@0 226
michael@0 227 char sf_file [FNSIZE];
michael@0 228 char pk7_file [FNSIZE];
michael@0 229
michael@0 230 /* open cert database */
michael@0 231 db = CERT_GetDefaultCertDB();
michael@0 232
michael@0 233 if (db == NULL)
michael@0 234 return - 1;
michael@0 235
michael@0 236 /* find cert */
michael@0 237 /*cert = CERT_FindCertByNicknameOrEmailAddr(db, keyName);*/
michael@0 238 cert = PK11_FindCertFromNickname(keyName, &pwdata);
michael@0 239
michael@0 240 if (cert == NULL) {
michael@0 241 SECU_PrintError ( PROGRAM_NAME,
michael@0 242 "Cannot find the cert \"%s\"", keyName);
michael@0 243 return -1;
michael@0 244 }
michael@0 245
michael@0 246
michael@0 247 /* determine the key type, which sets the extension for pkcs7 object */
michael@0 248
michael@0 249 *keyType = jar_find_key_type (cert);
michael@0 250 file_ext = (*keyType == dsaKey) ? "dsa" : "rsa";
michael@0 251
michael@0 252 sprintf (sf_file, "%s/META-INF/%s.sf", dir, base);
michael@0 253 sprintf (pk7_file, "%s/META-INF/%s.%s", dir, base, file_ext);
michael@0 254
michael@0 255 if ((in = fopen (sf_file, "rb")) == NULL) {
michael@0 256 PR_fprintf(errorFD, "%s: Can't open %s for reading\n", PROGRAM_NAME,
michael@0 257 sf_file);
michael@0 258 errorCount++;
michael@0 259 exit (ERRX);
michael@0 260 }
michael@0 261
michael@0 262 if ((out = fopen (pk7_file, "wb")) == NULL) {
michael@0 263 PR_fprintf(errorFD, "%s: Can't open %s for writing\n", PROGRAM_NAME,
michael@0 264 sf_file);
michael@0 265 errorCount++;
michael@0 266 exit (ERRX);
michael@0 267 }
michael@0 268
michael@0 269 status = SignFile (out, in, cert);
michael@0 270
michael@0 271 CERT_DestroyCertificate (cert);
michael@0 272 fclose (in);
michael@0 273 fclose (out);
michael@0 274
michael@0 275 if (status) {
michael@0 276 PR_fprintf(errorFD, "%s: PROBLEM signing data (%s)\n",
michael@0 277 PROGRAM_NAME, SECU_Strerror(PORT_GetError()));
michael@0 278 errorCount++;
michael@0 279 return - 1;
michael@0 280 }
michael@0 281
michael@0 282 return 0;
michael@0 283 }
michael@0 284
michael@0 285
michael@0 286 /*
michael@0 287 * j a r _ f i n d _ k e y _ t y p e
michael@0 288 *
michael@0 289 * Determine the key type for a given cert, which
michael@0 290 * should be rsaKey or dsaKey. Any error return 0.
michael@0 291 *
michael@0 292 */
michael@0 293 static int
michael@0 294 jar_find_key_type (CERTCertificate *cert)
michael@0 295 {
michael@0 296 SECKEYPrivateKey * privk = NULL;
michael@0 297 KeyType keyType;
michael@0 298
michael@0 299 /* determine its type */
michael@0 300 privk = PK11_FindKeyByAnyCert (cert, &pwdata);
michael@0 301 if (privk == NULL) {
michael@0 302 PR_fprintf(errorFD, "warning - can't find private key for this cert\n");
michael@0 303 warningCount++;
michael@0 304 return 0;
michael@0 305 }
michael@0 306
michael@0 307 keyType = privk->keyType;
michael@0 308 SECKEY_DestroyPrivateKey (privk);
michael@0 309 return keyType;
michael@0 310 }
michael@0 311
michael@0 312
michael@0 313 /*
michael@0 314 * m a n i f e s t o
michael@0 315 *
michael@0 316 * Run once for every subdirectory in which a
michael@0 317 * manifest is to be created -- usually exactly once.
michael@0 318 *
michael@0 319 */
michael@0 320 static int
michael@0 321 manifesto (char *dirname, char *install_script, PRBool recurse)
michael@0 322 {
michael@0 323 char metadir [FNSIZE], sfname [FNSIZE];
michael@0 324
michael@0 325 /* Create the META-INF directory to hold signing info */
michael@0 326
michael@0 327 if (PR_Access (dirname, PR_ACCESS_READ_OK)) {
michael@0 328 PR_fprintf(errorFD, "%s: unable to read your directory: %s\n",
michael@0 329 PROGRAM_NAME, dirname);
michael@0 330 errorCount++;
michael@0 331 perror (dirname);
michael@0 332 exit (ERRX);
michael@0 333 }
michael@0 334
michael@0 335 if (PR_Access (dirname, PR_ACCESS_WRITE_OK)) {
michael@0 336 PR_fprintf(errorFD, "%s: unable to write to your directory: %s\n",
michael@0 337 PROGRAM_NAME, dirname);
michael@0 338 errorCount++;
michael@0 339 perror(dirname);
michael@0 340 exit(ERRX);
michael@0 341 }
michael@0 342
michael@0 343 sprintf (metadir, "%s/META-INF", dirname);
michael@0 344
michael@0 345 strcpy (sfname, metadir);
michael@0 346
michael@0 347 PR_MkDir (metadir, 0777);
michael@0 348
michael@0 349 strcat (metadir, "/");
michael@0 350 strcat (metadir, MANIFEST);
michael@0 351
michael@0 352 if ((mf = fopen (metadir, "wb")) == NULL) {
michael@0 353 perror (MANIFEST);
michael@0 354 PR_fprintf(errorFD, "%s: Probably, the directory you are trying to"
michael@0 355 " sign has\n", PROGRAM_NAME);
michael@0 356 PR_fprintf(errorFD, "%s: permissions problems or may not exist.\n",
michael@0 357 PROGRAM_NAME);
michael@0 358 errorCount++;
michael@0 359 exit (ERRX);
michael@0 360 }
michael@0 361
michael@0 362 if (verbosity >= 0) {
michael@0 363 PR_fprintf(outputFD, "Generating %s file..\n", metadir);
michael@0 364 }
michael@0 365
michael@0 366 fprintf(mf, "Manifest-Version: 1.0\n");
michael@0 367 fprintf (mf, "Created-By: %s\n", CREATOR);
michael@0 368 fprintf (mf, "Comments: %s\n", BREAKAGE);
michael@0 369
michael@0 370 if (scriptdir) {
michael@0 371 fprintf (mf, "Comments: --\n");
michael@0 372 fprintf (mf, "Comments: --\n");
michael@0 373 fprintf (mf, "Comments: -- This archive signs Javascripts which may not necessarily\n");
michael@0 374 fprintf (mf, "Comments: -- be included in the physical jar file.\n");
michael@0 375 fprintf (mf, "Comments: --\n");
michael@0 376 fprintf (mf, "Comments: --\n");
michael@0 377 }
michael@0 378
michael@0 379 if (install_script)
michael@0 380 fprintf (mf, "Install-Script: %s\n", install_script);
michael@0 381
michael@0 382 if (metafile)
michael@0 383 add_meta (mf, "+");
michael@0 384
michael@0 385 /* Loop through all files & subdirectories */
michael@0 386 foreach (dirname, "", manifesto_fn, recurse, PR_FALSE /*include dirs */,
michael@0 387 (void * )NULL);
michael@0 388
michael@0 389 fclose (mf);
michael@0 390
michael@0 391 strcat (sfname, "/");
michael@0 392 strcat (sfname, base);
michael@0 393 strcat (sfname, ".sf");
michael@0 394
michael@0 395 if (verbosity >= 0) {
michael@0 396 PR_fprintf(outputFD, "Generating %s.sf file..\n", base);
michael@0 397 }
michael@0 398 generate_SF_file (metadir, sfname);
michael@0 399
michael@0 400 return 0;
michael@0 401 }
michael@0 402
michael@0 403
michael@0 404 /*
michael@0 405 * m a n i f e s t o _ x p i _ f n
michael@0 406 *
michael@0 407 * Called by pointer from SignArchive(), once for
michael@0 408 * each file within the directory. This function
michael@0 409 * is only used for adding to XPI compatible archive
michael@0 410 *
michael@0 411 */
michael@0 412 static int manifesto_xpi_fn
michael@0 413 (char *relpath, char *basedir, char *reldir, char *filename, void *arg)
michael@0 414 {
michael@0 415 char fullname [FNSIZE];
michael@0 416
michael@0 417 if (verbosity >= 0) {
michael@0 418 PR_fprintf(outputFD, "--> %s\n", relpath);
michael@0 419 }
michael@0 420
michael@0 421 /* extension matching */
michael@0 422 if (extensionsGiven) {
michael@0 423 char *ext = PL_strrchr(relpath, '.');
michael@0 424 if (!ext)
michael@0 425 return 0;
michael@0 426 if (!PL_HashTableLookup(extensions, ext))
michael@0 427 return 0;
michael@0 428 }
michael@0 429 sprintf (fullname, "%s/%s", basedir, relpath);
michael@0 430 JzipAdd(fullname, relpath, zipfile, compression_level);
michael@0 431
michael@0 432 return 0;
michael@0 433 }
michael@0 434
michael@0 435
michael@0 436 /*
michael@0 437 * m a n i f e s t o _ f n
michael@0 438 *
michael@0 439 * Called by pointer from manifesto(), once for
michael@0 440 * each file within the directory.
michael@0 441 *
michael@0 442 */
michael@0 443 static int manifesto_fn
michael@0 444 (char *relpath, char *basedir, char *reldir, char *filename, void *arg)
michael@0 445 {
michael@0 446 int use_js;
michael@0 447
michael@0 448 JAR_Digest dig;
michael@0 449 char fullname [FNSIZE];
michael@0 450
michael@0 451 if (verbosity >= 0) {
michael@0 452 PR_fprintf(outputFD, "--> %s\n", relpath);
michael@0 453 }
michael@0 454
michael@0 455 /* extension matching */
michael@0 456 if (extensionsGiven) {
michael@0 457 char *ext = PL_strrchr(relpath, '.');
michael@0 458 if (!ext)
michael@0 459 return 0;
michael@0 460 if (!PL_HashTableLookup(extensions, ext))
michael@0 461 return 0;
michael@0 462 }
michael@0 463
michael@0 464 sprintf (fullname, "%s/%s", basedir, relpath);
michael@0 465
michael@0 466 fprintf (mf, "\n");
michael@0 467
michael@0 468 use_js = 0;
michael@0 469
michael@0 470 if (scriptdir && !PORT_Strcmp (scriptdir, reldir))
michael@0 471 use_js++;
michael@0 472
michael@0 473 /* sign non-.js files inside .arc directories using the javascript magic */
michael@0 474
michael@0 475 if ( (PL_strcaserstr(filename, ".js") != filename + strlen(filename) - 3)
michael@0 476 && (PL_strcaserstr(reldir, ".arc") == reldir + strlen(filename) - 4))
michael@0 477 use_js++;
michael@0 478
michael@0 479 if (use_js) {
michael@0 480 fprintf (mf, "Name: %s\n", filename);
michael@0 481 fprintf (mf, "Magic: javascript\n");
michael@0 482
michael@0 483 if (optimize == 0)
michael@0 484 fprintf (mf, "javascript.id: %s\n", filename);
michael@0 485
michael@0 486 if (metafile)
michael@0 487 add_meta (mf, filename);
michael@0 488 } else {
michael@0 489 fprintf (mf, "Name: %s\n", relpath);
michael@0 490 if (metafile)
michael@0 491 add_meta (mf, relpath);
michael@0 492 }
michael@0 493
michael@0 494 JAR_digest_file (fullname, &dig);
michael@0 495
michael@0 496
michael@0 497 if (optimize == 0) {
michael@0 498 fprintf (mf, "Digest-Algorithms: MD5 SHA1\n");
michael@0 499 fprintf (mf, "MD5-Digest: %s\n", BTOA_DataToAscii (dig.md5,
michael@0 500 MD5_LENGTH));
michael@0 501 }
michael@0 502
michael@0 503 fprintf (mf, "SHA1-Digest: %s\n", BTOA_DataToAscii (dig.sha1, SHA1_LENGTH));
michael@0 504
michael@0 505 if (!use_js) {
michael@0 506 JzipAdd(fullname, relpath, zipfile, compression_level);
michael@0 507 }
michael@0 508
michael@0 509 return 0;
michael@0 510 }
michael@0 511
michael@0 512
michael@0 513 /*
michael@0 514 * a d d _ m e t a
michael@0 515 *
michael@0 516 * Parse the metainfo file, and add any details
michael@0 517 * necessary to the manifest file. In most cases you
michael@0 518 * should be using the -i option (ie, for SmartUpdate).
michael@0 519 *
michael@0 520 */
michael@0 521 static int add_meta (FILE *fp, char *name)
michael@0 522 {
michael@0 523 FILE * met;
michael@0 524 char buf [BUFSIZ];
michael@0 525
michael@0 526 int place;
michael@0 527 char *pattern, *meta;
michael@0 528
michael@0 529 int num = 0;
michael@0 530
michael@0 531 if ((met = fopen (metafile, "r")) != NULL) {
michael@0 532 while (fgets (buf, BUFSIZ, met)) {
michael@0 533 char *s;
michael@0 534
michael@0 535 for (s = buf; *s && *s != '\n' && *s != '\r'; s++)
michael@0 536 ;
michael@0 537 *s = 0;
michael@0 538
michael@0 539 if (*buf == 0)
michael@0 540 continue;
michael@0 541
michael@0 542 pattern = buf;
michael@0 543
michael@0 544 /* skip to whitespace */
michael@0 545 for (s = buf; *s && *s != ' ' && *s != '\t'; s++)
michael@0 546 ;
michael@0 547
michael@0 548 /* terminate pattern */
michael@0 549 if (*s == ' ' || *s == '\t')
michael@0 550 *s++ = 0;
michael@0 551
michael@0 552 /* eat through whitespace */
michael@0 553 while (*s == ' ' || *s == '\t')
michael@0 554 s++;
michael@0 555
michael@0 556 meta = s;
michael@0 557
michael@0 558 /* this will eventually be regexp matching */
michael@0 559
michael@0 560 place = 0;
michael@0 561 if (!PORT_Strcmp (pattern, name))
michael@0 562 place = 1;
michael@0 563
michael@0 564 if (place) {
michael@0 565 num++;
michael@0 566 if (verbosity >= 0) {
michael@0 567 PR_fprintf(outputFD, "[%s] %s\n", name, meta);
michael@0 568 }
michael@0 569 fprintf (fp, "%s\n", meta);
michael@0 570 }
michael@0 571 }
michael@0 572 fclose (met);
michael@0 573 } else {
michael@0 574 PR_fprintf(errorFD, "%s: can't open metafile: %s\n", PROGRAM_NAME,
michael@0 575 metafile);
michael@0 576 errorCount++;
michael@0 577 exit (ERRX);
michael@0 578 }
michael@0 579
michael@0 580 return num;
michael@0 581 }
michael@0 582
michael@0 583
michael@0 584 /**********************************************************************
michael@0 585 *
michael@0 586 * S i g n F i l e
michael@0 587 */
michael@0 588 static int
michael@0 589 SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert)
michael@0 590 {
michael@0 591 int nb;
michael@0 592 char ibuf[4096], digestdata[32];
michael@0 593 const SECHashObject *hashObj;
michael@0 594 void *hashcx;
michael@0 595 unsigned int len;
michael@0 596
michael@0 597 SECItem digest;
michael@0 598 SEC_PKCS7ContentInfo * cinfo;
michael@0 599 SECStatus rv;
michael@0 600
michael@0 601 if (outFile == NULL || inFile == NULL || cert == NULL)
michael@0 602 return - 1;
michael@0 603
michael@0 604 /* XXX probably want to extend interface to allow other hash algorithms */
michael@0 605 hashObj = HASH_GetHashObject(HASH_AlgSHA1);
michael@0 606
michael@0 607 hashcx = (*hashObj->create)();
michael@0 608 if (hashcx == NULL)
michael@0 609 return - 1;
michael@0 610
michael@0 611 (*hashObj->begin)(hashcx);
michael@0 612
michael@0 613 for (; ; ) {
michael@0 614 if (feof(inFile))
michael@0 615 break;
michael@0 616 nb = fread(ibuf, 1, sizeof(ibuf), inFile);
michael@0 617 if (nb == 0) {
michael@0 618 if (ferror(inFile)) {
michael@0 619 PORT_SetError(SEC_ERROR_IO);
michael@0 620 (*hashObj->destroy)(hashcx, PR_TRUE);
michael@0 621 return - 1;
michael@0 622 }
michael@0 623 /* eof */
michael@0 624 break;
michael@0 625 }
michael@0 626 (*hashObj->update)(hashcx, (unsigned char *) ibuf, nb);
michael@0 627 }
michael@0 628
michael@0 629 (*hashObj->end)(hashcx, (unsigned char *) digestdata, &len, 32);
michael@0 630 (*hashObj->destroy)(hashcx, PR_TRUE);
michael@0 631
michael@0 632 digest.data = (unsigned char *) digestdata;
michael@0 633 digest.len = len;
michael@0 634
michael@0 635 cinfo = SEC_PKCS7CreateSignedData
michael@0 636 (cert, certUsageObjectSigner, NULL,
michael@0 637 SEC_OID_SHA1, &digest, NULL, NULL);
michael@0 638
michael@0 639 if (cinfo == NULL)
michael@0 640 return - 1;
michael@0 641
michael@0 642 rv = SEC_PKCS7IncludeCertChain (cinfo, NULL);
michael@0 643 if (rv != SECSuccess) {
michael@0 644 SEC_PKCS7DestroyContentInfo (cinfo);
michael@0 645 return - 1;
michael@0 646 }
michael@0 647
michael@0 648 if (no_time == 0) {
michael@0 649 rv = SEC_PKCS7AddSigningTime (cinfo);
michael@0 650 if (rv != SECSuccess) {
michael@0 651 /* don't check error */
michael@0 652 }
michael@0 653 }
michael@0 654
michael@0 655 rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL, NULL, &pwdata);
michael@0 656
michael@0 657 SEC_PKCS7DestroyContentInfo (cinfo);
michael@0 658
michael@0 659 if (rv != SECSuccess)
michael@0 660 return - 1;
michael@0 661
michael@0 662 return 0;
michael@0 663 }
michael@0 664
michael@0 665
michael@0 666 /*
michael@0 667 * g e n e r a t e _ S F _ f i l e
michael@0 668 *
michael@0 669 * From the supplied manifest file, calculates
michael@0 670 * digests on the various sections, creating a .SF
michael@0 671 * file in the process.
michael@0 672 *
michael@0 673 */
michael@0 674 static int generate_SF_file (char *manifile, char *who)
michael@0 675 {
michael@0 676 FILE * sf;
michael@0 677 FILE * mf;
michael@0 678 long r1, r2, r3;
michael@0 679 char whofile [FNSIZE];
michael@0 680 char *buf, *name = NULL;
michael@0 681 JAR_Digest dig;
michael@0 682 int line = 0;
michael@0 683
michael@0 684 strcpy (whofile, who);
michael@0 685
michael@0 686 if ((mf = fopen (manifile, "rb")) == NULL) {
michael@0 687 perror (manifile);
michael@0 688 exit (ERRX);
michael@0 689 }
michael@0 690
michael@0 691 if ((sf = fopen (whofile, "wb")) == NULL) {
michael@0 692 perror (who);
michael@0 693 exit (ERRX);
michael@0 694 }
michael@0 695
michael@0 696 buf = (char *) PORT_ZAlloc (BUFSIZ);
michael@0 697
michael@0 698 if (buf)
michael@0 699 name = (char *) PORT_ZAlloc (BUFSIZ);
michael@0 700
michael@0 701 if (buf == NULL || name == NULL)
michael@0 702 out_of_memory();
michael@0 703
michael@0 704 fprintf (sf, "Signature-Version: 1.0\n");
michael@0 705 fprintf (sf, "Created-By: %s\n", CREATOR);
michael@0 706 fprintf (sf, "Comments: %s\n", BREAKAGE);
michael@0 707
michael@0 708 if (fgets (buf, BUFSIZ, mf) == NULL) {
michael@0 709 PR_fprintf(errorFD, "%s: empty manifest file!\n", PROGRAM_NAME);
michael@0 710 errorCount++;
michael@0 711 exit (ERRX);
michael@0 712 }
michael@0 713
michael@0 714 if (strncmp (buf, "Manifest-Version:", 17)) {
michael@0 715 PR_fprintf(errorFD, "%s: not a manifest file!\n", PROGRAM_NAME);
michael@0 716 errorCount++;
michael@0 717 exit (ERRX);
michael@0 718 }
michael@0 719
michael@0 720 fseek (mf, 0L, SEEK_SET);
michael@0 721
michael@0 722 /* Process blocks of headers, and calculate their hashen */
michael@0 723
michael@0 724 while (1) {
michael@0 725 /* Beginning range */
michael@0 726 r1 = ftell (mf);
michael@0 727
michael@0 728 if (fgets (name, BUFSIZ, mf) == NULL)
michael@0 729 break;
michael@0 730
michael@0 731 line++;
michael@0 732
michael@0 733 if (r1 != 0 && strncmp (name, "Name:", 5)) {
michael@0 734 PR_fprintf(errorFD,
michael@0 735 "warning: unexpected input in manifest file \"%s\" at line %d:\n",
michael@0 736 manifile, line);
michael@0 737 PR_fprintf(errorFD, "%s\n", name);
michael@0 738 warningCount++;
michael@0 739 }
michael@0 740
michael@0 741 r2 = r1;
michael@0 742 while (fgets (buf, BUFSIZ, mf)) {
michael@0 743 if (*buf == 0 || *buf == '\n' || *buf == '\r')
michael@0 744 break;
michael@0 745
michael@0 746 line++;
michael@0 747
michael@0 748 /* Ending range for hashing */
michael@0 749 r2 = ftell (mf);
michael@0 750 }
michael@0 751
michael@0 752 r3 = ftell (mf);
michael@0 753
michael@0 754 if (r1) {
michael@0 755 fprintf (sf, "\n");
michael@0 756 fprintf (sf, "%s", name);
michael@0 757 }
michael@0 758
michael@0 759 calculate_MD5_range (mf, r1, r2, &dig);
michael@0 760
michael@0 761 if (optimize == 0) {
michael@0 762 fprintf (sf, "Digest-Algorithms: MD5 SHA1\n");
michael@0 763 fprintf (sf, "MD5-Digest: %s\n",
michael@0 764 BTOA_DataToAscii (dig.md5, MD5_LENGTH));
michael@0 765 }
michael@0 766
michael@0 767 fprintf (sf, "SHA1-Digest: %s\n",
michael@0 768 BTOA_DataToAscii (dig.sha1, SHA1_LENGTH));
michael@0 769
michael@0 770 /* restore normalcy after changing offset position */
michael@0 771 fseek (mf, r3, SEEK_SET);
michael@0 772 }
michael@0 773
michael@0 774 PORT_Free (buf);
michael@0 775 PORT_Free (name);
michael@0 776
michael@0 777 fclose (sf);
michael@0 778 fclose (mf);
michael@0 779
michael@0 780 return 0;
michael@0 781 }
michael@0 782
michael@0 783
michael@0 784 /*
michael@0 785 * c a l c u l a t e _ M D 5 _ r a n g e
michael@0 786 *
michael@0 787 * Calculate the MD5 digest on a range of bytes in
michael@0 788 * the specified fopen'd file. Returns base64.
michael@0 789 *
michael@0 790 */
michael@0 791 static int
michael@0 792 calculate_MD5_range (FILE *fp, long r1, long r2, JAR_Digest *dig)
michael@0 793 {
michael@0 794 int num;
michael@0 795 int range;
michael@0 796 unsigned char *buf;
michael@0 797 SECStatus rv;
michael@0 798
michael@0 799 range = r2 - r1;
michael@0 800
michael@0 801 /* position to the beginning of range */
michael@0 802 fseek (fp, r1, SEEK_SET);
michael@0 803
michael@0 804 buf = (unsigned char *) PORT_ZAlloc (range);
michael@0 805 if (buf == NULL)
michael@0 806 out_of_memory();
michael@0 807
michael@0 808 if ((num = fread (buf, 1, range, fp)) != range) {
michael@0 809 PR_fprintf(errorFD, "%s: expected %d bytes, got %d\n", PROGRAM_NAME,
michael@0 810 range, num);
michael@0 811 errorCount++;
michael@0 812 exit (ERRX);
michael@0 813 }
michael@0 814
michael@0 815 rv = PK11_HashBuf(SEC_OID_MD5, dig->md5, buf, range);
michael@0 816 if (rv == SECSuccess) {
michael@0 817 rv =PK11_HashBuf(SEC_OID_SHA1, dig->sha1, buf, range);
michael@0 818 }
michael@0 819 if (rv != SECSuccess) {
michael@0 820 PR_fprintf(errorFD, "%s: can't generate digest context\n",
michael@0 821 PROGRAM_NAME);
michael@0 822 errorCount++;
michael@0 823 exit (ERRX);
michael@0 824 }
michael@0 825
michael@0 826 PORT_Free (buf);
michael@0 827
michael@0 828 return 0;
michael@0 829 }
michael@0 830
michael@0 831
michael@0 832 static void SignOut (void *arg, const char *buf, unsigned long len)
michael@0 833 {
michael@0 834 fwrite (buf, len, 1, (FILE * ) arg);
michael@0 835 }
michael@0 836
michael@0 837

mercurial