~ubuntu-branches/ubuntu/precise/nss/precise-security

« back to all changes in this revision

Viewing changes to mozilla/security/nss/cmd/smimetools/cmsutil.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2013-11-14 14:58:07 UTC
  • mfrom: (1.1.19)
  • Revision ID: package-import@ubuntu.com-20131114145807-ay302kimn72ovt88
Tags: 3.15.3-0ubuntu0.12.04.1
* SECURITY UPDATE: New upstream release to fix multiple security issues
  and add TLSv1.2 support.
  - CVE-2013-1739
  - CVE-2013-1741
  - CVE-2013-5605
  - CVE-2013-5606
* Adjusted packaging for 3.15.3:
  - debian/patches/*: refreshed.
  - debian/patches/lower-dhe-priority.patch: removed, no longer needed,
    was a workaround for an old version of firefox.
  - debian/libnss3.symbols: added new symbols.
  - debian/rules: updated for new source layout.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
/*
6
 
 * cmsutil -- A command to work with CMS data
7
 
 *
8
 
 * $Id: cmsutil.c,v 1.55 2012/03/20 14:47:20 gerv%gerv.net Exp $
9
 
 */
10
 
 
11
 
#include "nspr.h"
12
 
#include "secutil.h"
13
 
#include "plgetopt.h"
14
 
#include "secpkcs7.h"
15
 
#include "cert.h"
16
 
#include "certdb.h"
17
 
#include "secoid.h"
18
 
#include "cms.h"
19
 
#include "nss.h"
20
 
#include "smime.h"
21
 
#include "pk11func.h"
22
 
 
23
 
#if defined(XP_UNIX)
24
 
#include <unistd.h>
25
 
#endif
26
 
 
27
 
#if defined(_WIN32)
28
 
#include "fcntl.h"
29
 
#include "io.h"
30
 
#endif
31
 
 
32
 
#include <stdio.h>
33
 
#include <string.h>
34
 
 
35
 
char *progName = NULL;
36
 
static int cms_verbose = 0;
37
 
static secuPWData pwdata = { PW_NONE, 0 };
38
 
static PK11PasswordFunc pwcb = NULL;
39
 
static void *pwcb_arg = NULL;
40
 
 
41
 
 
42
 
/* XXX stolen from cmsarray.c
43
 
 * nss_CMSArray_Count - count number of elements in array
44
 
 */
45
 
int
46
 
nss_CMSArray_Count(void **array)
47
 
{
48
 
    int n = 0;
49
 
    if (array == NULL)
50
 
        return 0;
51
 
    while (*array++ != NULL)
52
 
        n++;
53
 
    return n;
54
 
}
55
 
 
56
 
static SECStatus
57
 
DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input,
58
 
           SECAlgorithmID **algids)
59
 
{
60
 
    NSSCMSDigestContext *digcx;
61
 
    SECStatus rv;
62
 
 
63
 
    digcx = NSS_CMSDigestContext_StartMultiple(algids);
64
 
    if (digcx == NULL)
65
 
        return SECFailure;
66
 
 
67
 
    NSS_CMSDigestContext_Update(digcx, input->data, input->len);
68
 
 
69
 
    rv = NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests);
70
 
    return rv;
71
 
}
72
 
 
73
 
 
74
 
static void
75
 
Usage(char *progName)
76
 
{
77
 
    fprintf(stderr, 
78
 
"Usage:  %s [-C|-D|-E|-O|-S] [<options>] [-d dbdir] [-u certusage]\n"
79
 
" -C            create a CMS encrypted data message\n"
80
 
" -D            decode a CMS message\n"
81
 
"  -b           decode a batch of files named in infile\n"
82
 
"  -c content   use this detached content\n"
83
 
"  -n           suppress output of content\n"
84
 
"  -h num       display num levels of CMS message info as email headers\n"
85
 
"  -k           keep decoded encryption certs in perm cert db\n"
86
 
" -E            create a CMS enveloped data message\n"
87
 
"  -r id,...    create envelope for these recipients,\n"
88
 
"               where id can be a certificate nickname or email address\n"
89
 
" -S            create a CMS signed data message\n"
90
 
"  -G           include a signing time attribute\n"
91
 
"  -H hash      use hash (default:SHA1)\n"
92
 
"  -N nick      use certificate named \"nick\" for signing\n"
93
 
"  -P           include a SMIMECapabilities attribute\n"
94
 
"  -T           do not include content in CMS message\n"
95
 
"  -Y nick      include a EncryptionKeyPreference attribute with cert\n"
96
 
"                 (use \"NONE\" to omit)\n"
97
 
" -O            create a CMS signed message containing only certificates\n"
98
 
" General Options:\n"
99
 
" -d dbdir      key/cert database directory (default: ~/.netscape)\n"
100
 
" -e envelope   enveloped data message in this file is used for bulk key\n"
101
 
" -i infile     use infile as source of data (default: stdin)\n"
102
 
" -o outfile    use outfile as destination of data (default: stdout)\n"
103
 
" -p password   use password as key db password (default: prompt)\n"
104
 
" -f pwfile     use password file to set password on all PKCS#11 tokens)\n"
105
 
" -u certusage  set type of certificate usage (default: certUsageEmailSigner)\n"
106
 
" -v            print debugging information\n"
107
 
"\n"
108
 
"Cert usage codes:\n",
109
 
            progName);
110
 
    fprintf(stderr, "%-25s  0 - certUsageSSLClient\n", " ");
111
 
    fprintf(stderr, "%-25s  1 - certUsageSSLServer\n", " ");
112
 
    fprintf(stderr, "%-25s  2 - certUsageSSLServerWithStepUp\n", " ");
113
 
    fprintf(stderr, "%-25s  3 - certUsageSSLCA\n", " ");
114
 
    fprintf(stderr, "%-25s  4 - certUsageEmailSigner\n", " ");
115
 
    fprintf(stderr, "%-25s  5 - certUsageEmailRecipient\n", " ");
116
 
    fprintf(stderr, "%-25s  6 - certUsageObjectSigner\n", " ");
117
 
    fprintf(stderr, "%-25s  7 - certUsageUserCertImport\n", " ");
118
 
    fprintf(stderr, "%-25s  8 - certUsageVerifyCA\n", " ");
119
 
    fprintf(stderr, "%-25s  9 - certUsageProtectedObjectSigner\n", " ");
120
 
    fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " ");
121
 
    fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " ");
122
 
 
123
 
    exit(-1);
124
 
}
125
 
 
126
 
struct optionsStr {
127
 
    char *pwfile;
128
 
    char *password;
129
 
    SECCertUsage certUsage;
130
 
    CERTCertDBHandle *certHandle;
131
 
};
132
 
 
133
 
struct decodeOptionsStr {
134
 
    struct optionsStr *options;
135
 
    SECItem            content;
136
 
    int headerLevel;
137
 
    PRBool suppressContent;
138
 
    NSSCMSGetDecryptKeyCallback dkcb;
139
 
    PK11SymKey *bulkkey;
140
 
    PRBool      keepCerts;
141
 
};
142
 
 
143
 
struct signOptionsStr {
144
 
    struct optionsStr *options;
145
 
    char *nickname;
146
 
    char *encryptionKeyPreferenceNick;
147
 
    PRBool signingTime;
148
 
    PRBool smimeProfile;
149
 
    PRBool detached;
150
 
    SECOidTag hashAlgTag;
151
 
};
152
 
 
153
 
struct envelopeOptionsStr {
154
 
    struct optionsStr *options;
155
 
    char **recipients;
156
 
};
157
 
 
158
 
struct certsonlyOptionsStr {
159
 
    struct optionsStr *options;
160
 
    char **recipients;
161
 
};
162
 
 
163
 
struct encryptOptionsStr {
164
 
    struct optionsStr *options;
165
 
    char **recipients;
166
 
    NSSCMSMessage *envmsg;
167
 
    SECItem *input;
168
 
    FILE *outfile;
169
 
    PRFileDesc *envFile;
170
 
    PK11SymKey *bulkkey;
171
 
    SECOidTag bulkalgtag;
172
 
    int keysize;
173
 
};
174
 
 
175
 
static NSSCMSMessage *
176
 
decode(FILE *out, SECItem *input, const struct decodeOptionsStr *decodeOptions)
177
 
