Bug Summary

File:s/cmd/signtool/sign.c
Warning:line 847, column 16
The 1st argument to 'fread' is NULL but should not be NULL

Annotated Source Code

Press '?' to see keyboard shortcuts

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