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.

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

mercurial