1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * cmsutil -- A command to work with CMS data
40 * $Id: cmsutil.c,v 1.53 2006/08/05 01:19:23 julien.pierre.bugs%sun.com Exp $
67 char *progName
= NULL
;
68 static int cms_verbose
= 0;
69 static secuPWData pwdata
= { PW_NONE
, 0 };
70 static PK11PasswordFunc pwcb
= NULL
;
71 static void *pwcb_arg
= NULL
;
74 /* XXX stolen from cmsarray.c
75 * nss_CMSArray_Count - count number of elements in array
78 nss_CMSArray_Count(void **array
)
83 while (*array
++ != NULL
)
89 DigestFile(PLArenaPool
*poolp
, SECItem
***digests
, SECItem
*input
,
90 SECAlgorithmID
**algids
)
92 NSSCMSDigestContext
*digcx
;
95 digcx
= NSS_CMSDigestContext_StartMultiple(algids
);
99 NSS_CMSDigestContext_Update(digcx
, input
->data
, input
->len
);
101 rv
= NSS_CMSDigestContext_FinishMultiple(digcx
, poolp
, digests
);
107 Usage(char *progName
)
110 "Usage: %s [-C|-D|-E|-O|-S] [<options>] [-d dbdir] [-u certusage]\n"
111 " -C create a CMS encrypted data message\n"
112 " -D decode a CMS message\n"
113 " -b decode a batch of files named in infile\n"
114 " -c content use this detached content\n"
115 " -n suppress output of content\n"
116 " -h num display num levels of CMS message info as email headers\n"
117 " -k keep decoded encryption certs in perm cert db\n"
118 " -E create a CMS enveloped data message\n"
119 " -r id,... create envelope for these recipients,\n"
120 " where id can be a certificate nickname or email address\n"
121 " -S create a CMS signed data message\n"
122 " -G include a signing time attribute\n"
123 " -H hash use hash (default:SHA1)\n"
124 " -N nick use certificate named \"nick\" for signing\n"
125 " -P include a SMIMECapabilities attribute\n"
126 " -T do not include content in CMS message\n"
127 " -Y nick include a EncryptionKeyPreference attribute with cert\n"
128 " (use \"NONE\" to omit)\n"
129 " -O create a CMS signed message containing only certificates\n"
130 " General Options:\n"
131 " -d dbdir key/cert database directory (default: ~/.netscape)\n"
132 " -e envelope enveloped data message in this file is used for bulk key\n"
133 " -i infile use infile as source of data (default: stdin)\n"
134 " -o outfile use outfile as destination of data (default: stdout)\n"
135 " -p password use password as key db password (default: prompt)\n"
136 " -u certusage set type of certificate usage (default: certUsageEmailSigner)\n"
137 " -v print debugging information\n"
139 "Cert usage codes:\n",
141 fprintf(stderr
, "%-25s 0 - certUsageSSLClient\n", " ");
142 fprintf(stderr
, "%-25s 1 - certUsageSSLServer\n", " ");
143 fprintf(stderr
, "%-25s 2 - certUsageSSLServerWithStepUp\n", " ");
144 fprintf(stderr
, "%-25s 3 - certUsageSSLCA\n", " ");
145 fprintf(stderr
, "%-25s 4 - certUsageEmailSigner\n", " ");
146 fprintf(stderr
, "%-25s 5 - certUsageEmailRecipient\n", " ");
147 fprintf(stderr
, "%-25s 6 - certUsageObjectSigner\n", " ");
148 fprintf(stderr
, "%-25s 7 - certUsageUserCertImport\n", " ");
149 fprintf(stderr
, "%-25s 8 - certUsageVerifyCA\n", " ");
150 fprintf(stderr
, "%-25s 9 - certUsageProtectedObjectSigner\n", " ");
151 fprintf(stderr
, "%-25s 10 - certUsageStatusResponder\n", " ");
152 fprintf(stderr
, "%-25s 11 - certUsageAnyCA\n", " ");
159 SECCertUsage certUsage
;
160 CERTCertDBHandle
*certHandle
;
163 struct decodeOptionsStr
{
164 struct optionsStr
*options
;
167 PRBool suppressContent
;
168 NSSCMSGetDecryptKeyCallback dkcb
;
173 struct signOptionsStr
{
174 struct optionsStr
*options
;
176 char *encryptionKeyPreferenceNick
;
180 SECOidTag hashAlgTag
;
183 struct envelopeOptionsStr
{
184 struct optionsStr
*options
;
188 struct certsonlyOptionsStr
{
189 struct optionsStr
*options
;
193 struct encryptOptionsStr
{
194 struct optionsStr
*options
;
196 NSSCMSMessage
*envmsg
;
201 SECOidTag bulkalgtag
;
205 static NSSCMSMessage
*
206 decode(FILE *out
, SECItem
*input
, const struct decodeOptionsStr
*decodeOptions
)
208 NSSCMSDecoderContext
*dcx
;
212 SECItem sitem
= { 0, 0, 0 };
215 dcx
= NSS_CMSDecoder_Start(NULL
,
216 NULL
, NULL
, /* content callback */
217 pwcb
, pwcb_arg
, /* password callback */
218 decodeOptions
->dkcb
, /* decrypt key callback */
219 decodeOptions
->bulkkey
);
221 fprintf(stderr
, "%s: failed to set up message decoder.\n", progName
);
224 rv
= NSS_CMSDecoder_Update(dcx
, (char *)input
->data
, input
->len
);
225 if (rv
!= SECSuccess
) {
226 fprintf(stderr
, "%s: failed to decode message.\n", progName
);
227 NSS_CMSDecoder_Cancel(dcx
);
230 cmsg
= NSS_CMSDecoder_Finish(dcx
);
232 fprintf(stderr
, "%s: failed to decode message.\n", progName
);
236 if (decodeOptions
->headerLevel
>= 0) {
237 /*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/
238 fprintf(out
, "SMIME: ");
241 nlevels
= NSS_CMSMessage_ContentLevelCount(cmsg
);
242 for (i
= 0; i
< nlevels
; i
++) {
243 NSSCMSContentInfo
*cinfo
;
246 cinfo
= NSS_CMSMessage_ContentLevel(cmsg
, i
);
247 typetag
= NSS_CMSContentInfo_GetContentTypeTag(cinfo
);
249 if (decodeOptions
->headerLevel
>= 0)
250 fprintf(out
, "\tlevel=%d.%d; ", decodeOptions
->headerLevel
, nlevels
- i
);
253 case SEC_OID_PKCS7_SIGNED_DATA
:
255 NSSCMSSignedData
*sigd
= NULL
;
260 if (decodeOptions
->headerLevel
>= 0)
261 fprintf(out
, "type=signedData; ");
262 sigd
= (NSSCMSSignedData
*)NSS_CMSContentInfo_GetContent(cinfo
);
264 SECU_PrintError(progName
, "signedData component missing");
268 /* if we have a content file, but no digests for this signedData */
269 if (decodeOptions
->content
.data
!= NULL
&&
270 !NSS_CMSSignedData_HasDigests(sigd
)) {
272 SECAlgorithmID
**digestalgs
;
274 /* detached content: grab content file */
275 sitem
= decodeOptions
->content
;
277 if ((poolp
= PORT_NewArena(1024)) == NULL
) {
278 fprintf(stderr
, "cmsutil: Out of memory.\n");
281 digestalgs
= NSS_CMSSignedData_GetDigestAlgs(sigd
);
282 if (DigestFile (poolp
, &digests
, &sitem
, digestalgs
)
284 SECU_PrintError(progName
,
285 "problem computing message digest");
286 PORT_FreeArena(poolp
, PR_FALSE
);
289 if (NSS_CMSSignedData_SetDigests(sigd
, digestalgs
, digests
)
291 SECU_PrintError(progName
,
292 "problem setting message digests");
293 PORT_FreeArena(poolp
, PR_FALSE
);
296 PORT_FreeArena(poolp
, PR_FALSE
);
299 /* import the certificates */
300 if (NSS_CMSSignedData_ImportCerts(sigd
,
301 decodeOptions
->options
->certHandle
,
302 decodeOptions
->options
->certUsage
,
303 decodeOptions
->keepCerts
)
305 SECU_PrintError(progName
, "cert import failed");
309 /* find out about signers */
310 nsigners
= NSS_CMSSignedData_SignerInfoCount(sigd
);
311 if (decodeOptions
->headerLevel
>= 0)
312 fprintf(out
, "nsigners=%d; ", nsigners
);
314 /* Might be a cert transport message
315 ** or might be an invalid message, such as a QA test message
316 ** or a message from an attacker.
319 rv
= NSS_CMSSignedData_VerifyCertsOnly(sigd
,
320 decodeOptions
->options
->certHandle
,
321 decodeOptions
->options
->certUsage
);
322 if (rv
!= SECSuccess
) {
323 fprintf(stderr
, "cmsutil: Verify certs-only failed!\n");
329 /* still no digests? */
330 if (!NSS_CMSSignedData_HasDigests(sigd
)) {
331 SECU_PrintError(progName
, "no message digests");
335 for (j
= 0; j
< nsigners
; j
++) {
337 NSSCMSSignerInfo
*si
;
338 NSSCMSVerificationStatus vs
;
341 si
= NSS_CMSSignedData_GetSignerInfo(sigd
, j
);
342 if (decodeOptions
->headerLevel
>= 0) {
344 static char empty
[] = { "" };
346 signercn
= NSS_CMSSignerInfo_GetSignerCommonName(si
);
347 if (signercn
== NULL
)
349 fprintf(out
, "\n\t\tsigner%d.id=\"%s\"; ", j
, signercn
);
350 if (signercn
!= empty
)
353 bad
= NSS_CMSSignedData_VerifySignerInfo(sigd
, j
,
354 decodeOptions
->options
->certHandle
,
355 decodeOptions
->options
->certUsage
);
356 vs
= NSS_CMSSignerInfo_GetVerificationStatus(si
);
357 svs
= NSS_CMSUtil_VerificationStatusToString(vs
);
358 if (decodeOptions
->headerLevel
>= 0) {
359 fprintf(out
, "signer%d.status=%s; ", j
, svs
);
361 } else if (bad
&& out
) {
362 fprintf(stderr
, "signer %d status = %s\n", j
, svs
);
368 case SEC_OID_PKCS7_ENVELOPED_DATA
:
370 NSSCMSEnvelopedData
*envd
;
371 if (decodeOptions
->headerLevel
>= 0)
372 fprintf(out
, "type=envelopedData; ");
373 envd
= (NSSCMSEnvelopedData
*)NSS_CMSContentInfo_GetContent(cinfo
);
375 SECU_PrintError(progName
, "envelopedData component missing");
380 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
382 NSSCMSEncryptedData
*encd
;
383 if (decodeOptions
->headerLevel
>= 0)
384 fprintf(out
, "type=encryptedData; ");
385 encd
= (NSSCMSEncryptedData
*)NSS_CMSContentInfo_GetContent(cinfo
);
387 SECU_PrintError(progName
, "encryptedData component missing");
392 case SEC_OID_PKCS7_DATA
:
393 if (decodeOptions
->headerLevel
>= 0)
394 fprintf(out
, "type=data; ");
399 if (decodeOptions
->headerLevel
>= 0)
403 if (!decodeOptions
->suppressContent
&& out
) {
404 SECItem
*item
= (sitem
.data
? &sitem
405 : NSS_CMSMessage_GetContent(cmsg
));
406 if (item
&& item
->data
&& item
->len
) {
407 fwrite(item
->data
, item
->len
, 1, out
);
414 NSS_CMSMessage_Destroy(cmsg
);
418 /* example of a callback function to use with encoder */
421 writeout(void *arg, const char *buf, unsigned long len)
423 FILE *f = (FILE *)arg;
425 if (f != NULL && buf != NULL)
426 (void)fwrite(buf, len, 1, f);
430 static NSSCMSMessage
*
431 signed_data(struct signOptionsStr
*signOptions
)
433 NSSCMSMessage
*cmsg
= NULL
;
434 NSSCMSContentInfo
*cinfo
;
435 NSSCMSSignedData
*sigd
;
436 NSSCMSSignerInfo
*signerinfo
;
437 CERTCertificate
*cert
= NULL
, *ekpcert
= NULL
;
440 fprintf(stderr
, "Input to signed_data:\n");
441 if (signOptions
->options
->password
)
442 fprintf(stderr
, "password [%s]\n", signOptions
->options
->password
);
444 fprintf(stderr
, "password [NULL]\n");
445 fprintf(stderr
, "certUsage [%d]\n", signOptions
->options
->certUsage
);
446 if (signOptions
->options
->certHandle
)
447 fprintf(stderr
, "certdb [%p]\n", signOptions
->options
->certHandle
);
449 fprintf(stderr
, "certdb [NULL]\n");
450 if (signOptions
->nickname
)
451 fprintf(stderr
, "nickname [%s]\n", signOptions
->nickname
);
453 fprintf(stderr
, "nickname [NULL]\n");
455 if (signOptions
->nickname
== NULL
) {
457 "ERROR: please indicate the nickname of a certificate to sign with.\n");
460 if ((cert
= CERT_FindUserCertByUsage(signOptions
->options
->certHandle
,
461 signOptions
->nickname
,
462 signOptions
->options
->certUsage
,
465 SECU_PrintError(progName
,
466 "the corresponding cert for key \"%s\" does not exist",
467 signOptions
->nickname
);
471 fprintf(stderr
, "Found certificate for %s\n", signOptions
->nickname
);
474 * create the message object
476 cmsg
= NSS_CMSMessage_Create(NULL
); /* create a message on its own pool */
478 fprintf(stderr
, "ERROR: cannot create CMS message.\n");
482 * build chain of objects: message->signedData->data
484 if ((sigd
= NSS_CMSSignedData_Create(cmsg
)) == NULL
) {
485 fprintf(stderr
, "ERROR: cannot create CMS signedData object.\n");
488 cinfo
= NSS_CMSMessage_GetContentInfo(cmsg
);
489 if (NSS_CMSContentInfo_SetContent_SignedData(cmsg
, cinfo
, sigd
)
491 fprintf(stderr
, "ERROR: cannot attach CMS signedData object.\n");
494 cinfo
= NSS_CMSSignedData_GetContentInfo(sigd
);
495 /* we're always passing data in and detaching optionally */
496 if (NSS_CMSContentInfo_SetContent_Data(cmsg
, cinfo
, NULL
,
497 signOptions
->detached
)
499 fprintf(stderr
, "ERROR: cannot attach CMS data object.\n");
503 * create & attach signer information
505 signerinfo
= NSS_CMSSignerInfo_Create(cmsg
, cert
, signOptions
->hashAlgTag
);
506 if (signerinfo
== NULL
) {
507 fprintf(stderr
, "ERROR: cannot create CMS signerInfo object.\n");
512 "Created CMS message, added signed data w/ signerinfo\n");
514 /* we want the cert chain included for this one */
515 if (NSS_CMSSignerInfo_IncludeCerts(signerinfo
, NSSCMSCM_CertChain
,
516 signOptions
->options
->certUsage
)
518 fprintf(stderr
, "ERROR: cannot find cert chain.\n");
522 fprintf(stderr
, "imported certificate\n");
524 if (signOptions
->signingTime
) {
525 if (NSS_CMSSignerInfo_AddSigningTime(signerinfo
, PR_Now())
527 fprintf(stderr
, "ERROR: cannot add signingTime attribute.\n");
531 if (signOptions
->smimeProfile
) {
532 if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo
) != SECSuccess
) {
533 fprintf(stderr
, "ERROR: cannot add SMIMECaps attribute.\n");
538 if (!signOptions
->encryptionKeyPreferenceNick
) {
539 /* check signing cert for fitness as encryption cert */
540 SECStatus FitForEncrypt
= CERT_CheckCertUsage(cert
,
541 certUsageEmailRecipient
);
543 if (SECSuccess
== FitForEncrypt
) {
544 /* if yes, add signing cert as EncryptionKeyPreference */
545 if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo
, cert
,
546 signOptions
->options
->certHandle
)
549 "ERROR: cannot add default SMIMEEncKeyPrefs attribute.\n");
552 if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo
, cert
,
553 signOptions
->options
->certHandle
)
556 "ERROR: cannot add default MS SMIMEEncKeyPrefs attribute.\n");
560 /* this is a dual-key cert case, we need to look for the encryption
561 certificate under the same nickname as the signing cert */
562 /* get the cert, add it to the message */
563 if ((ekpcert
= CERT_FindUserCertByUsage(
564 signOptions
->options
->certHandle
,
565 signOptions
->nickname
,
566 certUsageEmailRecipient
,
569 SECU_PrintError(progName
,
570 "the corresponding cert for key \"%s\" does not exist",
571 signOptions
->encryptionKeyPreferenceNick
);
574 if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,
575 signOptions
->options
->certHandle
)
578 "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n");
581 if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,
582 signOptions
->options
->certHandle
)
585 "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n");
588 if (NSS_CMSSignedData_AddCertificate(sigd
, ekpcert
) != SECSuccess
) {
589 fprintf(stderr
, "ERROR: cannot add encryption certificate.\n");
593 } else if (PL_strcmp(signOptions
->encryptionKeyPreferenceNick
, "NONE") == 0) {
596 /* get the cert, add it to the message */
597 if ((ekpcert
= CERT_FindUserCertByUsage(
598 signOptions
->options
->certHandle
,
599 signOptions
->encryptionKeyPreferenceNick
,
600 certUsageEmailRecipient
, PR_FALSE
, &pwdata
))
602 SECU_PrintError(progName
,
603 "the corresponding cert for key \"%s\" does not exist",
604 signOptions
->encryptionKeyPreferenceNick
);
607 if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo
, ekpcert
,
608 signOptions
->options
->certHandle
)
610 fprintf(stderr
, "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n");
613 if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo
, ekpcert
,
614 signOptions
->options
->certHandle
)
616 fprintf(stderr
, "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n");
619 if (NSS_CMSSignedData_AddCertificate(sigd
, ekpcert
) != SECSuccess
) {
620 fprintf(stderr
, "ERROR: cannot add encryption certificate.\n");
625 if (NSS_CMSSignedData_AddSignerInfo(sigd
, signerinfo
) != SECSuccess
) {
626 fprintf(stderr
, "ERROR: cannot add CMS signerInfo object.\n");
630 fprintf(stderr
, "created signed-data message\n");
633 CERT_DestroyCertificate(ekpcert
);
636 CERT_DestroyCertificate(cert
);
641 CERT_DestroyCertificate(ekpcert
);
644 CERT_DestroyCertificate(cert
);
646 NSS_CMSMessage_Destroy(cmsg
);
650 static NSSCMSMessage
*
651 enveloped_data(struct envelopeOptionsStr
*envelopeOptions
)
653 NSSCMSMessage
*cmsg
= NULL
;
654 NSSCMSContentInfo
*cinfo
;
655 NSSCMSEnvelopedData
*envd
;
656 NSSCMSRecipientInfo
*recipientinfo
;
657 CERTCertificate
**recipientcerts
= NULL
;
658 CERTCertDBHandle
*dbhandle
;
659 PLArenaPool
*tmppoolp
= NULL
;
660 SECOidTag bulkalgtag
;
663 dbhandle
= envelopeOptions
->options
->certHandle
;
664 /* count the recipients */
665 if ((cnt
= nss_CMSArray_Count((void **)envelopeOptions
->recipients
)) == 0) {
666 fprintf(stderr
, "ERROR: please name at least one recipient.\n");
669 if ((tmppoolp
= PORT_NewArena (1024)) == NULL
) {
670 fprintf(stderr
, "ERROR: out of memory.\n");
673 /* XXX find the recipient's certs by email address or nickname */
674 if ((recipientcerts
=
675 (CERTCertificate
**)PORT_ArenaZAlloc(tmppoolp
,
676 (cnt
+1)*sizeof(CERTCertificate
*)))
678 fprintf(stderr
, "ERROR: out of memory.\n");
681 for (i
=0; envelopeOptions
->recipients
[i
] != NULL
; i
++) {
682 if ((recipientcerts
[i
] =
683 CERT_FindCertByNicknameOrEmailAddr(dbhandle
,
684 envelopeOptions
->recipients
[i
]))
686 SECU_PrintError(progName
, "cannot find certificate for \"%s\"",
687 envelopeOptions
->recipients
[i
]);
692 recipientcerts
[i
] = NULL
;
694 /* find a nice bulk algorithm */
695 if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientcerts
, &bulkalgtag
,
696 &keysize
) != SECSuccess
) {
697 fprintf(stderr
, "ERROR: cannot find common bulk algorithm.\n");
701 * create the message object
703 cmsg
= NSS_CMSMessage_Create(NULL
); /* create a message on its own pool */
705 fprintf(stderr
, "ERROR: cannot create CMS message.\n");
709 * build chain of objects: message->envelopedData->data
711 if ((envd
= NSS_CMSEnvelopedData_Create(cmsg
, bulkalgtag
, keysize
))
713 fprintf(stderr
, "ERROR: cannot create CMS envelopedData object.\n");
716 cinfo
= NSS_CMSMessage_GetContentInfo(cmsg
);
717 if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg
, cinfo
, envd
)
719 fprintf(stderr
, "ERROR: cannot attach CMS envelopedData object.\n");
722 cinfo
= NSS_CMSEnvelopedData_GetContentInfo(envd
);
723 /* we're always passing data in, so the content is NULL */
724 if (NSS_CMSContentInfo_SetContent_Data(cmsg
, cinfo
, NULL
, PR_FALSE
)
726 fprintf(stderr
, "ERROR: cannot attach CMS data object.\n");
730 * create & attach recipient information
732 for (i
= 0; recipientcerts
[i
] != NULL
; i
++) {
733 if ((recipientinfo
= NSS_CMSRecipientInfo_Create(cmsg
,
736 fprintf(stderr
, "ERROR: cannot create CMS recipientInfo object.\n");
739 if (NSS_CMSEnvelopedData_AddRecipient(envd
, recipientinfo
)
741 fprintf(stderr
, "ERROR: cannot add CMS recipientInfo object.\n");
744 CERT_DestroyCertificate(recipientcerts
[i
]);
747 PORT_FreeArena(tmppoolp
, PR_FALSE
);
750 if (recipientcerts
) {
751 for (; recipientcerts
[i
] != NULL
; i
++) {
752 CERT_DestroyCertificate(recipientcerts
[i
]);
756 NSS_CMSMessage_Destroy(cmsg
);
758 PORT_FreeArena(tmppoolp
, PR_FALSE
);
762 PK11SymKey
*dkcb(void *arg
, SECAlgorithmID
*algid
)
764 return (PK11SymKey
*)arg
;
768 get_enc_params(struct encryptOptionsStr
*encryptOptions
)
770 struct envelopeOptionsStr envelopeOptions
;
771 SECStatus rv
= SECFailure
;
772 NSSCMSMessage
*env_cmsg
;
773 NSSCMSContentInfo
*cinfo
;
776 * construct an enveloped data message to obtain bulk keys
778 if (encryptOptions
->envmsg
) {
779 env_cmsg
= encryptOptions
->envmsg
; /* get it from an old message */
781 SECItem dummyOut
= { 0, 0, 0 };
782 SECItem dummyIn
= { 0, 0, 0 };
783 char str
[] = "Hello!";
784 PLArenaPool
*tmparena
= PORT_NewArena(1024);
785 dummyIn
.data
= (unsigned char *)str
;
786 dummyIn
.len
= strlen(str
);
787 envelopeOptions
.options
= encryptOptions
->options
;
788 envelopeOptions
.recipients
= encryptOptions
->recipients
;
789 env_cmsg
= enveloped_data(&envelopeOptions
);
790 NSS_CMSDEREncode(env_cmsg
, &dummyIn
, &dummyOut
, tmparena
);
791 PR_Write(encryptOptions
->envFile
, dummyOut
.data
, dummyOut
.len
);
792 PORT_FreeArena(tmparena
, PR_FALSE
);
795 * get the content info for the enveloped data
797 nlevels
= NSS_CMSMessage_ContentLevelCount(env_cmsg
);
798 for (i
= 0; i
< nlevels
; i
++) {
800 cinfo
= NSS_CMSMessage_ContentLevel(env_cmsg
, i
);
801 typetag
= NSS_CMSContentInfo_GetContentTypeTag(cinfo
);
802 if (typetag
== SEC_OID_PKCS7_DATA
) {
804 * get the symmetric key
806 encryptOptions
->bulkalgtag
= NSS_CMSContentInfo_GetContentEncAlgTag(cinfo
);
807 encryptOptions
->keysize
= NSS_CMSContentInfo_GetBulkKeySize(cinfo
);
808 encryptOptions
->bulkkey
= NSS_CMSContentInfo_GetBulkKey(cinfo
);
814 fprintf(stderr
, "%s: could not retrieve enveloped data.", progName
);
817 NSS_CMSMessage_Destroy(env_cmsg
);
821 static NSSCMSMessage
*
822 encrypted_data(struct encryptOptionsStr
*encryptOptions
)
824 SECStatus rv
= SECFailure
;
825 NSSCMSMessage
*cmsg
= NULL
;
826 NSSCMSContentInfo
*cinfo
;
827 NSSCMSEncryptedData
*encd
;
828 NSSCMSEncoderContext
*ecx
= NULL
;
829 PLArenaPool
*tmppoolp
= NULL
;
830 SECItem derOut
= { 0, 0, 0 };
831 /* arena for output */
832 tmppoolp
= PORT_NewArena(1024);
834 fprintf(stderr
, "%s: out of memory.\n", progName
);
838 * create the message object
840 cmsg
= NSS_CMSMessage_Create(NULL
);
842 fprintf(stderr
, "ERROR: cannot create CMS message.\n");
846 * build chain of objects: message->encryptedData->data
848 if ((encd
= NSS_CMSEncryptedData_Create(cmsg
, encryptOptions
->bulkalgtag
,
849 encryptOptions
->keysize
))
851 fprintf(stderr
, "ERROR: cannot create CMS encryptedData object.\n");
854 cinfo
= NSS_CMSMessage_GetContentInfo(cmsg
);
855 if (NSS_CMSContentInfo_SetContent_EncryptedData(cmsg
, cinfo
, encd
)
857 fprintf(stderr
, "ERROR: cannot attach CMS encryptedData object.\n");
860 cinfo
= NSS_CMSEncryptedData_GetContentInfo(encd
);
861 /* we're always passing data in, so the content is NULL */
862 if (NSS_CMSContentInfo_SetContent_Data(cmsg
, cinfo
, NULL
, PR_FALSE
)
864 fprintf(stderr
, "ERROR: cannot attach CMS data object.\n");
867 ecx
= NSS_CMSEncoder_Start(cmsg
, NULL
, NULL
, &derOut
, tmppoolp
, NULL
, NULL
,
868 dkcb
, encryptOptions
->bulkkey
, NULL
, NULL
);
870 fprintf(stderr
, "%s: cannot create encoder context.\n", progName
);
873 rv
= NSS_CMSEncoder_Update(ecx
, (char *)encryptOptions
->input
->data
,
874 encryptOptions
->input
->len
);
876 fprintf(stderr
, "%s: failed to add data to encoder.\n", progName
);
879 rv
= NSS_CMSEncoder_Finish(ecx
);
881 fprintf(stderr
, "%s: failed to encrypt data.\n", progName
);
884 fwrite(derOut
.data
, derOut
.len
, 1, encryptOptions
->outfile
);
887 PK11_FreeSymKey(bulkkey);
890 PORT_FreeArena(tmppoolp
, PR_FALSE
);
895 PK11_FreeSymKey(bulkkey);
898 PORT_FreeArena(tmppoolp
, PR_FALSE
);
900 NSS_CMSMessage_Destroy(cmsg
);
904 static NSSCMSMessage
*
905 signed_data_certsonly(struct certsonlyOptionsStr
*certsonlyOptions
)
907 NSSCMSMessage
*cmsg
= NULL
;
908 NSSCMSContentInfo
*cinfo
;
909 NSSCMSSignedData
*sigd
;
910 CERTCertificate
**certs
= NULL
;
911 CERTCertDBHandle
*dbhandle
;
912 PLArenaPool
*tmppoolp
= NULL
;
914 dbhandle
= certsonlyOptions
->options
->certHandle
;
915 if ((cnt
= nss_CMSArray_Count((void**)certsonlyOptions
->recipients
)) == 0) {
917 "ERROR: please indicate the nickname of a certificate to sign with.\n");
920 if (!(tmppoolp
= PORT_NewArena(1024))) {
921 fprintf(stderr
, "ERROR: out of memory.\n");
924 if (!(certs
= PORT_ArenaZNewArray(tmppoolp
, CERTCertificate
*, cnt
+ 1))) {
925 fprintf(stderr
, "ERROR: out of memory.\n");
928 for (i
=0; certsonlyOptions
->recipients
[i
] != NULL
; i
++) {
930 CERT_FindCertByNicknameOrEmailAddr(dbhandle
,
931 certsonlyOptions
->recipients
[i
]))
933 SECU_PrintError(progName
, "cannot find certificate for \"%s\"",
934 certsonlyOptions
->recipients
[i
]);
942 * create the message object
944 cmsg
= NSS_CMSMessage_Create(NULL
);
946 fprintf(stderr
, "ERROR: cannot create CMS message.\n");
950 * build chain of objects: message->signedData->data
952 if ((sigd
= NSS_CMSSignedData_CreateCertsOnly(cmsg
, certs
[0], PR_TRUE
))
954 fprintf(stderr
, "ERROR: cannot create CMS signedData object.\n");
957 CERT_DestroyCertificate(certs
[0]);
958 for (i
=1; i
<cnt
; i
++) {
959 if (NSS_CMSSignedData_AddCertChain(sigd
, certs
[i
])) {
960 fprintf(stderr
, "ERROR: cannot add cert chain for \"%s\".\n",
961 certsonlyOptions
->recipients
[i
]);
964 CERT_DestroyCertificate(certs
[i
]);
966 cinfo
= NSS_CMSMessage_GetContentInfo(cmsg
);
967 if (NSS_CMSContentInfo_SetContent_SignedData(cmsg
, cinfo
, sigd
)
969 fprintf(stderr
, "ERROR: cannot attach CMS signedData object.\n");
972 cinfo
= NSS_CMSSignedData_GetContentInfo(sigd
);
973 if (NSS_CMSContentInfo_SetContent_Data(cmsg
, cinfo
, NULL
, PR_FALSE
)
975 fprintf(stderr
, "ERROR: cannot attach CMS data object.\n");
979 PORT_FreeArena(tmppoolp
, PR_FALSE
);
984 CERT_DestroyCertificate(certs
[i
]);
988 NSS_CMSMessage_Destroy(cmsg
);
990 PORT_FreeArena(tmppoolp
, PR_FALSE
);
995 pl_fgets(char * buf
, int size
, PRFileDesc
* fd
)
1001 nb
= PR_Read(fd
, bp
, 1);
1003 /* deal with error */
1005 } else if (nb
== 0) {
1008 } else if (*bp
== '\n') {
1010 ++bp
; /* keep EOL character */
1013 /* ordinary character */
1022 typedef enum { UNKNOWN
, DECODE
, SIGN
, ENCRYPT
, ENVELOPE
, CERTSONLY
} Mode
;
1025 doBatchDecode(FILE *outFile
, PRFileDesc
*batchFile
,
1026 const struct decodeOptionsStr
*decodeOptions
)
1030 char batchLine
[512];
1032 while (NULL
!= (str
= pl_fgets(batchLine
, sizeof batchLine
, batchFile
))) {
1033 NSSCMSMessage
*cmsg
= NULL
;
1034 PRFileDesc
* inFile
;
1035 int len
= strlen(str
);
1037 SECItem input
= {0, 0, 0};
1041 ((cc
= str
[len
- 1]) == '\n' || cc
== '\r')) {
1044 if (!len
) /* skip empty line */
1047 continue; /* skip comment line */
1048 fprintf(outFile
, "========== %s ==========\n", str
);
1049 inFile
= PR_Open(str
, PR_RDONLY
, 00660);
1050 if (inFile
== NULL
) {
1051 fprintf(outFile
, "%s: unable to open \"%s\" for reading\n",
1056 rv
= SECU_FileToItem(&input
, inFile
);
1058 if (rv
!= SECSuccess
) {
1059 SECU_PrintError(progName
, "unable to read infile");
1063 cmsg
= decode(outFile
, &input
, decodeOptions
);
1064 SECITEM_FreeItem(&input
, PR_FALSE
);
1066 NSS_CMSMessage_Destroy(cmsg
);
1068 SECU_PrintError(progName
, "problem decoding");
1076 main(int argc
, char **argv
)
1079 NSSCMSMessage
*cmsg
= NULL
;
1081 PLOptState
*optstate
;
1083 Mode mode
= UNKNOWN
;
1084 struct decodeOptionsStr decodeOptions
= { 0 };
1085 struct signOptionsStr signOptions
= { 0 };
1086 struct envelopeOptionsStr envelopeOptions
= { 0 };
1087 struct certsonlyOptionsStr certsonlyOptions
= { 0 };
1088 struct encryptOptionsStr encryptOptions
= { 0 };
1089 struct optionsStr options
= { 0 };
1091 static char *ptrarray
[128] = { 0 };
1092 int nrecipients
= 0;
1095 SECItem input
= { 0, 0, 0};
1096 SECItem envmsg
= { 0, 0, 0 };
1098 PRFileDesc
*contentFile
= NULL
;
1099 PRBool batch
= PR_FALSE
;
1102 const char *ev
= PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
1104 ev
= PR_GetEnv("NSS_STRICT_SHUTDOWN");
1108 progName
= strrchr(argv
[0], '/');
1110 progName
= strrchr(argv
[0], '\\');
1111 progName
= progName
? progName
+1 : argv
[0];
1117 decodeOptions
.content
.data
= NULL
;
1118 decodeOptions
.content
.len
= 0;
1119 decodeOptions
.suppressContent
= PR_FALSE
;
1120 decodeOptions
.headerLevel
= -1;
1121 decodeOptions
.keepCerts
= PR_FALSE
;
1122 options
.certUsage
= certUsageEmailSigner
;
1123 options
.password
= NULL
;
1124 signOptions
.nickname
= NULL
;
1125 signOptions
.detached
= PR_FALSE
;
1126 signOptions
.signingTime
= PR_FALSE
;
1127 signOptions
.smimeProfile
= PR_FALSE
;
1128 signOptions
.encryptionKeyPreferenceNick
= NULL
;
1129 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1130 envelopeOptions
.recipients
= NULL
;
1131 encryptOptions
.recipients
= NULL
;
1132 encryptOptions
.envmsg
= NULL
;
1133 encryptOptions
.envFile
= NULL
;
1134 encryptOptions
.bulkalgtag
= SEC_OID_UNKNOWN
;
1135 encryptOptions
.bulkkey
= NULL
;
1136 encryptOptions
.keysize
= -1;
1139 * Parse command line arguments
1141 optstate
= PL_CreateOptState(argc
, argv
,
1142 "CDEGH:N:OPSTY:bc:d:e:h:i:kno:p:r:s:u:v");
1143 while ((status
= PL_GetNextOpt(optstate
)) == PL_OPT_OK
) {
1144 switch (optstate
->option
) {
1157 "%s: option -G only supported with option -S.\n",
1162 signOptions
.signingTime
= PR_TRUE
;
1167 "%s: option -H only supported with option -S.\n",
1172 decodeOptions
.suppressContent
= PR_TRUE
;
1173 if (!strcmp(optstate
->value
, "MD2"))
1174 signOptions
.hashAlgTag
= SEC_OID_MD2
;
1175 else if (!strcmp(optstate
->value
, "MD4"))
1176 signOptions
.hashAlgTag
= SEC_OID_MD4
;
1177 else if (!strcmp(optstate
->value
, "MD5"))
1178 signOptions
.hashAlgTag
= SEC_OID_MD5
;
1179 else if (!strcmp(optstate
->value
, "SHA1"))
1180 signOptions
.hashAlgTag
= SEC_OID_SHA1
;
1181 else if (!strcmp(optstate
->value
, "SHA256"))
1182 signOptions
.hashAlgTag
= SEC_OID_SHA256
;
1183 else if (!strcmp(optstate
->value
, "SHA384"))
1184 signOptions
.hashAlgTag
= SEC_OID_SHA384
;
1185 else if (!strcmp(optstate
->value
, "SHA512"))
1186 signOptions
.hashAlgTag
= SEC_OID_SHA512
;
1189 "%s: -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512\n",
1197 "%s: option -N only supported with option -S.\n",
1202 signOptions
.nickname
= strdup(optstate
->value
);
1210 "%s: option -P only supported with option -S.\n",
1215 signOptions
.smimeProfile
= PR_TRUE
;
1223 "%s: option -T only supported with option -S.\n",
1228 signOptions
.detached
= PR_TRUE
;
1233 "%s: option -Y only supported with option -S.\n",
1238 signOptions
.encryptionKeyPreferenceNick
= strdup(optstate
->value
);
1242 if (mode
!= DECODE
) {
1244 "%s: option -b only supported with option -D.\n",
1253 if (mode
!= DECODE
) {
1255 "%s: option -c only supported with option -D.\n",
1260 contentFile
= PR_Open(optstate
->value
, PR_RDONLY
, 006600);
1261 if (contentFile
== NULL
) {
1262 fprintf(stderr
, "%s: unable to open \"%s\" for reading.\n",
1263 progName
, optstate
->value
);
1267 rv
= SECU_FileToItem(&decodeOptions
.content
, contentFile
);
1268 PR_Close(contentFile
);
1269 if (rv
!= SECSuccess
) {
1270 SECU_PrintError(progName
, "problem reading content file");
1273 if (!decodeOptions
.content
.data
) {
1274 /* file was zero length */
1275 decodeOptions
.content
.data
= (unsigned char *)PORT_Strdup("");
1276 decodeOptions
.content
.len
= 0;
1281 SECU_ConfigDirectory(optstate
->value
);
1284 envFileName
= strdup(optstate
->value
);
1285 encryptOptions
.envFile
= PR_Open(envFileName
, PR_RDONLY
, 00660);
1289 if (mode
!= DECODE
) {
1291 "%s: option -h only supported with option -D.\n",
1296 decodeOptions
.headerLevel
= atoi(optstate
->value
);
1297 if (decodeOptions
.headerLevel
< 0) {
1298 fprintf(stderr
, "option -h cannot have a negative value.\n");
1303 if (!optstate
->value
) {
1304 fprintf(stderr
, "-i option requires filename argument\n");
1307 inFile
= PR_Open(optstate
->value
, PR_RDONLY
, 00660);
1308 if (inFile
== NULL
) {
1309 fprintf(stderr
, "%s: unable to open \"%s\" for reading\n",
1310 progName
, optstate
->value
);
1316 if (mode
!= DECODE
) {
1318 "%s: option -k only supported with option -D.\n",
1323 decodeOptions
.keepCerts
= PR_TRUE
;
1327 if (mode
!= DECODE
) {
1329 "%s: option -n only supported with option -D.\n",
1334 decodeOptions
.suppressContent
= PR_TRUE
;
1337 outFile
= fopen(optstate
->value
, "wb");
1338 if (outFile
== NULL
) {
1339 fprintf(stderr
, "%s: unable to open \"%s\" for writing\n",
1340 progName
, optstate
->value
);
1345 if (!optstate
->value
) {
1346 fprintf(stderr
, "%s: option -p must have a value.\n", progName
);
1351 options
.password
= strdup(optstate
->value
);
1355 if (!optstate
->value
) {
1356 fprintf(stderr
, "%s: option -r must have a value.\n", progName
);
1360 envelopeOptions
.recipients
= ptrarray
;
1361 str
= (char *)optstate
->value
;
1363 tok
= strchr(str
, ',');
1364 if (tok
) *tok
= '\0';
1365 envelopeOptions
.recipients
[nrecipients
++] = strdup(str
);
1366 if (tok
) str
= tok
+ 1;
1368 envelopeOptions
.recipients
[nrecipients
] = NULL
;
1369 encryptOptions
.recipients
= envelopeOptions
.recipients
;
1370 certsonlyOptions
.recipients
= envelopeOptions
.recipients
;
1376 usageType
= atoi (strdup(optstate
->value
));
1377 if (usageType
< certUsageSSLClient
|| usageType
> certUsageAnyCA
)
1379 options
.certUsage
= (SECCertUsage
)usageType
;
1388 if (status
== PL_OPT_BAD
)
1390 PL_DestroyOptState(optstate
);
1392 if (mode
== UNKNOWN
)
1395 if (mode
!= CERTSONLY
&& !batch
) {
1396 rv
= SECU_FileToItem(&input
, inFile
);
1397 if (rv
!= SECSuccess
) {
1398 SECU_PrintError(progName
, "unable to read infile");
1401 if (inFile
!= PR_STDIN
) {
1406 fprintf(stderr
, "received commands\n");
1409 /* Call the libsec initialization routines */
1410 PR_Init(PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
1411 rv
= NSS_InitReadWrite(SECU_ConfigDirectory(NULL
));
1412 if (SECSuccess
!= rv
) {
1413 SECU_PrintError(progName
, "NSS_Init failed");
1417 fprintf(stderr
, "NSS has been initialized.\n");
1419 options
.certHandle
= CERT_GetDefaultCertDB();
1420 if (!options
.certHandle
) {
1421 SECU_PrintError(progName
, "No default cert DB");
1425 fprintf(stderr
, "Got default certdb\n");
1427 if (options
.password
)
1429 pwdata
.source
= PW_PLAINTEXT
;
1430 pwdata
.data
= options
.password
;
1432 pwcb
= SECU_GetModulePassword
;
1433 pwcb_arg
= (void *)&pwdata
;
1435 PK11_SetPasswordFunc(&SECU_GetModulePassword
);
1439 if (outFile
== stdout
) {
1440 /* If we're going to write binary data to stdout, we must put stdout
1441 ** into O_BINARY mode or else outgoing \n's will become \r\n's.
1443 int smrv
= _setmode(_fileno(stdout
), _O_BINARY
);
1446 "%s: Cannot change stdout to binary mode. Use -o option instead.\n",
1455 case DECODE
: /* -D */
1456 decodeOptions
.options
= &options
;
1457 if (encryptOptions
.envFile
) {
1458 /* Decoding encrypted-data, so get the bulkkey from an
1459 * enveloped-data message.
1461 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1462 decodeOptions
.options
= &options
;
1463 encryptOptions
.envmsg
= decode(NULL
, &envmsg
, &decodeOptions
);
1464 if (!encryptOptions
.envmsg
) {
1465 SECU_PrintError(progName
, "problem decoding env msg");
1469 rv
= get_enc_params(&encryptOptions
);
1470 decodeOptions
.dkcb
= dkcb
;
1471 decodeOptions
.bulkkey
= encryptOptions
.bulkkey
;
1474 cmsg
= decode(outFile
, &input
, &decodeOptions
);
1476 SECU_PrintError(progName
, "problem decoding");
1480 exitstatus
= doBatchDecode(outFile
, inFile
, &decodeOptions
);
1481 if (inFile
!= PR_STDIN
) {
1487 signOptions
.options
= &options
;
1488 cmsg
= signed_data(&signOptions
);
1490 SECU_PrintError(progName
, "problem signing");
1494 case ENCRYPT
: /* -C */
1496 fprintf(stderr
, "%s: you must specify an envelope file with -e.\n",
1500 encryptOptions
.options
= &options
;
1501 encryptOptions
.input
= &input
;
1502 encryptOptions
.outfile
= outFile
;
1503 /* decode an enveloped-data message to get the bulkkey (create
1504 * a new one if neccessary)
1506 if (!encryptOptions
.envFile
) {
1507 encryptOptions
.envFile
= PR_Open(envFileName
,
1508 PR_WRONLY
|PR_CREATE_FILE
, 00660);
1509 if (!encryptOptions
.envFile
) {
1510 fprintf(stderr
, "%s: failed to create file %s.\n", progName
,
1515 SECU_FileToItem(&envmsg
, encryptOptions
.envFile
);
1516 decodeOptions
.options
= &options
;
1517 encryptOptions
.envmsg
= decode(NULL
, &envmsg
, &decodeOptions
);
1518 if (encryptOptions
.envmsg
== NULL
) {
1519 SECU_PrintError(progName
, "problem decrypting env msg");
1524 rv
= get_enc_params(&encryptOptions
);
1525 /* create the encrypted-data message */
1526 cmsg
= encrypted_data(&encryptOptions
);
1528 SECU_PrintError(progName
, "problem encrypting");
1531 if (encryptOptions
.bulkkey
) {
1532 PK11_FreeSymKey(encryptOptions
.bulkkey
);
1533 encryptOptions
.bulkkey
= NULL
;
1536 case ENVELOPE
: /* -E */
1537 envelopeOptions
.options
= &options
;
1538 cmsg
= enveloped_data(&envelopeOptions
);
1540 SECU_PrintError(progName
, "problem enveloping");
1544 case CERTSONLY
: /* -O */
1545 certsonlyOptions
.options
= &options
;
1546 cmsg
= signed_data_certsonly(&certsonlyOptions
);
1548 SECU_PrintError(progName
, "problem with certs-only");
1553 fprintf(stderr
, "One of options -D, -S or -E must be set.\n");
1557 if ( (mode
== SIGN
|| mode
== ENVELOPE
|| mode
== CERTSONLY
)
1558 && (!exitstatus
) ) {
1559 PLArenaPool
*arena
= PORT_NewArena(1024);
1560 NSSCMSEncoderContext
*ecx
;
1561 SECItem output
= { 0, 0, 0 };
1564 fprintf(stderr
, "%s: out of memory.\n", progName
);
1569 fprintf(stderr
, "cmsg [%p]\n", cmsg
);
1570 fprintf(stderr
, "arena [%p]\n", arena
);
1572 fprintf(stderr
, "password [%s]\n", (char *)pwcb_arg
);
1574 fprintf(stderr
, "password [NULL]\n");
1576 ecx
= NSS_CMSEncoder_Start(cmsg
,
1577 NULL
, NULL
, /* DER output callback */
1578 &output
, arena
, /* destination storage */
1579 pwcb
, pwcb_arg
, /* password callback */
1580 NULL
, NULL
, /* decrypt key callback */
1581 NULL
, NULL
); /* detached digests */
1583 fprintf(stderr
, "%s: cannot create encoder context.\n", progName
);
1587 fprintf(stderr
, "input len [%d]\n", input
.len
);
1589 for(j
=0;j
<input
.len
;j
++)
1590 fprintf(stderr
, "%2x%c", input
.data
[j
], (j
>0&&j
%35==0)?'\n':' ');
1593 if (input
.len
> 0) { /* skip if certs-only (or other zero content) */
1594 rv
= NSS_CMSEncoder_Update(ecx
, (char *)input
.data
, input
.len
);
1597 "%s: failed to add data to encoder.\n", progName
);
1601 rv
= NSS_CMSEncoder_Finish(ecx
);
1603 SECU_PrintError(progName
, "failed to encode data");
1608 fprintf(stderr
, "encoding passed\n");
1610 fwrite(output
.data
, output
.len
, 1, outFile
);
1612 fprintf(stderr
, "wrote to file\n");
1614 PORT_FreeArena(arena
, PR_FALSE
);
1617 NSS_CMSMessage_Destroy(cmsg
);
1618 if (outFile
!= stdout
)
1621 SECITEM_FreeItem(&decodeOptions
.content
, PR_FALSE
);
1622 SECITEM_FreeItem(&envmsg
, PR_FALSE
);
1623 SECITEM_FreeItem(&input
, PR_FALSE
);
1624 if (NSS_Shutdown() != SECSuccess
) {
1625 SECU_PrintError(progName
, "NSS_Shutdown failed");