Bug Summary

File:s/cmd/signtool/sign.c
Warning:line 768, column 24
Null pointer passed to 1st parameter expecting 'nonnull'

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