{
178
 
    NSSCMSDecoderContext *dcx;
179
 
    SECStatus rv;
180
 
    NSSCMSMessage *cmsg;
181
 
    int nlevels, i;
182
 
    SECItem sitem = { 0, 0, 0 };
183
 
 
184
 
    PORT_SetError(0);
185
 
    dcx = NSS_CMSDecoder_Start(NULL, 
186
 
                               NULL, NULL,         /* content callback     */
187
 
                               pwcb, pwcb_arg,     /* password callback    */
188
 
                               decodeOptions->dkcb, /* decrypt key callback */
189
 
                               decodeOptions->bulkkey);
190
 
    if (dcx == NULL) {
191
 
        fprintf(stderr, "%s: failed to set up message decoder.\n", progName);
192
 
        return NULL;
193
 
    }
194
 
    rv = NSS_CMSDecoder_Update(dcx, (char *)input->data, input->len);
195
 
    if (rv != SECSuccess) {
196
 
        fprintf(stderr, "%s: failed to decode message.\n", progName);
197
 
        NSS_CMSDecoder_Cancel(dcx);
198
 
        return NULL;
199
 
    }
200
 
    cmsg = NSS_CMSDecoder_Finish(dcx);
201
 
    if (cmsg == NULL) {
202
 
        fprintf(stderr, "%s: failed to decode message.\n", progName);
203
 
        return NULL;
204
 
    }
205
 
 
206
 
    if (decodeOptions->headerLevel >= 0) {
207
 
        /*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/
208
 
        fprintf(out, "SMIME: ");
209
 
    }
210
 
 
211
 
    nlevels = NSS_CMSMessage_ContentLevelCount(cmsg);
212
 
    for (i = 0; i < nlevels; i++) {
213
 
        NSSCMSContentInfo *cinfo;
214
 
        SECOidTag typetag;
215
 
 
216
 
        cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);
217
 
        typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
218
 
 
219
 
        if (decodeOptions->headerLevel >= 0)
220
 
            fprintf(out, "\tlevel=%d.%d; ", decodeOptions->headerLevel, nlevels - i);
221
 
 
222
 
        switch (typetag) {
223
 
        case SEC_OID_PKCS7_SIGNED_DATA:
224
 
          {
225
 
            NSSCMSSignedData *sigd = NULL;
226
 
            SECItem **digests;
227
 
            int nsigners;
228
 
            int j;
229
 
 
230
 
            if (decodeOptions->headerLevel >= 0)
231
 
                fprintf(out, "type=signedData; ");
232
 
            sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
233
 
            if (sigd == NULL) {
234
 
                SECU_PrintError(progName, "signedData component missing");
235
 
                goto loser;
236
 
            }
237
 
 
238
 
            /* if we have a content file, but no digests for this signedData */
239
 
            if (decodeOptions->content.data != NULL && 
240
 
                !NSS_CMSSignedData_HasDigests(sigd)) {
241
 
                PLArenaPool     *poolp;
242
 
                SECAlgorithmID **digestalgs;
243
 
 
244
 
                /* detached content: grab content file */
245
 
                sitem = decodeOptions->content;
246
 
 
247
 
                if ((poolp = PORT_NewArena(1024)) == NULL) {
248
 
                    fprintf(stderr, "cmsutil: Out of memory.\n");
249
 
                    goto loser;
250
 
                }
251
 
                digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
252
 
                if (DigestFile (poolp, &digests, &sitem, digestalgs) 
253
 
                      != SECSuccess) {
254
 
                    SECU_PrintError(progName, 
255
 
                                    "problem computing message digest");
256
 
                    PORT_FreeArena(poolp, PR_FALSE);
257
 
                    goto loser;
258
 
                }
259
 
                if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) 
260
 
                    != SECSuccess) {
261
 
                    SECU_PrintError(progName, 
262
 
                                    "problem setting message digests");
263
 
                    PORT_FreeArena(poolp, PR_FALSE);
264
 
                    goto loser;
265
 
                }
266
 
                PORT_FreeArena(poolp, PR_FALSE);
267
 
            }
268
 
 
269
 
            /* import the certificates */
270
 
            if (NSS_CMSSignedData_ImportCerts(sigd, 
271
 
                                           decodeOptions->options->certHandle, 
272
 
                                           decodeOptions->options->certUsage, 
273
 
                                           decodeOptions->keepCerts) 
274
 
                  != SECSuccess) {
275
 
                SECU_PrintError(progName, "cert import failed");
276
 
                goto loser;
277
 
            }
278
 
 
279
 
            /* find out about signers */
280
 
            nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
281
 
            if (decodeOptions->headerLevel >= 0)
282
 
                fprintf(out, "nsigners=%d; ", nsigners);
283
 
            if (nsigners == 0) {
284
 
                /* Might be a cert transport message
285
 
                ** or might be an invalid message, such as a QA test message
286
 
                ** or a message from an attacker.
287
 
                */
288
 
                SECStatus rv;
289
 
                rv = NSS_CMSSignedData_VerifyCertsOnly(sigd, 
290
 
                                            decodeOptions->options->certHandle, 
291
 
                                            decodeOptions->options->certUsage);
292
 
                if (rv != SECSuccess) {
293
 
                    fprintf(stderr, "cmsutil: Verify certs-only failed!\n");
294
 
                    goto loser;
295
 
                }
296
 
                return cmsg;
297
 
            }
298
 
 
299
 
            /* still no digests? */
300
 
            if (!NSS_CMSSignedData_HasDigests(sigd)) {
301
 
                SECU_PrintError(progName, "no message digests");
302
 
                goto loser;
303
 
            }
304
 
 
305
 
            for (j = 0; j < nsigners; j++) {
306
 
                const char * svs;
307
 
                NSSCMSSignerInfo *si;
308
 
                NSSCMSVerificationStatus vs;
309
 
                SECStatus bad;
310
 
 
311
 
                si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
312
 
                if (decodeOptions->headerLevel >= 0) {
313
 
                    char *signercn;
314
 
                    static char empty[] = { "" };
315
 
 
316
 
                    signercn = NSS_CMSSignerInfo_GetSignerCommonName(si);
317
 
                    if (signercn == NULL)
318
 
                        signercn = empty;
319
 
                    fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j, signercn);
320
 
                    if (signercn != empty)
321
 
                        PORT_Free(signercn);
322
 
                }
323
 
                bad = NSS_CMSSignedData_VerifySignerInfo(sigd, j, 
324
 
                                           decodeOptions->options->certHandle, 
325
 
                                           decodeOptions->options->certUsage);
326
 
                vs  = NSS_CMSSignerInfo_GetVerificationStatus(si);
327
 
                svs = NSS_CMSUtil_VerificationStatusToString(vs);
328
 
                if (decodeOptions->headerLevel >= 0) {
329
 
                    fprintf(out, "signer%d.status=%s; ", j, svs);
330
 
                    /* goto loser ? */
331
 
                } else if (bad && out) {
332
 
                    fprintf(stderr, "signer %d status = %s\n", j, svs);
333
 
                    goto loser;
334
 
                }
335
 
            }
336
 
          }
337
 
          break;
338
 
        case SEC_OID_PKCS7_ENVELOPED_DATA:
339
 
          {
340
 
            NSSCMSEnvelopedData *envd;
341
 
            if (decodeOptions->headerLevel >= 0)
342
 
                fprintf(out, "type=envelopedData; ");
343
 
            envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);
344
 
            if (envd == NULL) {
345
 
                SECU_PrintError(progName, "envelopedData component missing");
346
 
                goto loser;
347
 
            }
348
 
          }
349
 
          break;
350
 
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
351
 
          {
352
 
            NSSCMSEncryptedData *encd;
353
 
            if (decodeOptions->headerLevel >= 0)
354
 
                fprintf(out, "type=encryptedData; ");
355
 
            encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
356
 
            if (encd == NULL) {
357
 
                SECU_PrintError(progName, "encryptedData component missing");
358
 
                goto loser;
359
 
            }
360
 
          }
361
 
          break;
362
 
        case SEC_OID_PKCS7_DATA:
363
 
            if (decodeOptions->headerLevel >= 0)
364
 
                fprintf(out, "type=data; ");
365
 
            break;
366
 
        default:
367
 
            break;
368
 
        }
369
 
        if (decodeOptions->headerLevel >= 0)
370
 
            fprintf(out, "\n");
371
 
    }
372
 
 
373
 
    if (!decodeOptions->suppressContent && out) {
374
 
        SECItem *item = (sitem.data ? &sitem 
375
 
                                    : NSS_CMSMessage_GetContent(cmsg));
376
 
        if (item && item->data && item->len) {
377
 
            fwrite(item->data, item->len, 1, out);
378
 
        }
379
 
    }
380
 
    return cmsg;
381
 
 
382
 
loser:
383
 
    if (cmsg)
384
 
        NSS_CMSMessage_Destroy(cmsg);
385
 
    return NULL;
386
 
}
387
 
 
388
 
/* example of a callback function to use with encoder */
389
 
/*
390
 
static void
391
 
writeout(void *arg, const char *buf, unsigned long len)
392
 
{
393
 
    FILE *f = (FILE *)arg;
394
 
 
395
 
    if (f != NULL && buf != NULL)
396
 
        (void)fwrite(buf, len, 1, f);
397
 
}
398
 
*/
399
 
 
400
 
static NSSCMSMessage *
401
 
