Bug Summary

File:s/cmd/smimetools/cmsutil.c
Warning:line 1502, column 13
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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