~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/cmd/signtool/sign.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
4
 * The contents of this file are subject to the Mozilla Public License Version
 
5
 * 1.1 (the "License"); you may not use this file except in compliance with
 
6
 * the License. You may obtain a copy of the License at
 
7
 * http://www.mozilla.org/MPL/
 
8
 *
 
9
 * Software distributed under the License is distributed on an "AS IS" basis,
 
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
11
 * for the specific language governing rights and limitations under the
 
12
 * License.
 
13
 *
 
14
 * The Original Code is the Netscape security libraries.
 
15
 *
 
16
 * The Initial Developer of the Original Code is
 
17
 * Netscape Communications Corporation.
 
18
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 
19
 * the Initial Developer. All Rights Reserved.
 
20
 *
 
21
 * Contributor(s):
 
22
 *
 
23
 * Alternatively, the contents of this file may be used under the terms of
 
24
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
25
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
26
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
27
 * of those above. If you wish to allow use of your version of this file only
 
28
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
29
 * use your version of this file under the terms of the MPL, indicate your
 
30
 * decision by deleting the provisions above and replace them with the notice
 
31
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
32
 * the provisions above, a recipient may use your version of this file under
 
33
 * the terms of any one of the MPL, the GPL or the LGPL.
 
34
 *
 
35
 * ***** END LICENSE BLOCK ***** */
 
36
 
 
37
#include "signtool.h"
 
38
#include "zip.h" 
 
39
#include "prmem.h"
 
40
#include "blapi.h"
 
41
#include "sechash.h"    /* for HASH_GetHashObject() */
 
42
 
 
43
static int      create_pk7 (char *dir, char *keyName, int *keyType);
 
44
static int      jar_find_key_type (CERTCertificate *cert);
 
45
static int      manifesto (char *dirname, char *install_script, PRBool recurse);
 
46
static int      manifesto_fn(char *relpath, char *basedir, char *reldir,
 
47
                        char *filename, void *arg);
 
48
static int      manifesto_xpi_fn(char *relpath, char *basedir, char *reldir,
 
49
                        char *filename, void *arg);
 
50
static int      sign_all_arc_fn(char *relpath, char *basedir, char *reldir,
 
51
                        char *filename, void *arg);
 
52
static int      add_meta (FILE *fp, char *name);
 
53
static int      SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert);
 
54
static int      generate_SF_file (char *manifile, char *who);
 
55
static int      calculate_MD5_range (FILE *fp, long r1, long r2, 
 
56
                        JAR_Digest *dig);
 
57
static void     SignOut (void *arg, const char *buf, unsigned long len);
 
58
 
 
59
static char     *metafile = NULL;
 
60
static int      optimize = 0;
 
61
static FILE *mf;
 
62
static ZIPfile *zipfile = NULL;
 
63
 
 
64
/* 
 
65
 *  S i g n A r c h i v e
 
66
 *
 
67
 *  Sign an individual archive tree. A directory 
 
68
 *  called META-INF is created underneath this.
 
69
 *
 
70
 */
 
71
int
 
72
SignArchive(char *tree, char *keyName, char *zip_file, int javascript,
 
73
        char *meta_file, char *install_script, int _optimize, PRBool recurse)
 