signed_data(struct signOptionsStr *signOptions)
402
 
{
403
 
    NSSCMSMessage *cmsg = NULL;
404
 
    NSSCMSContentInfo *cinfo;
405
 
    NSSCMSSignedData *sigd;
406
 
    NSSCMSSignerInfo *signerinfo;
407
 
    CERTCertificate *cert= NULL, *ekpcert = NULL;
408
 
 
409
 
    if (cms_verbose) {
410
 
        fprintf(stderr, "Input to signed_data:\n");
411
 
        if (signOptions->options->password)
412
 
            fprintf(stderr, "password [%s]\n", signOptions->options->password);
413
 
        else if (signOptions->options->pwfile)
414
 
            fprintf(stderr, "password file [%s]\n", signOptions->options->pwfile);
415
 
        else
416
 
            fprintf(stderr, "password [NULL]\n");
417
 
        fprintf(stderr, "certUsage [%d]\n", signOptions->options->certUsage);
418
 
        if (signOptions->options->certHandle)
419
 
            fprintf(stderr, "certdb [%p]\n", signOptions->options->certHandle);
420
 
        else
421
 
            fprintf(stderr, "certdb [NULL]\n");
422
 
        if (signOptions->nickname)
423
 
            fprintf(stderr, "nickname [%s]\n", signOptions->nickname);
424
 
        else
425
 
            fprintf(stderr, "nickname [NULL]\n");
426
 
    }
427
 
    if (signOptions->nickname == NULL) {
428
 
        fprintf(stderr, 
429
 
        "ERROR: please indicate the nickname of a certificate to sign with.\n");
430
 
        return NULL;
431
 
    }
432
 
    if ((cert = CERT_FindUserCertByUsage(signOptions->options->certHandle, 
433
 
                                         signOptions->nickname,
434
 
                                         signOptions->options->certUsage,
435
 
                                         PR_FALSE,
436
 
                                         &pwdata)) == NULL) {
437
 
        SECU_PrintError(progName, 
438
 
                        "the corresponding cert for key \"%s\" does not exist",
439
 
                        signOptions->nickname);
440
 
        return NULL;
441
 
    }
442
 
    if (cms_verbose) {
443
 
        fprintf(stderr, "Found certificate for %s\n", signOptions->nickname);
444
 
    }
445
 
    /*
446
 
     * create the message object
447
 
     */
448
 
    cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
449
 
    if (cmsg == NULL) {
450
 
        fprintf(stderr, "ERROR: cannot create CMS message.\n");
451
 
        return NULL;
452
 
    }
453
 
    /*
454
 
     * build chain of objects: message->signedData->data
455
 
     */
456
 
    if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
457
 
        fprintf(stderr, "ERROR: cannot create CMS signedData object.\n");
458
 
        goto loser;
459
 
    }
460
 
    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
461
 
    if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) 
462
 
          != SECSuccess) {
463
 
        fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n");
464
 
        goto loser;
465
 
    }
466
 
    cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
467
 
    /* we're always passing data in and detaching optionally */
468
 
    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, 
469
 
                                           signOptions->detached) 
470
 
          != SECSuccess) {
471
 
        fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
472
 
        goto loser;
473
 
    }
474
 
    /* 
475
 
     * create & attach signer information
476
 
     */
477
 
    signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, signOptions->hashAlgTag);
478
 
    if (signerinfo == NULL) {
479
 
        fprintf(stderr, "ERROR: cannot create CMS signerInfo object.\n");
480
 
        goto loser;
481
 
    }
482
 
    if (cms_verbose) {
483
 
        fprintf(stderr,
484
 
                 "Created CMS message, added signed data w/ signerinfo\n");
485
 
    }
486
 
    /* we want the cert chain included for this one */
487
 
    if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, 
488
 
                                       signOptions->options->certUsage) 
489
 
          != SECSuccess) {
490
 
        fprintf(stderr, "ERROR: cannot find cert chain.\n");
491
 
        goto loser;
492
 
    }
493
 
    if (cms_verbose) {
494
 
        fprintf(stderr, "imported certificate\n");
495
 
    }
496
 
    if (signOptions->signingTime) {
497
 
        if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) 
498
 
              != SECSuccess) {
499
 
            fprintf(stderr, "ERROR: cannot add signingTime attribute.\n");
500
 
            goto loser;
501
 
        }
502
 
    }
503
 
    if (signOptions->smimeProfile) {
504
 
        if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
505
 
            fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n");
506
 
            goto loser;
507
 
        }
508
 
    }
509
 
 
510
 
    if (!signOptions->encryptionKeyPreferenceNick) {
511
 
        /* check signing cert for fitness as encryption cert */
512
 
        SECStatus FitForEncrypt = CERT_CheckCertUsage(cert,
513
 
                                                      certUsageEmailRecipient);
514
 
 
515
 
        if (SECSuccess == FitForEncrypt) {
516
 
            /* if yes, add signing cert as EncryptionKeyPreference */
517
 
            if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, cert, 
518
 
                                              signOptions->options->certHandle)
519
 
                  != SECSuccess) {
520
 
                fprintf(stderr, 
521
 
                    "ERROR: cannot add default SMIMEEncKeyPrefs attribute.\n");
522
 
                goto loser;
523
 
            }
524
 
            if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, cert, 
525
 
                                              signOptions->options->certHandle)
526
 
                  != SECSuccess) {
527
 
                fprintf(stderr, 
528
 
                    "ERROR: cannot add default MS SMIMEEncKeyPrefs attribute.\n");
529
 
                goto loser;
530
 
            }
531
 
        } else {
532
 
            /* this is a dual-key cert case, we need to look for the encryption
533
 
               certificate under the same nickname as the signing cert */
534
 
            /* get the cert, add it to the message */
535
 
            if ((ekpcert = CERT_FindUserCertByUsage(
536
 
                                              signOptions->options->certHandle,
537
 
                                              signOptions->nickname,
538
 
                                              certUsageEmailRecipient,
539
 
                                              PR_FALSE,
540
 
                                              &pwdata)) == NULL) {
541
 
                SECU_PrintError(progName, 
542
 
                         "the corresponding cert for key \"%s\" does not exist",
543
 
                         signOptions->encryptionKeyPreferenceNick);
544
 
                goto loser;
545
 
            }
546
 
            if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert, 
547
 
                                              signOptions->options->certHandle)
548
 
                  != SECSuccess) {
549
 
                fprintf(stderr, 
550
 
                        "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n");
551
 
                goto loser;
552
 
            }
553
 
            if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, 
554
 
                                              signOptions->options->certHandle)
555
 
                  != SECSuccess) {
556
 
                fprintf(stderr, 
557
 
                        "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n");
558
 
                goto loser;
559
 
            }
560
 
            if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
561
 
                fprintf(stderr, "ERROR: cannot add encryption certificate.\n");
562
 
                goto loser;
563
 
            }
564
 
        }
565
 
    } else if (PL_strcmp(signOptions->encryptionKeyPreferenceNick, "NONE") == 0) {
566
 
        /* No action */
567
 
    } else {
568
 
        /* get the cert, add it to the message */
569
 
        if ((ekpcert = CERT_FindUserCertByUsage(
570
 
                                     signOptions->options->certHandle, 
571
 
                                     signOptions->encryptionKeyPreferenceNick,
572
 
                                     certUsageEmailRecipient, PR_FALSE, &pwdata))
573
 
              == NULL) {
574
 
            SECU_PrintError(progName, 
575
 
                       "the corresponding cert for key \"%s\" does not exist",
576
 
                        signOptions->encryptionKeyPreferenceNick);
577
 
            goto loser;
578
 
        }
579
 
        if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert, 
580
 
                                             signOptions->options->certHandle)
581
 
              != SECSuccess) {
582
 
            fprintf(stderr, "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n");
583
 
            goto loser;
584
 
        }
585
 
        if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, 
586
 
                                             signOptions->options->certHandle)
587
 
              != SECSuccess) {
588
 
            fprintf(stderr, "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n");
589
 
            goto loser;
590
 
        }
591
 
        if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
592
 
            fprintf(stderr, "ERROR: cannot add encryption certificate.\n");
593
 
            goto loser;
594
 
        }
595
 
    }
596
 
 
597
 
    if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
598
 
        fprintf(stderr, "ERROR: cannot add CMS signerInfo object.\n");
599
 
        goto loser;
600
 
    }
601
 
    if (cms_verbose) {
602
 
        fprintf(stderr, "created signed-data message\n");
603
 
    }
604
 
    if (ekpcert) {
605
 
        CERT_DestroyCertificate(ekpcert);
606
 
    }
607
 
    if (cert) {
608
 
        CERT_DestroyCertificate(cert);
609
 
    }
610
 
    return cmsg;
611
 
loser:
612
 
    if (ekpcert) {
613
 
        CERT_DestroyCertificate(ekpcert);
614
 
    }
