Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 }