1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/signtool/sign.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,837 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "signtool.h" 1.9 +#include "zip.h" 1.10 +#include "prmem.h" 1.11 +#include "blapi.h" 1.12 +#include "sechash.h" /* for HASH_GetHashObject() */ 1.13 + 1.14 +static int create_pk7 (char *dir, char *keyName, int *keyType); 1.15 +static int jar_find_key_type (CERTCertificate *cert); 1.16 +static int manifesto (char *dirname, char *install_script, PRBool recurse); 1.17 +static int manifesto_fn(char *relpath, char *basedir, char *reldir, 1.18 + char *filename, void *arg); 1.19 +static int manifesto_xpi_fn(char *relpath, char *basedir, char *reldir, 1.20 + char *filename, void *arg); 1.21 +static int sign_all_arc_fn(char *relpath, char *basedir, char *reldir, 1.22 + char *filename, void *arg); 1.23 +static int add_meta (FILE *fp, char *name); 1.24 +static int SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert); 1.25 +static int generate_SF_file (char *manifile, char *who); 1.26 +static int calculate_MD5_range (FILE *fp, long r1, long r2, 1.27 + JAR_Digest *dig); 1.28 +static void SignOut (void *arg, const char *buf, unsigned long len); 1.29 + 1.30 +static char *metafile = NULL; 1.31 +static int optimize = 0; 1.32 +static FILE *mf; 1.33 +static ZIPfile *zipfile = NULL; 1.34 + 1.35 +/* 1.36 + * S i g n A r c h i v e 1.37 + * 1.38 + * Sign an individual archive tree. A directory 1.39 + * called META-INF is created underneath this. 1.40 + * 1.41 + */ 1.42 +int 1.43 +SignArchive(char *tree, char *keyName, char *zip_file, int javascript, 1.44 + char *meta_file, char *install_script, int _optimize, PRBool recurse) 1.45 +{ 1.46 + int status; 1.47 + char tempfn [FNSIZE], fullfn [FNSIZE]; 1.48 + int keyType = rsaKey; 1.49 + 1.50 + metafile = meta_file; 1.51 + optimize = _optimize; 1.52 + 1.53 + /* To create XPI compatible Archive manifesto() must be run before 1.54 + * the zipfile is opened. This is so the signed files are not added 1.55 + * the archive before the crucial rsa/dsa file*/ 1.56 + if (xpi_arc) { 1.57 + manifesto (tree, install_script, recurse); 1.58 + } 1.59 + 1.60 + if (zip_file) { 1.61 + zipfile = JzipOpen(zip_file, NULL /*no comment*/); 1.62 + } 1.63 + 1.64 + /*Sign and add files to the archive normally with manifesto()*/ 1.65 + if (!xpi_arc) { 1.66 + manifesto (tree, install_script, recurse); 1.67 + } 1.68 + 1.69 + if (keyName) { 1.70 + status = create_pk7 (tree, keyName, &keyType); 1.71 + if (status < 0) { 1.72 + PR_fprintf(errorFD, "the tree \"%s\" was NOT SUCCESSFULLY SIGNED\n", 1.73 + tree); 1.74 + errorCount++; 1.75 + exit (ERRX); 1.76 + } 1.77 + } 1.78 + 1.79 + /* Add the rsa/dsa file as the first file in the archive. This is crucial 1.80 + * for a XPInstall compatible archive */ 1.81 + if (xpi_arc) { 1.82 + if (verbosity >= 0) { 1.83 + PR_fprintf(outputFD, "%s \n", XPI_TEXT); 1.84 + } 1.85 + 1.86 + /* rsa/dsa to zip */ 1.87 + sprintf (tempfn, "META-INF/%s.%s", base, (keyType == dsaKey ? 1.88 + "dsa" : "rsa")); 1.89 + sprintf (fullfn, "%s/%s", tree, tempfn); 1.90 + JzipAdd(fullfn, tempfn, zipfile, compression_level); 1.91 + 1.92 + /* Loop through all files & subdirectories, add to archive */ 1.93 + foreach (tree, "", manifesto_xpi_fn, recurse, PR_FALSE /*include dirs */, 1.94 + (void * )NULL); 1.95 + } 1.96 + /* mf to zip */ 1.97 + strcpy (tempfn, "META-INF/manifest.mf"); 1.98 + sprintf (fullfn, "%s/%s", tree, tempfn); 1.99 + JzipAdd(fullfn, tempfn, zipfile, compression_level); 1.100 + 1.101 + /* sf to zip */ 1.102 + sprintf (tempfn, "META-INF/%s.sf", base); 1.103 + sprintf (fullfn, "%s/%s", tree, tempfn); 1.104 + JzipAdd(fullfn, tempfn, zipfile, compression_level); 1.105 + 1.106 + /* Add the rsa/dsa file to the zip archive normally */ 1.107 + if (!xpi_arc) { 1.108 + /* rsa/dsa to zip */ 1.109 + sprintf (tempfn, "META-INF/%s.%s", base, (keyType == dsaKey ? 1.110 + "dsa" : "rsa")); 1.111 + sprintf (fullfn, "%s/%s", tree, tempfn); 1.112 + JzipAdd(fullfn, tempfn, zipfile, compression_level); 1.113 + } 1.114 + 1.115 + JzipClose(zipfile); 1.116 + 1.117 + if (verbosity >= 0) { 1.118 + if (javascript) { 1.119 + PR_fprintf(outputFD, "jarfile \"%s\" signed successfully\n", 1.120 + zip_file); 1.121 + } else { 1.122 + PR_fprintf(outputFD, "tree \"%s\" signed successfully\n", 1.123 + tree); 1.124 + } 1.125 + } 1.126 + 1.127 + return 0; 1.128 +} 1.129 + 1.130 + 1.131 +typedef struct { 1.132 + char *keyName; 1.133 + int javascript; 1.134 + char *metafile; 1.135 + char *install_script; 1.136 + int optimize; 1.137 +} SignArcInfo; 1.138 + 1.139 +/* 1.140 + * S i g n A l l A r c 1.141 + * 1.142 + * Javascript may generate multiple .arc directories, one 1.143 + * for each jar archive needed. Sign them all. 1.144 + * 1.145 + */ 1.146 +int 1.147 +SignAllArc(char *jartree, char *keyName, int javascript, char *metafile, 1.148 +char *install_script, int optimize, PRBool recurse) 1.149 +{ 1.150 + SignArcInfo info; 1.151 + 1.152 + info.keyName = keyName; 1.153 + info.javascript = javascript; 1.154 + info.metafile = metafile; 1.155 + info.install_script = install_script; 1.156 + info.optimize = optimize; 1.157 + 1.158 + return foreach(jartree, "", sign_all_arc_fn, recurse, 1.159 + PR_TRUE /*include dirs*/, (void * )&info); 1.160 +} 1.161 + 1.162 + 1.163 +static int 1.164 +sign_all_arc_fn(char *relpath, char *basedir, char *reldir, char *filename, 1.165 + void *arg) 1.166 +{ 1.167 + char *zipfile = NULL; 1.168 + char *arc = NULL, *archive = NULL; 1.169 + int retval = 0; 1.170 + SignArcInfo * infop = (SignArcInfo * )arg; 1.171 + 1.172 + /* Make sure there is one and only one ".arc" in the relative path, 1.173 + * and that it is at the end of the path (don't sign .arcs within .arcs) */ 1.174 + if ( (PL_strcaserstr(relpath, ".arc") == relpath + strlen(relpath) - 1.175 + 4) && 1.176 + (PL_strcasestr(relpath, ".arc") == relpath + strlen(relpath) - 4) ) { 1.177 + 1.178 + if (!infop) { 1.179 + PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME); 1.180 + errorCount++; 1.181 + retval = -1; 1.182 + goto finish; 1.183 + } 1.184 + archive = PR_smprintf("%s/%s", basedir, relpath); 1.185 + 1.186 + zipfile = PL_strdup(archive); 1.187 + arc = PORT_Strrchr (zipfile, '.'); 1.188 + 1.189 + if (arc == NULL) { 1.190 + PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME); 1.191 + errorCount++; 1.192 + retval = -1; 1.193 + goto finish; 1.194 + } 1.195 + 1.196 + PL_strcpy (arc, ".jar"); 1.197 + 1.198 + if (verbosity >= 0) { 1.199 + PR_fprintf(outputFD, "\nsigning: %s\n", zipfile); 1.200 + } 1.201 + retval = SignArchive(archive, infop->keyName, zipfile, 1.202 + infop->javascript, infop->metafile, infop->install_script, 1.203 + infop->optimize, PR_TRUE /* recurse */); 1.204 + } 1.205 +finish: 1.206 + if (archive) 1.207 + PR_Free(archive); 1.208 + if (zipfile) 1.209 + PR_Free(zipfile); 1.210 + 1.211 + return retval; 1.212 +} 1.213 + 1.214 + 1.215 +/********************************************************************* 1.216 + * 1.217 + * c r e a t e _ p k 7 1.218 + */ 1.219 +static int 1.220 +create_pk7 (char *dir, char *keyName, int *keyType) 1.221 +{ 1.222 + int status = 0; 1.223 + char *file_ext; 1.224 + 1.225 + CERTCertificate * cert; 1.226 + CERTCertDBHandle * db; 1.227 + 1.228 + FILE * in, *out; 1.229 + 1.230 + char sf_file [FNSIZE]; 1.231 + char pk7_file [FNSIZE]; 1.232 + 1.233 + /* open cert database */ 1.234 + db = CERT_GetDefaultCertDB(); 1.235 + 1.236 + if (db == NULL) 1.237 + return - 1; 1.238 + 1.239 + /* find cert */ 1.240 + /*cert = CERT_FindCertByNicknameOrEmailAddr(db, keyName);*/ 1.241 + cert = PK11_FindCertFromNickname(keyName, &pwdata); 1.242 + 1.243 + if (cert == NULL) { 1.244 + SECU_PrintError ( PROGRAM_NAME, 1.245 + "Cannot find the cert \"%s\"", keyName); 1.246 + return -1; 1.247 + } 1.248 + 1.249 + 1.250 + /* determine the key type, which sets the extension for pkcs7 object */ 1.251 + 1.252 + *keyType = jar_find_key_type (cert); 1.253 + file_ext = (*keyType == dsaKey) ? "dsa" : "rsa"; 1.254 + 1.255 + sprintf (sf_file, "%s/META-INF/%s.sf", dir, base); 1.256 + sprintf (pk7_file, "%s/META-INF/%s.%s", dir, base, file_ext); 1.257 + 1.258 + if ((in = fopen (sf_file, "rb")) == NULL) { 1.259 + PR_fprintf(errorFD, "%s: Can't open %s for reading\n", PROGRAM_NAME, 1.260 + sf_file); 1.261 + errorCount++; 1.262 + exit (ERRX); 1.263 + } 1.264 + 1.265 + if ((out = fopen (pk7_file, "wb")) == NULL) { 1.266 + PR_fprintf(errorFD, "%s: Can't open %s for writing\n", PROGRAM_NAME, 1.267 + sf_file); 1.268 + errorCount++; 1.269 + exit (ERRX); 1.270 + } 1.271 + 1.272 + status = SignFile (out, in, cert); 1.273 + 1.274 + CERT_DestroyCertificate (cert); 1.275 + fclose (in); 1.276 + fclose (out); 1.277 + 1.278 + if (status) { 1.279 + PR_fprintf(errorFD, "%s: PROBLEM signing data (%s)\n", 1.280 + PROGRAM_NAME, SECU_Strerror(PORT_GetError())); 1.281 + errorCount++; 1.282 + return - 1; 1.283 + } 1.284 + 1.285 + return 0; 1.286 +} 1.287 + 1.288 + 1.289 +/* 1.290 + * j a r _ f i n d _ k e y _ t y p e 1.291 + * 1.292 + * Determine the key type for a given cert, which 1.293 + * should be rsaKey or dsaKey. Any error return 0. 1.294 + * 1.295 + */ 1.296 +static int 1.297 +jar_find_key_type (CERTCertificate *cert) 1.298 +{ 1.299 + SECKEYPrivateKey * privk = NULL; 1.300 + KeyType keyType; 1.301 + 1.302 + /* determine its type */ 1.303 + privk = PK11_FindKeyByAnyCert (cert, &pwdata); 1.304 + if (privk == NULL) { 1.305 + PR_fprintf(errorFD, "warning - can't find private key for this cert\n"); 1.306 + warningCount++; 1.307 + return 0; 1.308 + } 1.309 + 1.310 + keyType = privk->keyType; 1.311 + SECKEY_DestroyPrivateKey (privk); 1.312 + return keyType; 1.313 +} 1.314 + 1.315 + 1.316 +/* 1.317 + * m a n i f e s t o 1.318 + * 1.319 + * Run once for every subdirectory in which a 1.320 + * manifest is to be created -- usually exactly once. 1.321 + * 1.322 + */ 1.323 +static int 1.324 +manifesto (char *dirname, char *install_script, PRBool recurse) 1.325 +{ 1.326 + char metadir [FNSIZE], sfname [FNSIZE]; 1.327 + 1.328 + /* Create the META-INF directory to hold signing info */ 1.329 + 1.330 + if (PR_Access (dirname, PR_ACCESS_READ_OK)) { 1.331 + PR_fprintf(errorFD, "%s: unable to read your directory: %s\n", 1.332 + PROGRAM_NAME, dirname); 1.333 + errorCount++; 1.334 + perror (dirname); 1.335 + exit (ERRX); 1.336 + } 1.337 + 1.338 + if (PR_Access (dirname, PR_ACCESS_WRITE_OK)) { 1.339 + PR_fprintf(errorFD, "%s: unable to write to your directory: %s\n", 1.340 + PROGRAM_NAME, dirname); 1.341 + errorCount++; 1.342 + perror(dirname); 1.343 + exit(ERRX); 1.344 + } 1.345 + 1.346 + sprintf (metadir, "%s/META-INF", dirname); 1.347 + 1.348 + strcpy (sfname, metadir); 1.349 + 1.350 + PR_MkDir (metadir, 0777); 1.351 + 1.352 + strcat (metadir, "/"); 1.353 + strcat (metadir, MANIFEST); 1.354 + 1.355 + if ((mf = fopen (metadir, "wb")) == NULL) { 1.356 + perror (MANIFEST); 1.357 + PR_fprintf(errorFD, "%s: Probably, the directory you are trying to" 1.358 + " sign has\n", PROGRAM_NAME); 1.359 + PR_fprintf(errorFD, "%s: permissions problems or may not exist.\n", 1.360 + PROGRAM_NAME); 1.361 + errorCount++; 1.362 + exit (ERRX); 1.363 + } 1.364 + 1.365 + if (verbosity >= 0) { 1.366 + PR_fprintf(outputFD, "Generating %s file..\n", metadir); 1.367 + } 1.368 + 1.369 + fprintf(mf, "Manifest-Version: 1.0\n"); 1.370 + fprintf (mf, "Created-By: %s\n", CREATOR); 1.371 + fprintf (mf, "Comments: %s\n", BREAKAGE); 1.372 + 1.373 + if (scriptdir) { 1.374 + fprintf (mf, "Comments: --\n"); 1.375 + fprintf (mf, "Comments: --\n"); 1.376 + fprintf (mf, "Comments: -- This archive signs Javascripts which may not necessarily\n"); 1.377 + fprintf (mf, "Comments: -- be included in the physical jar file.\n"); 1.378 + fprintf (mf, "Comments: --\n"); 1.379 + fprintf (mf, "Comments: --\n"); 1.380 + } 1.381 + 1.382 + if (install_script) 1.383 + fprintf (mf, "Install-Script: %s\n", install_script); 1.384 + 1.385 + if (metafile) 1.386 + add_meta (mf, "+"); 1.387 + 1.388 + /* Loop through all files & subdirectories */ 1.389 + foreach (dirname, "", manifesto_fn, recurse, PR_FALSE /*include dirs */, 1.390 + (void * )NULL); 1.391 + 1.392 + fclose (mf); 1.393 + 1.394 + strcat (sfname, "/"); 1.395 + strcat (sfname, base); 1.396 + strcat (sfname, ".sf"); 1.397 + 1.398 + if (verbosity >= 0) { 1.399 + PR_fprintf(outputFD, "Generating %s.sf file..\n", base); 1.400 + } 1.401 + generate_SF_file (metadir, sfname); 1.402 + 1.403 + return 0; 1.404 +} 1.405 + 1.406 + 1.407 +/* 1.408 + * m a n i f e s t o _ x p i _ f n 1.409 + * 1.410 + * Called by pointer from SignArchive(), once for 1.411 + * each file within the directory. This function 1.412 + * is only used for adding to XPI compatible archive 1.413 + * 1.414 + */ 1.415 +static int manifesto_xpi_fn 1.416 +(char *relpath, char *basedir, char *reldir, char *filename, void *arg) 1.417 +{ 1.418 + char fullname [FNSIZE]; 1.419 + 1.420 + if (verbosity >= 0) { 1.421 + PR_fprintf(outputFD, "--> %s\n", relpath); 1.422 + } 1.423 + 1.424 + /* extension matching */ 1.425 + if (extensionsGiven) { 1.426 + char *ext = PL_strrchr(relpath, '.'); 1.427 + if (!ext) 1.428 + return 0; 1.429 + if (!PL_HashTableLookup(extensions, ext)) 1.430 + return 0; 1.431 + } 1.432 + sprintf (fullname, "%s/%s", basedir, relpath); 1.433 + JzipAdd(fullname, relpath, zipfile, compression_level); 1.434 + 1.435 + return 0; 1.436 +} 1.437 + 1.438 + 1.439 +/* 1.440 + * m a n i f e s t o _ f n 1.441 + * 1.442 + * Called by pointer from manifesto(), once for 1.443 + * each file within the directory. 1.444 + * 1.445 + */ 1.446 +static int manifesto_fn 1.447 +(char *relpath, char *basedir, char *reldir, char *filename, void *arg) 1.448 +{ 1.449 + int use_js; 1.450 + 1.451 + JAR_Digest dig; 1.452 + char fullname [FNSIZE]; 1.453 + 1.454 + if (verbosity >= 0) { 1.455 + PR_fprintf(outputFD, "--> %s\n", relpath); 1.456 + } 1.457 + 1.458 + /* extension matching */ 1.459 + if (extensionsGiven) { 1.460 + char *ext = PL_strrchr(relpath, '.'); 1.461 + if (!ext) 1.462 + return 0; 1.463 + if (!PL_HashTableLookup(extensions, ext)) 1.464 + return 0; 1.465 + } 1.466 + 1.467 + sprintf (fullname, "%s/%s", basedir, relpath); 1.468 + 1.469 + fprintf (mf, "\n"); 1.470 + 1.471 + use_js = 0; 1.472 + 1.473 + if (scriptdir && !PORT_Strcmp (scriptdir, reldir)) 1.474 + use_js++; 1.475 + 1.476 + /* sign non-.js files inside .arc directories using the javascript magic */ 1.477 + 1.478 + if ( (PL_strcaserstr(filename, ".js") != filename + strlen(filename) - 3) 1.479 + && (PL_strcaserstr(reldir, ".arc") == reldir + strlen(filename) - 4)) 1.480 + use_js++; 1.481 + 1.482 + if (use_js) { 1.483 + fprintf (mf, "Name: %s\n", filename); 1.484 + fprintf (mf, "Magic: javascript\n"); 1.485 + 1.486 + if (optimize == 0) 1.487 + fprintf (mf, "javascript.id: %s\n", filename); 1.488 + 1.489 + if (metafile) 1.490 + add_meta (mf, filename); 1.491 + } else { 1.492 + fprintf (mf, "Name: %s\n", relpath); 1.493 + if (metafile) 1.494 + add_meta (mf, relpath); 1.495 + } 1.496 + 1.497 + JAR_digest_file (fullname, &dig); 1.498 + 1.499 + 1.500 + if (optimize == 0) { 1.501 + fprintf (mf, "Digest-Algorithms: MD5 SHA1\n"); 1.502 + fprintf (mf, "MD5-Digest: %s\n", BTOA_DataToAscii (dig.md5, 1.503 + MD5_LENGTH)); 1.504 + } 1.505 + 1.506 + fprintf (mf, "SHA1-Digest: %s\n", BTOA_DataToAscii (dig.sha1, SHA1_LENGTH)); 1.507 + 1.508 + if (!use_js) { 1.509 + JzipAdd(fullname, relpath, zipfile, compression_level); 1.510 + } 1.511 + 1.512 + return 0; 1.513 +} 1.514 + 1.515 + 1.516 +/* 1.517 + * a d d _ m e t a 1.518 + * 1.519 + * Parse the metainfo file, and add any details 1.520 + * necessary to the manifest file. In most cases you 1.521 + * should be using the -i option (ie, for SmartUpdate). 1.522 + * 1.523 + */ 1.524 +static int add_meta (FILE *fp, char *name) 1.525 +{ 1.526 + FILE * met; 1.527 + char buf [BUFSIZ]; 1.528 + 1.529 + int place; 1.530 + char *pattern, *meta; 1.531 + 1.532 + int num = 0; 1.533 + 1.534 + if ((met = fopen (metafile, "r")) != NULL) { 1.535 + while (fgets (buf, BUFSIZ, met)) { 1.536 + char *s; 1.537 + 1.538 + for (s = buf; *s && *s != '\n' && *s != '\r'; s++) 1.539 + ; 1.540 + *s = 0; 1.541 + 1.542 + if (*buf == 0) 1.543 + continue; 1.544 + 1.545 + pattern = buf; 1.546 + 1.547 + /* skip to whitespace */ 1.548 + for (s = buf; *s && *s != ' ' && *s != '\t'; s++) 1.549 + ; 1.550 + 1.551 + /* terminate pattern */ 1.552 + if (*s == ' ' || *s == '\t') 1.553 + *s++ = 0; 1.554 + 1.555 + /* eat through whitespace */ 1.556 + while (*s == ' ' || *s == '\t') 1.557 + s++; 1.558 + 1.559 + meta = s; 1.560 + 1.561 + /* this will eventually be regexp matching */ 1.562 + 1.563 + place = 0; 1.564 + if (!PORT_Strcmp (pattern, name)) 1.565 + place = 1; 1.566 + 1.567 + if (place) { 1.568 + num++; 1.569 + if (verbosity >= 0) { 1.570 + PR_fprintf(outputFD, "[%s] %s\n", name, meta); 1.571 + } 1.572 + fprintf (fp, "%s\n", meta); 1.573 + } 1.574 + } 1.575 + fclose (met); 1.576 + } else { 1.577 + PR_fprintf(errorFD, "%s: can't open metafile: %s\n", PROGRAM_NAME, 1.578 + metafile); 1.579 + errorCount++; 1.580 + exit (ERRX); 1.581 + } 1.582 + 1.583 + return num; 1.584 +} 1.585 + 1.586 + 1.587 +/********************************************************************** 1.588 + * 1.589 + * S i g n F i l e 1.590 + */ 1.591 +static int 1.592 +SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert) 1.593 +{ 1.594 + int nb; 1.595 + char ibuf[4096], digestdata[32]; 1.596 + const SECHashObject *hashObj; 1.597 + void *hashcx; 1.598 + unsigned int len; 1.599 + 1.600 + SECItem digest; 1.601 + SEC_PKCS7ContentInfo * cinfo; 1.602 + SECStatus rv; 1.603 + 1.604 + if (outFile == NULL || inFile == NULL || cert == NULL) 1.605 + return - 1; 1.606 + 1.607 + /* XXX probably want to extend interface to allow other hash algorithms */ 1.608 + hashObj = HASH_GetHashObject(HASH_AlgSHA1); 1.609 + 1.610 + hashcx = (*hashObj->create)(); 1.611 + if (hashcx == NULL) 1.612 + return - 1; 1.613 + 1.614 + (*hashObj->begin)(hashcx); 1.615 + 1.616 + for (; ; ) { 1.617 + if (feof(inFile)) 1.618 + break; 1.619 + nb = fread(ibuf, 1, sizeof(ibuf), inFile); 1.620 + if (nb == 0) { 1.621 + if (ferror(inFile)) { 1.622 + PORT_SetError(SEC_ERROR_IO); 1.623 + (*hashObj->destroy)(hashcx, PR_TRUE); 1.624 + return - 1; 1.625 + } 1.626 + /* eof */ 1.627 + break; 1.628 + } 1.629 + (*hashObj->update)(hashcx, (unsigned char *) ibuf, nb); 1.630 + } 1.631 + 1.632 + (*hashObj->end)(hashcx, (unsigned char *) digestdata, &len, 32); 1.633 + (*hashObj->destroy)(hashcx, PR_TRUE); 1.634 + 1.635 + digest.data = (unsigned char *) digestdata; 1.636 + digest.len = len; 1.637 + 1.638 + cinfo = SEC_PKCS7CreateSignedData 1.639 + (cert, certUsageObjectSigner, NULL, 1.640 + SEC_OID_SHA1, &digest, NULL, NULL); 1.641 + 1.642 + if (cinfo == NULL) 1.643 + return - 1; 1.644 + 1.645 + rv = SEC_PKCS7IncludeCertChain (cinfo, NULL); 1.646 + if (rv != SECSuccess) { 1.647 + SEC_PKCS7DestroyContentInfo (cinfo); 1.648 + return - 1; 1.649 + } 1.650 + 1.651 + if (no_time == 0) { 1.652 + rv = SEC_PKCS7AddSigningTime (cinfo); 1.653 + if (rv != SECSuccess) { 1.654 + /* don't check error */ 1.655 + } 1.656 + } 1.657 + 1.658 + rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL, NULL, &pwdata); 1.659 + 1.660 + SEC_PKCS7DestroyContentInfo (cinfo); 1.661 + 1.662 + if (rv != SECSuccess) 1.663 + return - 1; 1.664 + 1.665 + return 0; 1.666 +} 1.667 + 1.668 + 1.669 +/* 1.670 + * g e n e r a t e _ S F _ f i l e 1.671 + * 1.672 + * From the supplied manifest file, calculates 1.673 + * digests on the various sections, creating a .SF 1.674 + * file in the process. 1.675 + * 1.676 + */ 1.677 +static int generate_SF_file (char *manifile, char *who) 1.678 +{ 1.679 + FILE * sf; 1.680 + FILE * mf; 1.681 + long r1, r2, r3; 1.682 + char whofile [FNSIZE]; 1.683 + char *buf, *name = NULL; 1.684 + JAR_Digest dig; 1.685 + int line = 0; 1.686 + 1.687 + strcpy (whofile, who); 1.688 + 1.689 + if ((mf = fopen (manifile, "rb")) == NULL) { 1.690 + perror (manifile); 1.691 + exit (ERRX); 1.692 + } 1.693 + 1.694 + if ((sf = fopen (whofile, "wb")) == NULL) { 1.695 + perror (who); 1.696 + exit (ERRX); 1.697 + } 1.698 + 1.699 + buf = (char *) PORT_ZAlloc (BUFSIZ); 1.700 + 1.701 + if (buf) 1.702 + name = (char *) PORT_ZAlloc (BUFSIZ); 1.703 + 1.704 + if (buf == NULL || name == NULL) 1.705 + out_of_memory(); 1.706 + 1.707 + fprintf (sf, "Signature-Version: 1.0\n"); 1.708 + fprintf (sf, "Created-By: %s\n", CREATOR); 1.709 + fprintf (sf, "Comments: %s\n", BREAKAGE); 1.710 + 1.711 + if (fgets (buf, BUFSIZ, mf) == NULL) { 1.712 + PR_fprintf(errorFD, "%s: empty manifest file!\n", PROGRAM_NAME); 1.713 + errorCount++; 1.714 + exit (ERRX); 1.715 + } 1.716 + 1.717 + if (strncmp (buf, "Manifest-Version:", 17)) { 1.718 + PR_fprintf(errorFD, "%s: not a manifest file!\n", PROGRAM_NAME); 1.719 + errorCount++; 1.720 + exit (ERRX); 1.721 + } 1.722 + 1.723 + fseek (mf, 0L, SEEK_SET); 1.724 + 1.725 + /* Process blocks of headers, and calculate their hashen */ 1.726 + 1.727 + while (1) { 1.728 + /* Beginning range */ 1.729 + r1 = ftell (mf); 1.730 + 1.731 + if (fgets (name, BUFSIZ, mf) == NULL) 1.732 + break; 1.733 + 1.734 + line++; 1.735 + 1.736 + if (r1 != 0 && strncmp (name, "Name:", 5)) { 1.737 + PR_fprintf(errorFD, 1.738 + "warning: unexpected input in manifest file \"%s\" at line %d:\n", 1.739 + manifile, line); 1.740 + PR_fprintf(errorFD, "%s\n", name); 1.741 + warningCount++; 1.742 + } 1.743 + 1.744 + r2 = r1; 1.745 + while (fgets (buf, BUFSIZ, mf)) { 1.746 + if (*buf == 0 || *buf == '\n' || *buf == '\r') 1.747 + break; 1.748 + 1.749 + line++; 1.750 + 1.751 + /* Ending range for hashing */ 1.752 + r2 = ftell (mf); 1.753 + } 1.754 + 1.755 + r3 = ftell (mf); 1.756 + 1.757 + if (r1) { 1.758 + fprintf (sf, "\n"); 1.759 + fprintf (sf, "%s", name); 1.760 + } 1.761 + 1.762 + calculate_MD5_range (mf, r1, r2, &dig); 1.763 + 1.764 + if (optimize == 0) { 1.765 + fprintf (sf, "Digest-Algorithms: MD5 SHA1\n"); 1.766 + fprintf (sf, "MD5-Digest: %s\n", 1.767 + BTOA_DataToAscii (dig.md5, MD5_LENGTH)); 1.768 + } 1.769 + 1.770 + fprintf (sf, "SHA1-Digest: %s\n", 1.771 + BTOA_DataToAscii (dig.sha1, SHA1_LENGTH)); 1.772 + 1.773 + /* restore normalcy after changing offset position */ 1.774 + fseek (mf, r3, SEEK_SET); 1.775 + } 1.776 + 1.777 + PORT_Free (buf); 1.778 + PORT_Free (name); 1.779 + 1.780 + fclose (sf); 1.781 + fclose (mf); 1.782 + 1.783 + return 0; 1.784 +} 1.785 + 1.786 + 1.787 +/* 1.788 + * c a l c u l a t e _ M D 5 _ r a n g e 1.789 + * 1.790 + * Calculate the MD5 digest on a range of bytes in 1.791 + * the specified fopen'd file. Returns base64. 1.792 + * 1.793 + */ 1.794 +static int 1.795 +calculate_MD5_range (FILE *fp, long r1, long r2, JAR_Digest *dig) 1.796 +{ 1.797 + int num; 1.798 + int range; 1.799 + unsigned char *buf; 1.800 + SECStatus rv; 1.801 + 1.802 + range = r2 - r1; 1.803 + 1.804 + /* position to the beginning of range */ 1.805 + fseek (fp, r1, SEEK_SET); 1.806 + 1.807 + buf = (unsigned char *) PORT_ZAlloc (range); 1.808 + if (buf == NULL) 1.809 + out_of_memory(); 1.810 + 1.811 + if ((num = fread (buf, 1, range, fp)) != range) { 1.812 + PR_fprintf(errorFD, "%s: expected %d bytes, got %d\n", PROGRAM_NAME, 1.813 + range, num); 1.814 + errorCount++; 1.815 + exit (ERRX); 1.816 + } 1.817 + 1.818 + rv = PK11_HashBuf(SEC_OID_MD5, dig->md5, buf, range); 1.819 + if (rv == SECSuccess) { 1.820 + rv =PK11_HashBuf(SEC_OID_SHA1, dig->sha1, buf, range); 1.821 + } 1.822 + if (rv != SECSuccess) { 1.823 + PR_fprintf(errorFD, "%s: can't generate digest context\n", 1.824 + PROGRAM_NAME); 1.825 + errorCount++; 1.826 + exit (ERRX); 1.827 + } 1.828 + 1.829 + PORT_Free (buf); 1.830 + 1.831 + return 0; 1.832 +} 1.833 + 1.834 + 1.835 +static void SignOut (void *arg, const char *buf, unsigned long len) 1.836 +{ 1.837 + fwrite (buf, len, 1, (FILE * ) arg); 1.838 +} 1.839 + 1.840 +