615
 
    if (cert) {
616
 
        CERT_DestroyCertificate(cert);
617
 
    }
618
 
    NSS_CMSMessage_Destroy(cmsg);
619
 
    return NULL;
620
 
}
621
 
 
622
 
static NSSCMSMessage *
623
 
enveloped_data(struct envelopeOptionsStr *envelopeOptions)
624
 
{
625
 
    NSSCMSMessage *cmsg = NULL;
626
 
    NSSCMSContentInfo *cinfo;
627
 
    NSSCMSEnvelopedData *envd;
628
 
    NSSCMSRecipientInfo *recipientinfo;
629
 
    CERTCertificate **recipientcerts = NULL;
630
 
    CERTCertDBHandle *dbhandle;
631
 
    PLArenaPool *tmppoolp = NULL;
632
 
    SECOidTag bulkalgtag;
633
 
    int keysize, i = 0;
634
 
    int cnt;
635
 
    dbhandle = envelopeOptions->options->certHandle;
636
 
    /* count the recipients */
637
 
    if ((cnt = nss_CMSArray_Count((void **)envelopeOptions->recipients)) == 0) {
638
 
        fprintf(stderr, "ERROR: please name at least one recipient.\n");
639
 
        goto loser;
640
 
    }
641
 
    if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
642
 
        fprintf(stderr, "ERROR: out of memory.\n");
643
 
        goto loser;
644
 
    }
645
 
    /* XXX find the recipient's certs by email address or nickname */
646
 
    if ((recipientcerts = 
647
 
         (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp, 
648
 
                                             (cnt+1)*sizeof(CERTCertificate*)))
649
 
            == NULL) {
650
 
        fprintf(stderr, "ERROR: out of memory.\n");
651
 
        goto loser;
652
 
    }
653
 
    for (i=0; envelopeOptions->recipients[i] != NULL; i++) {
654
 
        if ((recipientcerts[i] = 
655
 
              CERT_FindCertByNicknameOrEmailAddr(dbhandle,  
656
 
                                                envelopeOptions->recipients[i]))
657
 
                == NULL) {
658
 
            SECU_PrintError(progName, "cannot find certificate for \"%s\"", 
659
 
                            envelopeOptions->recipients[i]);
660
 
            i=0;
661
 
            goto loser;
662
 
        }
663
 
    }
664
 
    recipientcerts[i] = NULL;
665
 
    i=0;
666
 
    /* find a nice bulk algorithm */
667
 
    if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientcerts, &bulkalgtag, 
668
 
                                               &keysize) != SECSuccess) {
669
 
        fprintf(stderr, "ERROR: cannot find common bulk algorithm.\n");
670
 
        goto loser;
671
 
    }
672
 
    /*
673
 
     * create the message object
674
 
     */
675
 
    cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
676
 
    if (cmsg == NULL) {
677
 
        fprintf(stderr, "ERROR: cannot create CMS message.\n");
678
 
        goto loser;
679
 
    }
680
 
    /*
681
 
     * build chain of objects: message->envelopedData->data
682
 
     */
683
 
    if ((envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, keysize)) 
684
 
          == NULL) {
685
 
        fprintf(stderr, "ERROR: cannot create CMS envelopedData object.\n");
686
 
        goto loser;
687
 
    }
688
 
    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
689
 
    if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) 
690
 
          != SECSuccess) {
691
 
        fprintf(stderr, "ERROR: cannot attach CMS envelopedData object.\n");
692
 
        goto loser;
693
 
    }
694
 
    cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
695
 
    /* we're always passing data in, so the content is NULL */
696
 
    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
697
 
          != SECSuccess) {
698
 
        fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
699
 
        goto loser;
700
 
    }
701
 
    /* 
702
 
     * create & attach recipient information
703
 
     */
704
 
    for (i = 0; recipientcerts[i] != NULL; i++) {
705
 
        if ((recipientinfo = NSS_CMSRecipientInfo_Create(cmsg, 
706
 
                                                         recipientcerts[i])) 
707
 
              == NULL) {
708
 
            fprintf(stderr, "ERROR: cannot create CMS recipientInfo object.\n");
709
 
            goto loser;
710
 
        }
711
 
        if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientinfo) 
712
 
              != SECSuccess) {
713
 
            fprintf(stderr, "ERROR: cannot add CMS recipientInfo object.\n");
714
 
            goto loser;
715
 
        }
716
 
        CERT_DestroyCertificate(recipientcerts[i]);
717
 
    }
718
 
    if (tmppoolp)
719
 
        PORT_FreeArena(tmppoolp, PR_FALSE);
720
 
    return cmsg;
721
 
loser:
722
 
    if (recipientcerts) {
723
 
        for (; recipientcerts[i] != NULL; i++) {
724
 
            CERT_DestroyCertificate(recipientcerts[i]);
725
 
        }
726
 
    }
727
 
    if (cmsg)
728
 
        NSS_CMSMessage_Destroy(cmsg);
729
 
    if (tmppoolp)
730
 
        PORT_FreeArena(tmppoolp, PR_FALSE);
731
 
    return NULL;
732
 
}
733
 
 
734
 
PK11SymKey *dkcb(void *arg, SECAlgorithmID *algid)
735
 
{
736
 
    return (PK11SymKey*)arg;
737
 
}
738
 
 
739
 
static SECStatus
740
 
get_enc_params(struct encryptOptionsStr *encryptOptions)
741
 
{
742
 
    struct envelopeOptionsStr envelopeOptions;
743
 
    SECStatus rv = SECFailure;
744
 
    NSSCMSMessage *env_cmsg;
745
 
    NSSCMSContentInfo *cinfo;
746
 
    int i, nlevels;
747
 
    /*
748
 
     * construct an enveloped data message to obtain bulk keys
749
 
     */
750
 
    if (encryptOptions->envmsg) {
751
 
        env_cmsg = encryptOptions->envmsg; /* get it from an old message */
752
 
    } else {
753
 
        SECItem dummyOut = { 0, 0, 0 };
754
 
        SECItem dummyIn  = { 0, 0, 0 };
755
 
        char str[] = "Hello!";
756
 
        PLArenaPool *tmparena = PORT_NewArena(1024);
757
 
        dummyIn.data = (unsigned char *)str;
758
 
        dummyIn.len = strlen(str);
759
 
        envelopeOptions.options = encryptOptions->options;
760
 
        envelopeOptions.recipients = encryptOptions->recipients;
761
 
        env_cmsg = enveloped_data(&envelopeOptions);
762
 
        NSS_CMSDEREncode(env_cmsg, &dummyIn, &dummyOut, tmparena);
763
 
        PR_Write(encryptOptions->envFile, dummyOut.data, dummyOut.len);
764
 
        PORT_FreeArena(tmparena, PR_FALSE);
765
 
    }
766
 
    /*
767
 
     * get the content info for the enveloped data 
768
 
     */
769
 
    nlevels = NSS_CMSMessage_ContentLevelCount(env_cmsg);
770
 
    for (i = 0; i < nlevels; i++) {
771
 
        SECOidTag typetag;
772
 
        cinfo = NSS_CMSMessage_ContentLevel(env_cmsg, i);
773
 
        typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
774
 
        if (typetag == SEC_OID_PKCS7_DATA) {
775
 
            /*
776
 
             * get the symmetric key
777
 
             */
778
 
            encryptOptions->bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo);
779
 
            encryptOptions->keysize = NSS_CMSContentInfo_GetBulkKeySize(cinfo);
780
 
            encryptOptions->bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
781
 
            rv = SECSuccess;
782
 
            break;
783
 
        }
784
 
    }
785
 
    if (i == nlevels) {
786
 
        fprintf(stderr, "%s: could not retrieve enveloped data.", progName);
787
 
    }
788
 
    if (env_cmsg)
789
 
        NSS_CMSMessage_Destroy(env_cmsg);
790
 
    return rv;
791
 
}
792
 
 
793
 
static NSSCMSMessage *
794
 
encrypted_data(struct encryptOptionsStr *encryptOptions)
795
 