74
{
 
75
    int status;
 
76
    char        tempfn [FNSIZE], fullfn [FNSIZE];
 
77
    int keyType = rsaKey;
 
78
 
 
79
    metafile = meta_file;
 
80
    optimize = _optimize;
 
81
 
 
82
    /* To create XPI compatible Archive manifesto() must be run before 
 
83
     * the zipfile is opened. This is so the signed files are not added
 
84
     * the archive before the crucial rsa/dsa file*/
 
85
    if (xpi_arc) {
 
86
        manifesto (tree, install_script, recurse);
 
87
    }
 
88
 
 
89
    if (zip_file) {
 
90
        zipfile = JzipOpen(zip_file, NULL /*no comment*/);
 
91
    }
 
92
 
 
93
    /*Sign and add files to the archive normally with manifesto()*/
 
94
    if (!xpi_arc) {
 
95
        manifesto (tree, install_script, recurse);
 
96
    }
 
97
 
 
98
    if (keyName) {
 
99
        status = create_pk7 (tree, keyName, &keyType);
 
100
        if (status < 0) {
 
101
            PR_fprintf(errorFD, "the tree \"%s\" was NOT SUCCESSFULLY SIGNED\n",
 
102
                 tree);
 
103
            errorCount++;
 
104
            exit (ERRX);
 
105
        }
 
106
    }
 
107
 
 
108
    /* Add the rsa/dsa file as the first file in the archive. This is crucial
 
109
     * for a XPInstall compatible archive */
 
110
    if (xpi_arc) {
 
111
        if (verbosity >= 0) {
 
112
            PR_fprintf(outputFD, "%s \n", XPI_TEXT);
 
113
        }
 
114
 
 
115
        /* rsa/dsa to zip */
 
116
        sprintf (tempfn, "META-INF/%s.%s", base, (keyType == dsaKey ?
 
117
            "dsa" : "rsa"));
 
118
        sprintf (fullfn, "%s/%s", tree, tempfn);
 
119
        JzipAdd(fullfn, tempfn, zipfile, compression_level);
 
120
 
 
121
        /* Loop through all files & subdirectories, add to archive */
 
122
        foreach (tree, "", manifesto_xpi_fn, recurse, PR_FALSE /*include dirs */,
 
123
                        (void * )NULL);
 
124
    }
 
125
    /* mf to zip */
 
126
    strcpy (tempfn, "META-INF/manifest.mf");
 
127
    sprintf (fullfn, "%s/%s", tree, tempfn);
 
128
    JzipAdd(fullfn, tempfn, zipfile, compression_level);
 
129
 
 
130
    /* sf to zip */
 
131
    sprintf (tempfn, "META-INF/%s.sf", base);
 
132
    sprintf (fullfn, "%s/%s", tree, tempfn);
 
133
    JzipAdd(fullfn, tempfn, zipfile, compression_level);
 
134
 
 
135
    /* Add the rsa/dsa file to the zip archive normally */
 
136
    if (!xpi_arc) {
 
137
        /* rsa/dsa to zip */
 
138
        sprintf (tempfn, "META-INF/%s.%s", base, (keyType == dsaKey ?
 
139
            "dsa" : "rsa"));
 
140
        sprintf (fullfn, "%s/%s", tree, tempfn);
 
141
        JzipAdd(fullfn, tempfn, zipfile, compression_level);
 
142
    }
 
143
 
 
144
    JzipClose(zipfile);
 
145
 
 
146
    if (verbosity >= 0) {
 
147
        if (javascript) {
 
148
            PR_fprintf(outputFD, "jarfile \"%s\" signed successfully\n",
 
149
                                                zip_file);
 
150
        } else {
 
151
            PR_fprintf(outputFD, "tree \"%s\" signed successfully\n",
 
152
                 tree);
 
153
        }
 
154
    }
 
155
 
 
156
    return 0;
 
157
}
 
158
 
 
159
 
 
160
typedef struct {
 
161
    char        *keyName;
 
162
    int javascript;
 
163
    char        *metafile;
 
164
    char        *install_script;
 
165
    int optimize;
 
166
} SignArcInfo;
 
167
 
 
168
/* 
 
169
 *  S i g n A l l A r c
 
170
 *
 
171
 *  Javascript may generate multiple .arc directories, one
 
172
 *  for each jar archive needed. Sign them all.
 
173
 *
 
174
 */
 
175
int
 
176
SignAllArc(char *jartree, char *keyName, int javascript, char *metafile,
 
177
char *install_script, int optimize, PRBool recurse)
 
178
{
 
179
    SignArcInfo info;
 
180
 
 
181
    info.keyName = keyName;
 
182
    info.javascript = javascript;
 
183
    info.metafile = metafile;
 
184
    info.install_script = install_script;
 
185
    info.optimize = optimize;
 
186
 
 
187
    return foreach(jartree, "", sign_all_arc_fn, recurse,
 
188
        PR_TRUE /*include dirs*/, (void * )&info);
 
189
}
 
190
 
 
191
 
 
192
static int      
 
193
sign_all_arc_fn(char *relpath, char *basedir, char *reldir, char *filename,
 
194
        void *arg)
 