{
796
 
    SECStatus rv = SECFailure;
797
 
    NSSCMSMessage *cmsg = NULL;
798
 
    NSSCMSContentInfo *cinfo;
799
 
    NSSCMSEncryptedData *encd;
800
 
    NSSCMSEncoderContext *ecx = NULL;
801
 
    PLArenaPool *tmppoolp = NULL;
802
 
    SECItem derOut = { 0, 0, 0 };
803
 
    /* arena for output */
804
 
    tmppoolp = PORT_NewArena(1024);
805
 
    if (!tmppoolp) {
806
 
        fprintf(stderr, "%s: out of memory.\n", progName);
807
 
        return NULL;
808
 
    }
809
 
    /*
810
 
     * create the message object
811
 
     */
812
 
    cmsg = NSS_CMSMessage_Create(NULL);
813
 
    if (cmsg == NULL) {
814
 
        fprintf(stderr, "ERROR: cannot create CMS message.\n");
815
 
        goto loser;
816
 
    }
817
 
    /*
818
 
     * build chain of objects: message->encryptedData->data
819
 
     */
820
 
    if ((encd = NSS_CMSEncryptedData_Create(cmsg, encryptOptions->bulkalgtag, 
821
 
                                                  encryptOptions->keysize)) 
822
 
           == NULL) {
823
 
        fprintf(stderr, "ERROR: cannot create CMS encryptedData object.\n");
824
 
        goto loser;
825
 
    }
826
 
    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
827
 
    if (NSS_CMSContentInfo_SetContent_EncryptedData(cmsg, cinfo, encd)
828
 
          != SECSuccess) {
829
 
        fprintf(stderr, "ERROR: cannot attach CMS encryptedData object.\n");
830
 
        goto loser;
831
 
    }
832
 
    cinfo = NSS_CMSEncryptedData_GetContentInfo(encd);
833
 
    /* we're always passing data in, so the content is NULL */
834
 
    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
835
 
          != SECSuccess) {
836
 
        fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
837
 
        goto loser;
838
 
    }
839
 
    ecx = NSS_CMSEncoder_Start(cmsg, NULL, NULL, &derOut, tmppoolp, NULL, NULL,
840
 
                               dkcb, encryptOptions->bulkkey, NULL, NULL);
841
 
    if (!ecx) {
842
 
        fprintf(stderr, "%s: cannot create encoder context.\n", progName);
843
 
        goto loser;
844
 
    }
845
 
    rv = NSS_CMSEncoder_Update(ecx, (char *)encryptOptions->input->data, 
846
 
                                    encryptOptions->input->len);
847
 
    if (rv) {
848
 
        fprintf(stderr, "%s: failed to add data to encoder.\n", progName);
849
 
        goto loser;
850
 
    }
851
 
    rv = NSS_CMSEncoder_Finish(ecx);
852
 
    if (rv) {
853
 
        fprintf(stderr, "%s: failed to encrypt data.\n", progName);
854
 
        goto loser;
855
 
    }
856
 
    fwrite(derOut.data, derOut.len, 1, encryptOptions->outfile);
857
 
    /*
858
 
    if (bulkkey)
859
 
        PK11_FreeSymKey(bulkkey);
860
 
        */
861
 
    if (tmppoolp)
862
 
        PORT_FreeArena(tmppoolp, PR_FALSE);
863
 
    return cmsg;
864
 
loser:
865
 
    /*
866
 
    if (bulkkey)
867
 
        PK11_FreeSymKey(bulkkey);
868
 
        */
869
 
    if (tmppoolp)
870
 
        PORT_FreeArena(tmppoolp, PR_FALSE);
871
 
    if (cmsg)
872
 
        NSS_CMSMessage_Destroy(cmsg);
873
 
    return NULL;
874
 
}
875
 
 
876
 
static NSSCMSMessage *
877
 
signed_data_certsonly(struct certsonlyOptionsStr *certsonlyOptions)
878
 
{
879
 
    NSSCMSMessage *cmsg = NULL;
880
 
    NSSCMSContentInfo *cinfo;
881
 
    NSSCMSSignedData *sigd;
882
 
    CERTCertificate **certs = NULL;
883
 
    CERTCertDBHandle *dbhandle;
884
 
    PLArenaPool *tmppoolp = NULL;
885
 
    int i = 0, cnt;
886
 
    dbhandle = certsonlyOptions->options->certHandle;
887
 
    if ((cnt = nss_CMSArray_Count((void**)certsonlyOptions->recipients)) == 0) {
888
 
        fprintf(stderr, 
889
 
        "ERROR: please indicate the nickname of a certificate to sign with.\n");
890
 
        goto loser;
891
 
    }
892
 
    if (!(tmppoolp = PORT_NewArena(1024))) {
893
 
        fprintf(stderr, "ERROR: out of memory.\n");
894
 
        goto loser;
895
 
    }
896
 
    if (!(certs = PORT_ArenaZNewArray(tmppoolp, CERTCertificate *, cnt + 1))) {
897
 
        fprintf(stderr, "ERROR: out of memory.\n");
898
 
        goto loser;
899
 
    }
900
 
    for (i=0; certsonlyOptions->recipients[i] != NULL; i++) {
901
 
        if ((certs[i] = 
902
 
              CERT_FindCertByNicknameOrEmailAddr(dbhandle,
903
 
                                              certsonlyOptions->recipients[i]))
904
 
                == NULL) {
905
 
            SECU_PrintError(progName, "cannot find certificate for \"%s\"", 
906
 
                            certsonlyOptions->recipients[i]);
907
 
            i=0;
908
 
            goto loser;
909
 
        }
910
 
    }
911
 
    certs[i] = NULL;
912
 
    i=0;
913
 
    /*
914
 
     * create the message object
915
 
     */
916
 
    cmsg = NSS_CMSMessage_Create(NULL);
917
 
    if (cmsg == NULL) {
918
 
        fprintf(stderr, "ERROR: cannot create CMS message.\n");
919
 
        goto loser;
920
 
    }
921
 
    /*
922
 
     * build chain of objects: message->signedData->data
923
 
     */
924
 
    if ((sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, certs[0], PR_TRUE))
925
 
          == NULL) {
926
 
        fprintf(stderr, "ERROR: cannot create CMS signedData object.\n");
927
 
        goto loser;
928
 
    }
929
 
    CERT_DestroyCertificate(certs[0]);
930
 
    for (i=1; i<cnt; i++) {
931
 
        if (NSS_CMSSignedData_AddCertChain(sigd, certs[i])) {
932
 
            fprintf(stderr, "ERROR: cannot add cert chain for \"%s\".\n",
933
 
                    certsonlyOptions->recipients[i]);
934
 
            goto loser;
935
 
        }
936
 
        CERT_DestroyCertificate(certs[i]);
937
 
    }
938
 
    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
939
 
    if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) 
940
 
          != SECSuccess) {
941
 
        fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n");
942
 
        goto loser;
943
 
    }
944
 
    cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
945
 
    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
946
 
           != SECSuccess) {
947
 
        fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
948
 
        goto loser;
949
 
    }
950
 
    if (tmppoolp)
951
 
        PORT_FreeArena(tmppoolp, PR_FALSE);
952
 
    return cmsg;
953
 
loser:
954
 
    if (certs) {
955
 
        for (; i<cnt; i++) {
956
 
            CERT_DestroyCertificate(certs[i]);
957
 
        }
958
 
    }
959
 
    if (cmsg)
960
 
        NSS_CMSMessage_Destroy(cmsg);
961
 
    if (tmppoolp)
962
 
        PORT_FreeArena(tmppoolp, PR_FALSE);
963
 
    return NULL;
964
 
}
965
 
 
966
 
static char *
967
 
pl_fgets(char * buf, int size, PRFileDesc * fd)
968
 
{
969
 
    char * bp = buf;
970
 
    int    nb = 0;;
971
 
 
972
 
    while (size > 1) {
973
 
        nb = PR_Read(fd, bp, 1);
974
 
        if (nb < 0) {
975
 
            /* deal with error */
976
 
            return NULL;
977
 
        } else if (nb == 0) {
978
 
            /* deal with EOF */
979
 
            return NULL;
980
 
        } else if (*bp == '\n') {
981
 
            /* deal with EOL */
982
 
            ++bp;  /* keep EOL character */
983
 
            break;
984
 
        } else {
985
 
            /* ordinary character */
986
 
            ++bp;
987
 
            --size;
988
 
        }
989
 
    }
990
 
    *bp = '\0';
991
 
    return buf;
992
 
}
993
 
 
994
 
typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode;
995
 
 
996
 
static int 
997
 
doBatchDecode(FILE *outFile, PRFileDesc *batchFile, 
998
 
              const struct decodeOptionsStr *decodeOptions)
999
 