195
{
 
196
    char        *zipfile = NULL;
 
197
    char        *arc = NULL, *archive = NULL;
 
198
    int retval = 0;
 
199
    SignArcInfo * infop = (SignArcInfo * )arg;
 
200
 
 
201
    /* Make sure there is one and only one ".arc" in the relative path, 
 
202
     * and that it is at the end of the path (don't sign .arcs within .arcs) */
 
203
    if ( (PL_strcaserstr(relpath, ".arc") == relpath + strlen(relpath) -
 
204
        4) && 
 
205
        (PL_strcasestr(relpath, ".arc") == relpath + strlen(relpath) - 4) ) {
 
206
 
 
207
        if (!infop) {
 
208
            PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME);
 
209
            errorCount++;
 
210
            retval = -1;
 
211
            goto finish;
 
212
        }
 
213
        archive = PR_smprintf("%s/%s", basedir, relpath);
 
214
 
 
215
        zipfile = PL_strdup(archive);
 
216
        arc = PORT_Strrchr (zipfile, '.');
 
217
 
 
218
        if (arc == NULL) {
 
219
            PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME);
 
220
            errorCount++;
 
221
            retval = -1;
 
222
            goto finish;
 
223
        }
 
224
 
 
225
        PL_strcpy (arc, ".jar");
 
226
 
 
227
        if (verbosity >= 0) {
 
228
            PR_fprintf(outputFD, "\nsigning: %s\n", zipfile);
 
229
        }
 
230
        retval = SignArchive(archive, infop->keyName, zipfile,
 
231
            infop->javascript, infop->metafile, infop->install_script,
 
232
                                infop->optimize, PR_TRUE /* recurse */);
 
233
    }
 
234
finish:
 
235
    if (archive) 
 
236
        PR_Free(archive);
 
237
    if (zipfile) 
 
238
        PR_Free(zipfile);
 
239
 
 
240
    return retval;
 
241
}
 
242
 
 
243
 
 
244
/*********************************************************************
 
245
 *
 
246
 * c r e a t e _ p k 7
 
247
 */
 
248
static int      
 
249
create_pk7 (char *dir, char *keyName, int *keyType)
 
250
{
 
251
    int status = 0;
 
252
    char        *file_ext;
 
253
 
 
254
    CERTCertificate * cert;
 
255
    CERTCertDBHandle * db;
 
256
 
 
257
    FILE * in, *out;
 
258
 
 
259
    char        sf_file [FNSIZE];
 
260
    char        pk7_file [FNSIZE];
 
261
 
 
262
    /* open cert database */
 
263
    db = CERT_GetDefaultCertDB();
 
264
 
 
265
    if (db == NULL)
 
266
        return - 1;
 
267
 
 
268
    /* find cert */
 
269
    /*cert = CERT_FindCertByNicknameOrEmailAddr(db, keyName);*/
 
270
    cert = PK11_FindCertFromNickname(keyName, NULL /*wincx*/);
 
271
 
 
272
    if (cert == NULL) {
 
273
        SECU_PrintError ( PROGRAM_NAME,
 
274
            "the cert \"%s\" does not exist in the database", keyName);
 
275
        return -1;
 
276
    }
 
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 = (*keyType == dsaKey) ? "dsa" : "rsa";
 
283
 
 
284
    sprintf (sf_file, "%s/META-INF/%s.sf", dir, base);
 
285
    sprintf (pk7_file, "%s/META-INF/%s.%s", dir, base, file_ext);
 
286
 
 
287
    if ((in = fopen (sf_file, "rb")) == NULL) {
 
288
        PR_fprintf(errorFD, "%s: Can't open %s for reading\n", PROGRAM_NAME,
 
289
             sf_file);
 
290
        errorCount++;
 
291
        exit (ERRX);
 
292
    }
 
293
 
 
294
    if ((out = fopen (pk7_file, "wb")) == NULL) {
 
295
        PR_fprintf(errorFD, "%s: Can't open %s for writing\n", PROGRAM_NAME,
 
296
             sf_file);
 
297
        errorCount++;
 
298
        exit (ERRX);
 
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, SECU_ErrorString ((int16) PORT_GetError()));
 
310
        errorCount++;
 
311
        return - 1;
 
312
    }
 
313
 
 
314
    return 0;
 
315
}
 
316
 
 
317
 
 
318
/*
 
319
 *  j a r _ f i n d _ k e y _ t y p e
 
320
 * 
 
321
 *  Determine the key type for a given cert, which 
 
322
 * should be rsaKey or dsaKey. Any error return 0.
 
323
 *
 
324
 */
 
325
static int      
 
326
jar_find_key_type (CERTCertificate *cert)
 
327
{
 
328
    PK11SlotInfo * slot = NULL;
 
329
    SECKEYPrivateKey * privk = NULL;
 
330
    KeyType keyType;
 
331
 
 
332
    /* determine its type */
 
333
    PK11_FindObjectForCert (cert, /*wincx*/ NULL, &slot);
 
334
 
 
335
    if (slot == NULL) {
 
336
        PR_fprintf(errorFD, "warning - can't find slot for this cert\n");
 
337
        warningCount++;
 
338
        return 0;
 
339
    }
 
340
 
 
341
    privk = PK11_FindPrivateKeyFromCert (slot, cert, /*wincx*/ NULL);
 
342
    PK11_FreeSlot (slot);
 
343
 
 
344
    if (privk == NULL) {
 
345
        PR_fprintf(errorFD, "warning - can't find private key for this cert\n");
 
346
        warningCount++;
 
347
        return 0;
 
348
    }
 
349
 
 
350
    keyType = privk->keyType;
 
351
    SECKEY_DestroyPrivateKey (privk);
 
352
    return keyType;
 
353
}
 
354
 
 
355
 
 
356
/*
 
357
 *  m a n i f e s t o
 
358
 *
 
359
 *  Run once for every subdirectory in which a 
 
360
 *  manifest is to be created -- usually exactly once.
 
361
 *
 
362
 */
 
363
static int      
 
364
manifesto (char *dirname, char *install_script, PRBool recurse)
 
365
{
 
366
    char        metadir [FNSIZE], sfname [FNSIZE];
 
367
 
 
368
    /* Create the META-INF directory to hold signing info */
 
369
 
 
370
    if (PR_Access (dirname, PR_ACCESS_READ_OK)) {
 
371
        PR_fprintf(errorFD, "%s: unable to read your directory: %s\n",
 
372
             PROGRAM_NAME, dirname);
 
373
        errorCount++;
 
374
        perror (dirname);
 
375
        exit (ERRX);
 
376
    }
 
377
 
 
378
    if (PR_Access (dirname, PR_ACCESS_WRITE_OK)) {
 
379
        PR_fprintf(errorFD, "%s: unable to write to your directory: %s\n",
 
380
                                PROGRAM_NAME, dirname);
 
381
        errorCount++;
 
382
        perror(dirname);
 
383
        exit(ERRX);
 
384
    }
 
385
 
 
386
    sprintf (metadir, "%s/META-INF", dirname);
 
387
 
 
388
    strcpy (sfname, metadir);
 
389
 
 
390
    PR_MkDir (metadir, 0777);
 
391
 
 
392
    strcat (metadir, "/");
 
393
    strcat (metadir, MANIFEST);
 
394
 
 
395
    if ((mf = fopen (metadir, "wb")) == NULL) {
 
396
        perror (MANIFEST);
 
397
        PR_fprintf(errorFD, "%s: Probably, the directory you are trying to"
 
398
                            " sign has\n", PROGRAM_NAME);
 
399
        PR_fprintf(errorFD, "%s: permissions problems or may not exist.\n",
 
400
                        PROGRAM_NAME);
 
401
        errorCount++;
 
402
        exit (ERRX);
 
403
    }
 
404
 
 
405
    if (verbosity >= 0) {
 
406
        PR_fprintf(outputFD, "Generating %s file..\n", metadir);
 
407
    }
 
408
 
 
409
    fprintf(mf, "Manifest-Version: 1.0\n");
 
410
    fprintf (mf, "Created-By: %s\n", CREATOR);
 
411
    fprintf (mf, "Comments: %s\n", BREAKAGE);
 
412
 
 
413
    if (scriptdir) {
 
414
        fprintf (mf, "Comments: --\n");
 
415
        fprintf (mf, "Comments: --\n");
 
416
        fprintf (mf, "Comments: -- This archive signs Javascripts which may not necessarily\n");
 
417
        fprintf (mf, "Comments: -- be included in the physical jar file.\n");
 
418
        fprintf (mf, "Comments: --\n");
 
419
        fprintf (mf, "Comments: --\n");
 
420
    }
 
421
 
 
422
    if (install_script)
 
423
        fprintf (mf, "Install-Script: %s\n", install_script);
 
424
 
 
425
    if (metafile)
 
426
        add_meta (mf, "+");
 
427
 
 
428
    /* Loop through all files & subdirectories */
 
429
    foreach (dirname, "", manifesto_fn, recurse, PR_FALSE /*include dirs */,
 
430
                        (void * )NULL);
 
431
 
 
432
    fclose (mf);
 
433
 
 
434
    strcat (sfname, "/");
 
435
    strcat (sfname, base);
 
436
    strcat (sfname, ".sf");
 
437
 
 
438
    if (verbosity >= 0) {
 
439
        PR_fprintf(outputFD, "Generating %s.sf file..\n", base);
 
440
    }
 
441
    generate_SF_file (metadir, sfname);
 
442
 
 
443
    return 0;
 
444
}
 