{
1000
 
    char * str;
1001
 
    int    exitStatus = 0;
1002
 
    char   batchLine[512];
1003
 
 
1004
 
    while (NULL != (str = pl_fgets(batchLine, sizeof batchLine, batchFile))) {
1005
 
        NSSCMSMessage *cmsg = NULL;
1006
 
        PRFileDesc *   inFile;
1007
 
        int            len = strlen(str);
1008
 
        SECStatus      rv;
1009
 
        SECItem        input = {0, 0, 0};
1010
 
        char           cc;
1011
 
 
1012
 
        while (len > 0 && 
1013
 
               ((cc = str[len - 1]) == '\n' || cc == '\r')) {
1014
 
            str[--len] = '\0';
1015
 
        }
1016
 
        if (!len) /* skip empty line */
1017
 
            continue;
1018
 
        if (str[0] == '#')
1019
 
            continue;  /* skip comment line */
1020
 
        fprintf(outFile, "========== %s ==========\n", str);
1021
 
        inFile = PR_Open(str, PR_RDONLY, 00660);
1022
 
        if (inFile == NULL) {
1023
 
            fprintf(outFile, "%s: unable to open \"%s\" for reading\n",
1024
 
                    progName, str);
1025
 
            exitStatus = 1;
1026
 
            continue;
1027
 
        }
1028
 
        rv = SECU_FileToItem(&input, inFile);
1029
 
        PR_Close(inFile);
1030
 
        if (rv != SECSuccess) {
1031
 
            SECU_PrintError(progName, "unable to read infile");
1032
 
            exitStatus = 1;
1033
 
            continue;
1034
 
        }
1035
 
        cmsg = decode(outFile, &input, decodeOptions);
1036
 
        SECITEM_FreeItem(&input, PR_FALSE);
1037
 
        if (cmsg)
1038
 
            NSS_CMSMessage_Destroy(cmsg);
1039
 
        else {
1040
 
            SECU_PrintError(progName, "problem decoding");
1041
 
            exitStatus = 1;
1042
 
        }
1043
 
    }
1044
 
    return exitStatus;
1045
 
}
1046
 
 
1047
 
int
1048
 
main(int argc, char **argv)
1049
 
{
1050
 
    FILE *outFile;
1051
 
    NSSCMSMessage *cmsg = NULL;
1052
 
    PRFileDesc *inFile;
1053
 
    PLOptState *optstate;
1054
 
    PLOptStatus status;
1055
 
    Mode mode = UNKNOWN;
1056
 
    struct decodeOptionsStr decodeOptions = { 0 };
1057
 
    struct signOptionsStr signOptions = { 0 };
1058
 
    struct envelopeOptionsStr envelopeOptions = { 0 };
1059
 
    struct certsonlyOptionsStr certsonlyOptions = { 0 };
1060
 
    struct encryptOptionsStr encryptOptions = { 0 };
1061
 
    struct optionsStr options = { 0 };
1062
 
    int exitstatus;
1063
 
    static char *ptrarray[128] = { 0 };
1064
 
    int nrecipients = 0;
1065
 
    char *str, *tok;
1066
 
    char *envFileName;
1067
 
    SECItem input = { 0, 0, 0};
1068
 
    SECItem envmsg = { 0, 0, 0 };
1069
 
    SECStatus rv;
1070
 
    PRFileDesc *contentFile = NULL;
1071
 
    PRBool      batch = PR_FALSE;
1072
 
 
1073
 
#ifdef NISCC_TEST
1074
 
    const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
1075
 
    PORT_Assert(ev); 
1076
 
    ev = PR_GetEnv("NSS_STRICT_SHUTDOWN");
1077
 
    PORT_Assert(ev); 
1078
 
#endif 
1079
 
 
1080
 
    progName = strrchr(argv[0], '/');
1081
 
    if (!progName)
1082
 
       progName = strrchr(argv[0], '\\');
1083
 
    progName = progName ? progName+1 : argv[0];
1084
 
 
1085
 
    inFile = PR_STDIN;
1086
 
    outFile = stdout;
1087
 
    envFileName = NULL;
1088
 
    mode = UNKNOWN;
1089
 
    decodeOptions.content.data = NULL;
1090
 
    decodeOptions.content.len  = 0;
1091
 
    decodeOptions.suppressContent = PR_FALSE;
1092
 
    decodeOptions.headerLevel = -1;
1093
 
    decodeOptions.keepCerts = PR_FALSE;
1094
 
    options.certUsage = certUsageEmailSigner;
1095
 
    options.password = NULL;
1096
 
    options.pwfile = NULL;
1097
 
    signOptions.nickname = NULL;
1098
 
    signOptions.detached = PR_FALSE;
1099
 
    signOptions.signingTime = PR_FALSE;
1100
 
    signOptions.smimeProfile = PR_FALSE;
1101
 
    signOptions.encryptionKeyPreferenceNick = NULL;
1102
 
    signOptions.hashAlgTag = SEC_OID_SHA1;
1103
 
    envelopeOptions.recipients = NULL;
1104
 
    encryptOptions.recipients = NULL;
1105
 
    encryptOptions.envmsg = NULL;
1106
 
    encryptOptions.envFile = NULL;
1107
 
    encryptOptions.bulkalgtag = SEC_OID_UNKNOWN;
1108
 
    encryptOptions.bulkkey = NULL;
1109
 
    encryptOptions.keysize = -1;
1110
 
 
1111
 
    /*
1112
 
     * Parse command line arguments
1113
 
     */
1114
 
    optstate = PL_CreateOptState(argc, argv, 
1115
 
                                 "CDEGH:N:OPSTY:bc:d:e:f:h:i:kno:p:r:s:u:v");
1116
 
    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
1117
 
        switch (optstate->option) {
1118
 
        case 'C':
1119
 
            mode = ENCRYPT;
1120
 
            break;
1121
 
        case 'D':
1122
 
            mode = DECODE;
1123
 
            break;
1124
 
        case 'E':
1125
 
            mode = ENVELOPE;
1126
 
            break;
1127
 
        case 'G':
1128
 
            if (mode != SIGN) {
1129
 
                fprintf(stderr, 
1130
 
                        "%s: option -G only supported with option -S.\n", 
1131
 
                        progName);
1132
 
                Usage(progName);
1133
 
                exit(1);
1134
 
            }
1135
 
            signOptions.signingTime = PR_TRUE;
1136
 
            break;
1137
 
       case 'H':
1138
 
           if (mode != SIGN) {
1139
 
               fprintf(stderr,
1140
 
                       "%s: option -H only supported with option -S.\n",
1141
 
                       progName);
1142
 
               Usage(progName);
1143
 
               exit(1);
1144
 
           }
1145
 
           decodeOptions.suppressContent = PR_TRUE;
1146
 
           if (!strcmp(optstate->value, "MD2"))
1147
 
               signOptions.hashAlgTag = SEC_OID_MD2;
1148
 
           else if (!strcmp(optstate->value, "MD4"))
1149
 
               signOptions.hashAlgTag = SEC_OID_MD4;
1150
 
           else if (!strcmp(optstate->value, "MD5"))
1151
 
               signOptions.hashAlgTag = SEC_OID_MD5;
1152
 
           else if (!strcmp(optstate->value, "SHA1"))
1153
 
               signOptions.hashAlgTag = SEC_OID_SHA1;
1154
 
           else if (!strcmp(optstate->value, "SHA256"))
1155
 
               signOptions.hashAlgTag = SEC_OID_SHA256;
1156
 
           else if (!strcmp(optstate->value, "SHA384"))
1157
 
               signOptions.hashAlgTag = SEC_OID_SHA384;
1158
 
           else if (!strcmp(optstate->value, "SHA512"))
1159
 
               signOptions.hashAlgTag = SEC_OID_SHA512;
1160
 
           else {
1161
 
               fprintf(stderr,
1162
 
           "%s: -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512\n",
1163
 
                       progName);
1164
 
               exit(1);
1165
 
           }
1166
 
           break;
1167
 
        case 'N':
1168
 
            if (mode != SIGN) {
1169
 
                fprintf(stderr, 
1170
 
                        "%s: option -N only supported with option -S.\n", 
1171
 
                        progName);
1172
 
                Usage(progName);
1173
 
                exit(1);
1174
 
            }
1175
 
            signOptions.nickname = strdup(optstate->value);
1176
 
            break;
1177
 
        case 'O':
1178
 
            mode = CERTSONLY;
1179
 
            break;
1180
 
        case 'P':
1181
 
            if (mode != SIGN) {
1182
 
                fprintf(stderr, 
1183
 
                        "%s: option -P only supported with option -S.\n", 
1184
 
                        progName);
1185
 
                Usage(progName);
1186
 
                exit(1);
1187
 
            }
1188
 
            signOptions.smimeProfile = PR_TRUE;
1189
 
            break;
1190
 
        case 'S':
1191
 
            mode = SIGN;
1192
 
            break;
1193
 
        case 'T':
1194
 
            if (mode != SIGN) {
1195
 
                fprintf(stderr, 
1196
 
                        "%s: option -T only supported with option -S.\n", 
1197
 
                        progName);
1198
 
                Usage(progName);
1199
 
                exit(1);
1200
 
            }
1201
 
            signOptions.detached = PR_TRUE;
1202
 
            break;
1203
 
        case 'Y':
1204
 
            if (mode != SIGN) {
1205
 
                fprintf(stderr, 
1206
 
                        "%s: option -Y only supported with option -S.\n", 
1207
 
                        progName);
1208
 
                Usage(progName);
1209
 
                exit(1);
1210
 
            }
1211
 
            signOptions.encryptionKeyPreferenceNick = strdup(optstate->value);
1212
 
            break;
1213
 
 
1214
 
        case 'b':
1215
 
            if (mode != DECODE) {
1216
 
                fprintf(stderr, 
1217
 
                        "%s: option -b only supported with option -D.\n", 
1218
 
                        progName);
1219
 
                Usage(progName);
1220
 
                exit(1);
1221
 
            }
1222
 
            batch = PR_TRUE;
1223
 
            break;
1224
 
 
1225
 
        case 'c':
1226
 
            if (mode != DECODE) {
1227
 
                fprintf(stderr, 
1228
 
                        "%s: option -c only supported with option -D.\n", 
1229
 
                        progName);
1230
 
                Usage(progName);
1231
 
                exit(1);
1232
 
            }
1233
 
            contentFile = PR_Open(optstate->value, PR_RDONLY, 006600);
1234
 
            if (contentFile == NULL) {
1235
 
                fprintf(stderr, "%s: unable to open \"%s\" for reading.\n",
1236
 
                        progName, optstate->value);
1237
 
                exit(1);
1238
 
            }
1239
 
 
1240
 
            rv = SECU_FileToItem(&decodeOptions.content, contentFile);
1241
 
            PR_Close(contentFile);
1242
 
            if (rv != SECSuccess) {
1243
 
                SECU_PrintError(progName, "problem reading content file");
1244
 
                exit(1);
1245
 
            }
1246
 
            if (!decodeOptions.content.data) {
1247
 
                /* file was zero length */
1248
 
                decodeOptions.content.data = (unsigned char *)PORT_Strdup("");
1249
 
                decodeOptions.content.len  = 0;
1250
 
            }
1251
 
 
1252
 
            break;
1253
 
        case 'd':
1254
 
            SECU_ConfigDirectory(optstate->value);
1255
 
            break;
1256
 
        case 'e':
1257
 
            envFileName = strdup(optstate->value);
1258
 
            encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660);
1259
 
            break;
1260
 
 
1261
 
        case 'h':
1262
 
            if (mode != DECODE) {
1263
 
                fprintf(stderr, 
1264
 
                        "%s: option -h only supported with option -D.\n", 
1265
 
                        progName);
1266
 
                Usage(progName);
1267
 
                exit(1);
1268
 
            }
1269
 
            decodeOptions.headerLevel = atoi(optstate->value);
1270
 
            if (decodeOptions.headerLevel < 0) {
1271
 
                fprintf(stderr, "option -h cannot have a negative value.\n");
1272
 
                exit(1);
1273
 
            }
1274
 
            break;
1275
 
        case 'i':
1276
 
            if (!optstate->value) {
1277
 
                fprintf(stderr, "-i option requires filename argument\n");
1278
 
                exit(1);
1279
 
            }
1280
 
            inFile = PR_Open(optstate->value, PR_RDONLY, 00660);
1281
 
            if (inFile == NULL) {
1282
 
                fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
1283
 
                        progName, optstate->value);
1284
 
                exit(1);
1285
 
            }