445
 
 
446
 
 
447
/*
 
448
 *  m a n i f e s t o _ x p i _ f n
 
449
 *
 
450
 *  Called by pointer from SignArchive(), once for
 
451
 *  each file within the directory. This function
 
452
 *  is only used for adding to XPI compatible archive
 
453
 *
 
454
 */
 
455
static int      manifesto_xpi_fn 
 
456
(char *relpath, char *basedir, char *reldir, char *filename, void *arg)
 
457
{
 
458
    char        fullname [FNSIZE];
 
459
 
 
460
    if (verbosity >= 0) {
 
461
        PR_fprintf(outputFD, "--> %s\n", relpath);
 
462
    }
 
463
 
 
464
    /* extension matching */
 
465
    if (extensionsGiven) {
 
466
        char    *ext = PL_strrchr(relpath, '.');
 
467
        if (!ext) 
 
468
            return 0;
 
469
        if (!PL_HashTableLookup(extensions, ext)) 
 
470
            return 0;
 
471
    }
 
472
    sprintf (fullname, "%s/%s", basedir, relpath);
 
473
    JzipAdd(fullname, relpath, zipfile, compression_level);
 
474
 
 
475
    return 0;
 
476
}
 
477
 
 
478
 
 
479
/*
 
480
 *  m a n i f e s t o _ f n
 
481
 *
 
482
 *  Called by pointer from manifesto(), once for
 
483
 *  each file within the directory.
 
484
 *
 
485
 */
 
486
static int      manifesto_fn 
 
487
(char *relpath, char *basedir, char *reldir, char *filename, void *arg)
 
488
{
 
489
    int use_js;
 
490
 
 
491
    JAR_Digest dig;
 
492
    char        fullname [FNSIZE];
 
493
 
 
494
    if (verbosity >= 0) {
 
495
        PR_fprintf(outputFD, "--> %s\n", relpath);
 
496
    }
 
497
 
 
498
    /* extension matching */
 
499
    if (extensionsGiven) {
 
500
        char    *ext = PL_strrchr(relpath, '.');
 
501
        if (!ext) 
 
502
            return 0;
 
503
        if (!PL_HashTableLookup(extensions, ext)) 
 
504
            return 0;
 
505
    }
 
506
 
 
507
    sprintf (fullname, "%s/%s", basedir, relpath);
 
508
 
 
509
    fprintf (mf, "\n");
 
510
 
 
511
    use_js = 0;
 
512
 
 
513
    if (scriptdir && !PORT_Strcmp (scriptdir, reldir))
 
514
        use_js++;
 
515
 
 
516
    /* sign non-.js files inside .arc directories using the javascript magic */
 
517
 
 
518
    if ( (PL_strcaserstr(filename, ".js") != filename + strlen(filename) - 3)
 
519
         && (PL_strcaserstr(reldir, ".arc") == reldir + strlen(filename) - 4))
 
520
        use_js++;
 
521
 
 
522
    if (use_js) {
 
523
        fprintf (mf, "Name: %s\n", filename);
 
524
        fprintf (mf, "Magic: javascript\n");
 
525
 
 
526
        if (optimize == 0)
 
527
            fprintf (mf, "javascript.id: %s\n", filename);
 
528
 
 
529
        if (metafile)
 
530
            add_meta (mf, filename);
 
531
    } else {
 
532
        fprintf (mf, "Name: %s\n", relpath);
 
533
        if (metafile)
 
534
            add_meta (mf, relpath);
 
535
    }
 
536
 
 
537
    JAR_digest_file (fullname, &dig);
 
538
 
 
539
 
 
540
    if (optimize == 0) {
 
541
        fprintf (mf, "Digest-Algorithms: MD5 SHA1\n");
 
542
        fprintf (mf, "MD5-Digest: %s\n", BTOA_DataToAscii (dig.md5,
 
543
             MD5_LENGTH));
 
544
    }
 
545
 
 
546
    fprintf (mf, "SHA1-Digest: %s\n", BTOA_DataToAscii (dig.sha1, SHA1_LENGTH));
 
547
 
 
548
    if (!use_js) {
 
549
        JzipAdd(fullname, relpath, zipfile, compression_level);
 
550
    }
 
551
 
 
552
    return 0;
 
553
}
 
554
 
 
555
 
 
556
/*
 
557
 *  a d d _ m e t a
 
558
 *
 
559
 *  Parse the metainfo file, and add any details
 
560
 *  necessary to the manifest file. In most cases you
 
561
 *  should be using the -i option (ie, for SmartUpdate).
 
562
 *
 
563
 */
 
564
static int      add_meta (FILE *fp, char *name)
 
565
{
 
566
    FILE * met;
 
567
    char        buf [BUFSIZ];
 
568
 
 
569
    int place;
 
570
    char        *pattern, *meta;
 
571
 
 
572
    int num = 0;
 
573
 
 
574
    if ((met = fopen (metafile, "r")) != NULL) {
 
575
        while (fgets (buf, BUFSIZ, met)) {
 
576
            char        *s;
 
577
 
 
578
            for (s = buf; *s && *s != '\n' && *s != '\r'; s++)
 
579
                ;
 
580
            *s = 0;
 
581
 
 
582
            if (*buf == 0)
 
583
                continue;
 
584
 
 
585
            pattern = buf;
 
586
 
 
587
            /* skip to whitespace */
 
588
            for (s = buf; *s && *s != ' ' && *s != '\t'; s++)
 
589
                ;
 
590
 
 
591
            /* terminate pattern */
 
592
            if (*s == ' ' || *s == '\t') 
 
593
                *s++ = 0;
 
594
 
 
595
            /* eat through whitespace */
 
596
            while (*s == ' ' || *s == '\t') 
 
597
                s++;
 
598
 
 
599
            meta = s;
 
600
 
 
601
            /* this will eventually be regexp matching */
 
602
 
 
603
            place = 0;
 
604
            if (!PORT_Strcmp (pattern, name))
 
605
                place = 1;
 
606
 
 
607
            if (place) {
 
608
                num++;
 
609
                if (verbosity >= 0) {
 
610
                    PR_fprintf(outputFD, "[%s] %s\n", name, meta);
 
611
                }
 
612
                fprintf (fp, "%s\n", meta);
 
613
            }
 
614
        }
 
615
        fclose (met);
 
616
    } else {
 
617
        PR_fprintf(errorFD, "%s: can't open metafile: %s\n", PROGRAM_NAME,
 
618
             metafile);
 
619
        errorCount++;
 
620
        exit (ERRX);
 
621
    }
 
622
 
 
623
    return num;
 
624
}
 
625
 
 
626
 
 
627
/**********************************************************************
 
628
 *
 
629
 * S i g n F i l e
 
630
 */
 
631
static int      
 
632
SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert)
 
633
{
 
634
    int nb;
 
635
    char        ibuf[4096], digestdata[32];
 
636
    const SECHashObject *hashObj;
 
637
    void        *hashcx;
 
638
    unsigned int        len;
 
639
 
 
640
    SECItem digest;
 
641
    SEC_PKCS7ContentInfo * cinfo;
 
642
    SECStatus rv;
 
643
 
 
644
    if (outFile == NULL || inFile == NULL || cert == NULL)
 
645
        return - 1;
 
646
 
 
647
    /* XXX probably want to extend interface to allow other hash algorithms */
 
648
    hashObj = HASH_GetHashObject(HASH_AlgSHA1);
 
649
 
 
650
    hashcx = (*hashObj->create)();
 
651
    if (hashcx == NULL)
 
652
        return - 1;
 
653
 
 
654
    (*hashObj->begin)(hashcx);
 
655
 
 
656
    for (; ; ) {
 
657
        if (feof(inFile)) 
 
658
            break;
 
659
        nb = fread(ibuf, 1, sizeof(ibuf), inFile);
 
660
        if (nb == 0) {
 
661
            if (ferror(inFile)) {
 
662
                PORT_SetError(SEC_ERROR_IO);
 
663
                (*hashObj->destroy)(hashcx, PR_TRUE);
 
664
                return - 1;
 
665
            }
 
666
            /* eof */
 
667
            break;
 
668
        }
 
669
        (*hashObj->update)(hashcx, (unsigned char *) ibuf, nb);
 
670
    }
 
671
 
 
672
    (*hashObj->end)(hashcx, (unsigned char *) digestdata, &len, 32);
 
673
    (*hashObj->destroy)(hashcx, PR_TRUE);
 
674
 
 
675
    digest.data = (unsigned char *) digestdata;
 
676
    digest.len = len;
 
677
 
 
678
    cinfo = SEC_PKCS7CreateSignedData 
 
679
        (cert, certUsageObjectSigner, NULL, 
 
680
        SEC_OID_SHA1, &digest, NULL, NULL);
 
681
 
 
682
    if (cinfo == NULL)
 
683
        return - 1;
 
684
 
 
685
    rv = SEC_PKCS7IncludeCertChain (cinfo, NULL);
 
686
    if (rv != SECSuccess) {
 
687
        SEC_PKCS7DestroyContentInfo (cinfo);
 
688
        return - 1;
 
689
    }
 
690
 
 
691
    if (no_time == 0) {
 
692
        rv = SEC_PKCS7AddSigningTime (cinfo);
 
693
        if (rv != SECSuccess) {
 
694
            /* don't check error */
 
695
        }
 
696
    }
 
697
 
 
698
    if (password) {
 
699
        rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL, 
 
700
            (SECKEYGetPasswordKey) password_hardcode, NULL);
 
701
    } else {
 
702
        rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL, NULL,
 
703
                                NULL);
 