1286
 
            break;
1287
 
 
1288
 
        case 'k':
1289
 
            if (mode != DECODE) {
1290
 
                fprintf(stderr, 
1291
 
                        "%s: option -k only supported with option -D.\n", 
1292
 
                        progName);
1293
 
                Usage(progName);
1294
 
                exit(1);
1295
 
            }
1296
 
            decodeOptions.keepCerts = PR_TRUE;
1297
 
            break;
1298
 
 
1299
 
        case 'n':
1300
 
            if (mode != DECODE) {
1301
 
                fprintf(stderr, 
1302
 
                        "%s: option -n only supported with option -D.\n", 
1303
 
                        progName);
1304
 
                Usage(progName);
1305
 
                exit(1);
1306
 
            }
1307
 
            decodeOptions.suppressContent = PR_TRUE;
1308
 
            break;
1309
 
        case 'o':
1310
 
            outFile = fopen(optstate->value, "wb");
1311
 
            if (outFile == NULL) {
1312
 
                fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
1313
 
                        progName, optstate->value);
1314
 
                exit(1);
1315
 
            }
1316
 
            break;
1317
 
        case 'p':
1318
 
            if (!optstate->value) {
1319
 
                fprintf(stderr, "%s: option -p must have a value.\n", progName);
1320
 
                Usage(progName);
1321
 
                exit(1);
1322
 
            }
1323
 
                
1324
 
            options.password = strdup(optstate->value);
1325
 
            break;
1326
 
 
1327
 
        case 'f':
1328
 
            if (!optstate->value) {
1329
 
                fprintf(stderr, "%s: option -f must have a value.\n", progName);
1330
 
                Usage(progName);
1331
 
                exit(1);
1332
 
            }
1333
 
 
1334
 
            options.pwfile = strdup(optstate->value);
1335
 
            break;
1336
 
 
1337
 
        case 'r':
1338
 
            if (!optstate->value) {
1339
 
                fprintf(stderr, "%s: option -r must have a value.\n", progName);
1340
 
                Usage(progName);
1341
 
                exit(1);
1342
 
            }
1343
 
            envelopeOptions.recipients = ptrarray;
1344
 
            str = (char *)optstate->value;
1345
 
            do {
1346
 
                tok = strchr(str, ',');
1347
 
                if (tok) *tok = '\0';
1348
 
                envelopeOptions.recipients[nrecipients++] = strdup(str);
1349
 
                if (tok) str = tok + 1;
1350
 
            } while (tok);
1351
 
            envelopeOptions.recipients[nrecipients] = NULL;
1352
 
            encryptOptions.recipients = envelopeOptions.recipients;
1353
 
            certsonlyOptions.recipients = envelopeOptions.recipients;
1354
 
            break;
1355
 
 
1356
 
        case 'u': {
1357
 
            int usageType;
1358
 
 
1359
 
            usageType = atoi (strdup(optstate->value));
1360
 
            if (usageType < certUsageSSLClient || usageType > certUsageAnyCA)
1361
 
                return -1;
1362
 
            options.certUsage = (SECCertUsage)usageType;
1363
 
            break;
1364
 
          }
1365
 
        case 'v':
1366
 
            cms_verbose = 1;
1367
 
            break;
1368
 
 
1369
 
        }
1370
 
    }
1371
 
    if (status == PL_OPT_BAD)
1372
 
        Usage(progName);
1373
 
    PL_DestroyOptState(optstate);
1374
 
 
1375
 
    if (mode == UNKNOWN)
1376
 
        Usage(progName);
1377
 
 
1378
 
    if (mode != CERTSONLY && !batch) {
1379
 
        rv = SECU_FileToItem(&input, inFile);
1380
 
        if (rv != SECSuccess) {
1381
 
            SECU_PrintError(progName, "unable to read infile");
1382
 
            exit(1);
1383
 
        }
1384
 
        if (inFile != PR_STDIN) {
1385
 
            PR_Close(inFile);
1386
 
        }
1387
 
    }
1388
 
    if (cms_verbose) {
1389
 
        fprintf(stderr, "received commands\n");
1390
 
    }
1391
 
 
1392
 
    /* Call the NSS initialization routines */
1393
 
    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
1394
 
    rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
1395
 
    if (SECSuccess != rv) {
1396
 
        SECU_PrintError(progName, "NSS_Init failed");
1397
 
        exit(1);
1398
 
    }
1399
 
    if (cms_verbose) {
1400
 
        fprintf(stderr, "NSS has been initialized.\n");
1401
 
    }
1402
 
    options.certHandle = CERT_GetDefaultCertDB();
1403
 
    if (!options.certHandle) {
1404
 
        SECU_PrintError(progName, "No default cert DB");
1405
 
        exit(1);
1406
 
    }
1407
 
    if (cms_verbose) {
1408
 
        fprintf(stderr, "Got default certdb\n");
1409
 
    }
1410
 
    if (options.password)
1411
 
    {
1412
 
        pwdata.source = PW_PLAINTEXT;
1413
 
        pwdata.data = options.password;
1414
 
    }
1415
 
    if (options.pwfile)
1416
 
    {
1417
 
        pwdata.source = PW_FROMFILE;
1418
 
        pwdata.data = options.pwfile;
1419
 
    }
1420
 
    pwcb = SECU_GetModulePassword;
1421
 
    pwcb_arg = (void *)&pwdata;
1422
 
 
1423
 
    PK11_SetPasswordFunc(&SECU_GetModulePassword);
1424
 
 
1425
 
 
1426
 
#if defined(_WIN32)
1427
 
    if (outFile == stdout) {
1428
 
        /* If we're going to write binary data to stdout, we must put stdout
1429
 
        ** into O_BINARY mode or else outgoing \n's will become \r\n's.
1430
 
        */
1431
 
        int smrv = _setmode(_fileno(stdout), _O_BINARY);
1432
 
        if (smrv == -1) {
1433
 
            fprintf(stderr,
1434
 
            "%s: Cannot change stdout to binary mode. Use -o option instead.\n",
1435
 
                    progName);
1436
 
            return smrv;
1437
 
        }
1438
 
    }