704
    }
 
705
 
 
706
 
 
707
    SEC_PKCS7DestroyContentInfo (cinfo);
 
708
 
 
709
    if (rv != SECSuccess)
 
710
        return - 1;
 
711
 
 
712
    return 0;
 
713
}
 
714
 
 
715
 
 
716
/*
 
717
 *  g e n e r a t e _ S F _ f i l e 
 
718
 *
 
719
 *  From the supplied manifest file, calculates
 
720
 *  digests on the various sections, creating a .SF
 
721
 *  file in the process.
 
722
 * 
 
723
 */
 
724
static int      generate_SF_file (char *manifile, char *who)
 
725
{
 
726
    FILE * sf;
 
727
    FILE * mf;
 
728
    long        r1, r2, r3;
 
729
    char        whofile [FNSIZE];
 
730
    char        *buf, *name = NULL;
 
731
    JAR_Digest dig;
 
732
    int line = 0;
 
733
 
 
734
    strcpy (whofile, who);
 
735
 
 
736
    if ((mf = fopen (manifile, "rb")) == NULL) {
 
737
        perror (manifile);
 
738
        exit (ERRX);
 
739
    }
 
740
 
 
741
    if ((sf = fopen (whofile, "wb")) == NULL) {
 
742
        perror (who);
 
743
        exit (ERRX);
 
744
    }
 
745
 
 
746
    buf = (char *) PORT_ZAlloc (BUFSIZ);
 
747
 
 
748
    if (buf)
 
749
        name = (char *) PORT_ZAlloc (BUFSIZ);
 
750
 
 
751
    if (buf == NULL || name == NULL)
 
752
        out_of_memory();
 
753
 
 
754
    fprintf (sf, "Signature-Version: 1.0\n");
 
755
    fprintf (sf, "Created-By: %s\n", CREATOR);
 
756
    fprintf (sf, "Comments: %s\n", BREAKAGE);
 
757
 
 
758
    if (fgets (buf, BUFSIZ, mf) == NULL) {
 
759
        PR_fprintf(errorFD, "%s: empty manifest file!\n", PROGRAM_NAME);
 
760
        errorCount++;
 
761
        exit (ERRX);
 
762
    }
 
763
 
 
764
    if (strncmp (buf, "Manifest-Version:", 17)) {
 
765
        PR_fprintf(errorFD, "%s: not a manifest file!\n", PROGRAM_NAME);
 
766
        errorCount++;
 
767
        exit (ERRX);
 
768
    }
 
769
 
 
770
    fseek (mf, 0L, SEEK_SET);
 
771
 
 
772
    /* Process blocks of headers, and calculate their hashen */
 
773
 
 
774
    while (1) {
 
775
        /* Beginning range */
 
776
        r1 = ftell (mf);
 
777
 
 
778
        if (fgets (name, BUFSIZ, mf) == NULL)
 
779
            break;
 
780
 
 
781
        line++;
 
782
 
 
783
        if (r1 != 0 && strncmp (name, "Name:", 5)) {
 
784
            PR_fprintf(errorFD, 
 
785
            "warning: unexpected input in manifest file \"%s\" at line %d:\n",
 
786
                 manifile, line);
 
787
            PR_fprintf(errorFD, "%s\n", name);
 
788
            warningCount++;
 
789
        }
 
790
 
 
791
        r2 = r1;
 
792
        while (fgets (buf, BUFSIZ, mf)) {
 
793
            if (*buf == 0 || *buf == '\n' || *buf == '\r')
 
794
                break;
 
795
 
 
796
            line++;
 
797
 
 
798
            /* Ending range for hashing */
 
799
            r2 = ftell (mf);
 
800
        }
 
801
 
 
802
        r3 = ftell (mf);
 
803
 
 
804
        if (r1) {
 
805
            fprintf (sf, "\n");
 
806
            fprintf (sf, "%s", name);
 
807
        }
 
808
 
 
809
        calculate_MD5_range (mf, r1, r2, &dig);
 
810
 
 
811
        if (optimize == 0) {
 
812
            fprintf (sf, "Digest-Algorithms: MD5 SHA1\n");
 
813
            fprintf (sf, "MD5-Digest: %s\n", 
 
814
                BTOA_DataToAscii (dig.md5, MD5_LENGTH));
 
815
        }
 
816
 
 
817
        fprintf (sf, "SHA1-Digest: %s\n", 
 
818
            BTOA_DataToAscii (dig.sha1, SHA1_LENGTH));
 
819
 
 
820
        /* restore normalcy after changing offset position */
 
821
        fseek (mf, r3, SEEK_SET);
 
822
    }
 
823
 
 
824
    PORT_Free (buf);
 
825
    PORT_Free (name);
 
826
 
 
827
    fclose (sf);
 
828
    fclose (mf);
 
829
 
 
830
    return 0;
 
831
}
 
832
 
 
833
 
 
834
/*
 
835
 *  c a l c u l a t e _ M D 5 _ r a n g e
 
836
 *
 
837
 *  Calculate the MD5 digest on a range of bytes in
 
838
 *  the specified fopen'd file. Returns base64.
 
839
 *
 
840
 */
 
841
static int      
 
842
calculate_MD5_range (FILE *fp, long r1, long r2, JAR_Digest *dig)
 
843
{
 
844
    int num;
 
845
    int range;
 
846
    unsigned char       *buf;
 
847
 
 
848
    MD5Context * md5 = 0;
 
849
    SHA1Context * sha1 = 0;
 
850
 
 
851
    unsigned int        sha1_length, md5_length;
 
852
 
 
853
    range = r2 - r1;
 
854
 
 
855
    /* position to the beginning of range */
 
856
    fseek (fp, r1, SEEK_SET);
 
857
 
 
858
    buf = (unsigned char *) PORT_ZAlloc (range);
 
859
    if (buf == NULL)
 
860
        out_of_memory();
 
861
 
 
862
    if ((num = fread (buf, 1, range, fp)) != range) {
 
863
        PR_fprintf(errorFD, "%s: expected %d bytes, got %d\n", PROGRAM_NAME,
 
864
                        range, num);
 
865
        errorCount++;
 
866
        exit (ERRX);
 
867
    }
 
868
 
 
869
    md5 = MD5_NewContext();
 
870
    sha1 = SHA1_NewContext();
 
871
 
 
872
    if (md5 == NULL || sha1 == NULL) {
 
873
        PR_fprintf(errorFD, "%s: can't generate digest context\n",
 
874
             PROGRAM_NAME);
 
875
        errorCount++;
 
876
        exit (ERRX);
 
877
    }
 
878
 
 
879
    MD5_Begin (md5);
 
880
    SHA1_Begin (sha1);
 
881
 
 
882
    MD5_Update (md5, buf, range);
 
883
    SHA1_Update (sha1, buf, range);
 
884
 
 
885
    MD5_End (md5, dig->md5, &md5_length, MD5_LENGTH);
 
886
    SHA1_End (sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
 
887
 
 
888
    MD5_DestroyContext (md5, PR_TRUE);
 
889
    SHA1_DestroyContext (sha1, PR_TRUE);
 
890
 
 
891
    PORT_Free (buf);
 
892
 
 
893
    return 0;
 
894
}
 
895
 
 
896
 
 
897
static void     SignOut (void *arg, const char *buf, unsigned long len)
 
898
{
 
899
    fwrite (buf, len, 1, (FILE * ) arg);
 
900
}
 
901
 
 
902