1439
 
#endif
1440
 
 
1441
 
    exitstatus = 0;
1442
 
    switch (mode) {
1443
 
    case DECODE:       /* -D */
1444
 
        decodeOptions.options = &options;
1445
 
        if (encryptOptions.envFile) {
1446
 
            /* Decoding encrypted-data, so get the bulkkey from an
1447
 
             * enveloped-data message.
1448
 
             */
1449
 
            SECU_FileToItem(&envmsg, encryptOptions.envFile);
1450
 
            decodeOptions.options = &options;
1451
 
            encryptOptions.envmsg = decode(NULL, &envmsg, &decodeOptions);
1452
 
            if (!encryptOptions.envmsg) {
1453
 
                SECU_PrintError(progName, "problem decoding env msg");
1454
 
                exitstatus = 1;
1455
 
                break;
1456
 
            }
1457
 
            rv = get_enc_params(&encryptOptions);
1458
 
            decodeOptions.dkcb = dkcb;
1459
 
            decodeOptions.bulkkey = encryptOptions.bulkkey;
1460
 
        }
1461
 
        if (!batch) {
1462
 
            cmsg = decode(outFile, &input, &decodeOptions);
1463
 
            if (!cmsg) {
1464
 
                SECU_PrintError(progName, "problem decoding");
1465
 
                exitstatus = 1;
1466
 
            }
1467
 
        } else {
1468
 
            exitstatus = doBatchDecode(outFile, inFile, &decodeOptions);
1469
 
            if (inFile != PR_STDIN) {
1470
 
                PR_Close(inFile);
1471
 
            }
1472
 
        }
1473
 
        break;
1474
 
    case SIGN:         /* -S */
1475
 
        signOptions.options = &options;
1476
 
        cmsg = signed_data(&signOptions);
1477
 
        if (!cmsg) {
1478
 
            SECU_PrintError(progName, "problem signing");
1479
 
            exitstatus = 1;
1480
 
        }
1481
 
        break;
1482
 
    case ENCRYPT:      /* -C */
1483
 
        if (!envFileName) {
1484
 
            fprintf(stderr, "%s: you must specify an envelope file with -e.\n",
1485
 
                    progName);
1486
 
            exit(1);
1487
 
        }
1488
 
        encryptOptions.options = &options;
1489
 
        encryptOptions.input = &input;
1490
 
        encryptOptions.outfile = outFile;
1491
 
        /* decode an enveloped-data message to get the bulkkey (create
1492
 
         * a new one if neccessary)
1493
 
         */
1494
 
        if (!encryptOptions.envFile) {
1495
 
            encryptOptions.envFile = PR_Open(envFileName, 
1496
 
                                             PR_WRONLY|PR_CREATE_FILE, 00660);
1497
 
            if (!encryptOptions.envFile) {
1498
 
                fprintf(stderr, "%s: failed to create file %s.\n", progName,
1499
 
                        envFileName);
1500
 
                exit(1);
1501
 
            }
1502
 
        } else {
1503
 
            SECU_FileToItem(&envmsg, encryptOptions.envFile);
1504
 
            decodeOptions.options = &options;
1505
 
            encryptOptions.envmsg = decode(NULL, &envmsg, &decodeOptions);
1506
 
            if (encryptOptions.envmsg == NULL) {
1507
 
                SECU_PrintError(progName, "problem decrypting env msg");
1508
 
                exitstatus = 1;
1509
 
                break;
1510
 
            }
1511
 
        }
1512
 
        rv = get_enc_params(&encryptOptions);
1513
 
        /* create the encrypted-data message */
1514
 
        cmsg = encrypted_data(&encryptOptions);
1515
 
        if (!cmsg) {
1516
 
            SECU_PrintError(progName, "problem encrypting");
1517
 
            exitstatus = 1;
1518
 
        }
1519
 
        if (encryptOptions.bulkkey) {
1520
 
            PK11_FreeSymKey(encryptOptions.bulkkey);
1521
 
            encryptOptions.bulkkey = NULL;
1522
 
        }
1523
 
        break;
1524
 
    case ENVELOPE:     /* -E */
1525
 
        envelopeOptions.options = &options;
1526
 
        cmsg = enveloped_data(&envelopeOptions);
1527
 
        if (!cmsg) {
1528
 
            SECU_PrintError(progName, "problem enveloping");
1529
 
            exitstatus = 1;
1530
 
        }
1531
 
        break;
1532
 
    case CERTSONLY:    /* -O */
1533
 
        certsonlyOptions.options = &options;
1534
 
        cmsg = signed_data_certsonly(&certsonlyOptions);
1535
 
        if (!cmsg) {
1536
 
            SECU_PrintError(progName, "problem with certs-only");
1537
 
            exitstatus = 1;
1538
 
        }
1539
 
        break;
1540
 
    default:
1541
 
        fprintf(stderr, "One of options -D, -S or -E must be set.\n");
1542
 
        Usage(progName);
1543
 
        exitstatus = 1;
1544
 
    }
1545
 
    if ( (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY)
1546
 
         && (!exitstatus) ) {
1547
 
        PLArenaPool *arena = PORT_NewArena(1024);
1548
 
        NSSCMSEncoderContext *ecx;
1549
 
        SECItem output = { 0, 0, 0 };
1550
 
 
1551
 
        if (!arena) {
1552
 
            fprintf(stderr, "%s: out of memory.\n", progName);
1553
 
            exit(1);
1554
 
        }
1555
 
 
1556
 
        if (cms_verbose) {
1557
 
            fprintf(stderr, "cmsg [%p]\n", cmsg);
1558
 
            fprintf(stderr, "arena [%p]\n", arena);
1559
 
            if (pwcb_arg && (PW_PLAINTEXT == ((secuPWData*)pwcb_arg)->source))
1560
 
                fprintf(stderr, "password [%s]\n",
1561
 
                        ((secuPWData*)pwcb_arg)->data);
1562
 
            else
1563
 
                fprintf(stderr, "password [NULL]\n");
1564
 
        }
1565
 
        ecx = NSS_CMSEncoder_Start(cmsg, 
1566
 
                                   NULL, NULL,     /* DER output callback  */
1567
 
                                   &output, arena, /* destination storage  */
1568
 
                                   pwcb, pwcb_arg, /* password callback    */
1569
 
                                   NULL, NULL,     /* decrypt key callback */
1570
 
                                   NULL, NULL );   /* detached digests    */
1571
 
        if (!ecx) {
1572
 
            fprintf(stderr, "%s: cannot create encoder context.\n", progName);
1573
 
            exit(1);
1574
 
        }
1575
 
        if (cms_verbose) {
1576
 
            fprintf(stderr, "input len [%d]\n", input.len);
1577
 
            { unsigned int j; 
1578
 
                for(j=0;j<input.len;j++)
1579
 
             fprintf(stderr, "%2x%c", input.data[j], (j>0&&j%35==0)?'\n':' ');
1580
 
            }
1581
 
        }
1582
 
        if (input.len > 0) { /* skip if certs-only (or other zero content) */
1583
 
            rv = NSS_CMSEncoder_Update(ecx, (char *)input.data, input.len);
1584
 
            if (rv) {
1585
 
                fprintf(stderr, 
1586
 
                        "%s: failed to add data to encoder.\n", progName);
1587
 
                exit(1);
1588
 
            }
1589
 
        }
1590
 
        rv = NSS_CMSEncoder_Finish(ecx);
1591
 
        if (rv) {
1592
 
            SECU_PrintError(progName, "failed to encode data");
1593
 
            exit(1);
1594
 
        }
1595
 
 
1596
 
        if (cms_verbose) {
1597
 
            fprintf(stderr, "encoding passed\n");
1598
 
        }
1599
 
        fwrite(output.data, output.len, 1, outFile);
1600
 
        if (cms_verbose) {
1601
 
            fprintf(stderr, "wrote to file\n");
1602
 
        }
1603
 
        PORT_FreeArena(arena, PR_FALSE);
1604
 
    }
1605
 
    if (cmsg)
1606
 
        NSS_CMSMessage_Destroy(cmsg);
1607
 
    if (outFile != stdout)
1608
 
        fclose(outFile);
1609
 
 
1610
 
    SECITEM_FreeItem(&decodeOptions.content, PR_FALSE);
1611
 
    SECITEM_FreeItem(&envmsg, PR_FALSE);
1612
 
    SECITEM_FreeItem(&input, PR_FALSE);
1613
 
    if (NSS_Shutdown() != SECSuccess) {
1614
 
        SECU_PrintError(progName, "NSS_Shutdown failed");
1615
 
        exitstatus = 1;
1616
 
    }
1617
 
    PR_Cleanup();
1618
 
    return exitstatus;
1619
 
}