gecko-dev/security/nss/cmd/smimetools/cmsutil.c

1344 lines
40 KiB
C
Raw Normal View History

2000-06-13 21:56:37 +00:00
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
/*
* cmsutil -- A command to work with CMS data
*
2000-12-11 18:42:58 +00:00
* $Id: cmsutil.c,v 1.19 2000/12/11 18:42:58 mcgreer%netscape.com Exp $
2000-06-13 21:56:37 +00:00
*/
#include "nspr.h"
#include "secutil.h"
#include "plgetopt.h"
#include "secpkcs7.h"
#include "cert.h"
#include "certdb.h"
#include "cdbhdl.h"
#include "secoid.h"
#include "cms.h"
#include "nss.h"
2000-06-13 21:56:37 +00:00
#include "smime.h"
#if defined(XP_UNIX)
#include <unistd.h>
#endif
#include <stdio.h>
#include <string.h>
extern void SEC_Init(void); /* XXX */
char *progName = NULL;
2000-06-13 21:56:37 +00:00
static SECStatus
DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input,
SECAlgorithmID **algids)
2000-06-13 21:56:37 +00:00
{
NSSCMSDigestContext *digcx;
digcx = NSS_CMSDigestContext_StartMultiple(algids);
if (digcx == NULL)
return SECFailure;
NSS_CMSDigestContext_Update(digcx, input->data, input->len);
2000-06-13 21:56:37 +00:00
return NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests);
2000-06-13 21:56:37 +00:00
}
static void
Usage(char *progName)
{
fprintf(stderr, "Usage: %s [-D|-S|-E] [<options>] [-d dbdir] [-u certusage]\n", progName);
fprintf(stderr, " -i infile use infile as source of data (default: stdin)\n");
fprintf(stderr, " -o outfile use outfile as destination of data (default: stdout)\n");
fprintf(stderr, " -d dbdir key/cert database directory (default: ~/.netscape)\n");
fprintf(stderr, " -p password use password as key db password (default: prompt)\n");
fprintf(stderr, " -u certusage set type of certificate usage (default: certUsageEmailSigner)\n");
fprintf(stderr, "\n");
fprintf(stderr, " -D decode a CMS message\n");
fprintf(stderr, " -c content use this detached content\n");
fprintf(stderr, " -n suppress output of content\n");
fprintf(stderr, " -h num generate email headers with info about CMS message\n");
fprintf(stderr, " -S create a CMS signed message\n");
fprintf(stderr, " -N nick use certificate named \"nick\" for signing\n");
fprintf(stderr, " -T do not include content in CMS message\n");
fprintf(stderr, " -G include a signing time attribute\n");
fprintf(stderr, " -P include a SMIMECapabilities attribute\n");
fprintf(stderr, " -Y nick include a EncryptionKeyPreference attribute with cert\n");
fprintf(stderr, " -E create a CMS enveloped message (NYI)\n");
fprintf(stderr, " -r id,... create envelope for these recipients,\n");
fprintf(stderr, " where id can be a certificate nickname or email address\n");
fprintf(stderr, "\nCert usage codes:\n");
fprintf(stderr, "%-25s 0 - certUsageSSLClient\n", " ");
fprintf(stderr, "%-25s 1 - certUsageSSLServer\n", " ");
fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUp\n", " ");
fprintf(stderr, "%-25s 3 - certUsageSSLCA\n", " ");
fprintf(stderr, "%-25s 4 - certUsageEmailSigner\n", " ");
fprintf(stderr, "%-25s 5 - certUsageEmailRecipient\n", " ");
fprintf(stderr, "%-25s 6 - certUsageObjectSigner\n", " ");
fprintf(stderr, "%-25s 7 - certUsageUserCertImport\n", " ");
fprintf(stderr, "%-25s 8 - certUsageVerifyCA\n", " ");
fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " ");
fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " ");
fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " ");
exit(-1);
}
static CERTCertDBHandle certHandleStatic; /* avoid having to allocate */
static CERTCertDBHandle *
OpenCertDB(char *progName)
{
CERTCertDBHandle *certHandle;
SECStatus rv;
certHandle = &certHandleStatic;
rv = CERT_OpenCertDB(certHandle, PR_FALSE, SECU_CertDBNameCallback, NULL);
if (rv != SECSuccess) {
SECU_PrintError(progName, "could not open cert database");
return NULL;
}
return certHandle;
}
char *
ownpw(PK11SlotInfo *info, PRBool retry, void *arg)
{
char * passwd = NULL;
if ( (!retry) && arg ) {
passwd = PL_strdup((char *)arg);
}
return passwd;
}
struct optionsStr {
char *password;
SECCertUsage certUsage;
CERTCertDBHandle *certHandle;
};
struct decodeOptionsStr {
struct optionsStr *options;
PRFileDesc *contentFile;
2000-06-13 21:56:37 +00:00
int headerLevel;
PRBool suppressContent;
NSSCMSGetDecryptKeyCallback dkcb;
PK11SymKey *bulkkey;
2000-06-13 21:56:37 +00:00
};
struct signOptionsStr {
struct optionsStr *options;
2000-06-13 21:56:37 +00:00
char *nickname;
char *encryptionKeyPreferenceNick;
PRBool signingTime;
PRBool smimeProfile;
PRBool detached;
};
struct envelopeOptionsStr {
struct optionsStr *options;
2000-06-13 21:56:37 +00:00
char **recipients;
};
struct certsonlyOptionsStr {
struct optionsStr *options;
char **recipients;
};
struct encryptOptionsStr {
struct optionsStr *options;
char **recipients;
NSSCMSMessage *envmsg;
SECItem *input;
FILE *outfile;
PRFileDesc *envFile;
PK11SymKey *bulkkey;
SECOidTag bulkalgtag;
int keysize;
};
static NSSCMSMessage *
decode(FILE *out, SECItem *output, SECItem *input,
struct decodeOptionsStr decodeOptions)
2000-06-13 21:56:37 +00:00
{
NSSCMSDecoderContext *dcx;
NSSCMSMessage *cmsg;
NSSCMSContentInfo *cinfo;
NSSCMSSignedData *sigd = NULL;
NSSCMSEnvelopedData *envd;
NSSCMSEncryptedData *encd;
2000-06-13 21:56:37 +00:00
SECAlgorithmID **digestalgs;
int nlevels, i, nsigners, j;
char *signercn;
NSSCMSSignerInfo *si;
SECOidTag typetag;
SECItem **digests;
PLArenaPool *poolp;
PK11PasswordFunc pwcb;
void *pwcb_arg;
SECItem *item, sitem = { 0, 0, 0 };
2000-06-13 21:56:37 +00:00
pwcb = (decodeOptions.options->password != NULL) ? ownpw : NULL;
pwcb_arg = (decodeOptions.options->password != NULL) ?
(void *)decodeOptions.options->password : NULL;
2000-06-13 21:56:37 +00:00
if (decodeOptions.contentFile) {
/* detached content: grab content file */
SECU_FileToItem(&sitem, decodeOptions.contentFile);
item = &sitem;
2000-06-13 21:56:37 +00:00
}
dcx = NSS_CMSDecoder_Start(NULL,
NULL, NULL, /* content callback */
pwcb, pwcb_arg, /* password callback */
decodeOptions.dkcb, /* decrypt key callback */
decodeOptions.bulkkey);
(void)NSS_CMSDecoder_Update(dcx, input->data, input->len);
2000-06-13 21:56:37 +00:00
cmsg = NSS_CMSDecoder_Finish(dcx);
if (cmsg == NULL) {
fprintf(stderr, "%s: failed to decode message.\n", progName);
return NULL;
}
2000-06-13 21:56:37 +00:00
if (decodeOptions.headerLevel >= 0) {
/*fprintf(out, "SMIME: ", decodeOptions.headerLevel, i);*/
fprintf(out, "SMIME: ");
2000-06-13 21:56:37 +00:00
}
nlevels = NSS_CMSMessage_ContentLevelCount(cmsg);
for (i = 0; i < nlevels; i++) {
cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);
typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
if (decodeOptions.headerLevel >= 0)
fprintf(out, "\tlevel=%d.%d; ", decodeOptions.headerLevel, nlevels - i);
switch (typetag) {
case SEC_OID_PKCS7_SIGNED_DATA:
if (decodeOptions.headerLevel >= 0)
fprintf(out, "type=signedData; ");
sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
if (sigd == NULL) {
SECU_PrintError(progName,
"problem finding signedData component");
goto loser;
2000-06-13 21:56:37 +00:00
}
/* if we have a content file, but no digests for this signedData */
if (decodeOptions.contentFile != NULL && !NSS_CMSSignedData_HasDigests(sigd)) {
if ((poolp = PORT_NewArena(1024)) == NULL) {
fprintf(stderr, "cmsutil: Out of memory.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
if (DigestFile (poolp, &digests, item, digestalgs)
!= SECSuccess) {
SECU_PrintError(progName,
"problem computing message digest");
goto loser;
2000-06-13 21:56:37 +00:00
}
if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) {
SECU_PrintError(progName,
"problem setting message digests");
goto loser;
2000-06-13 21:56:37 +00:00
}
PORT_FreeArena(poolp, PR_FALSE);
}
/* import the certificates */
if (NSS_CMSSignedData_ImportCerts(sigd,
decodeOptions.options->certHandle,
decodeOptions.options->certUsage,
PR_FALSE)
!= SECSuccess) {
SECU_PrintError(progName, "cert import failed");
goto loser;
2000-06-13 21:56:37 +00:00
}
/* find out about signers */
nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
if (decodeOptions.headerLevel >= 0)
fprintf(out, "nsigners=%d; ", nsigners);
if (nsigners == 0) {
/* must be a cert transport message */
SECStatus rv;
/* XXX workaround for bug #54014 */
NSS_CMSSignedData_ImportCerts(sigd,
decodeOptions.options->certHandle,
decodeOptions.options->certUsage,
PR_TRUE);
rv = NSS_CMSSignedData_VerifyCertsOnly(sigd,
decodeOptions.options->certHandle,
decodeOptions.options->certUsage);
if (rv != SECSuccess) {
fprintf(stderr, "cmsutil: Verify certs-only failed!\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
return cmsg;
}
2000-06-13 21:56:37 +00:00
/* still no digests? */
if (!NSS_CMSSignedData_HasDigests(sigd)) {
SECU_PrintError(progName, "no message digests");
goto loser;
}
for (j = 0; j < nsigners; j++) {
si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
signercn = NSS_CMSSignerInfo_GetSignerCommonName(si);
if (signercn == NULL)
signercn = "";
if (decodeOptions.headerLevel >= 0)
fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j, signercn);
(void)NSS_CMSSignedData_VerifySignerInfo(sigd, j,
decodeOptions.options->certHandle,
decodeOptions.options->certUsage);
if (decodeOptions.headerLevel >= 0)
fprintf(out, "signer%d.status=%s; ", j,
NSS_CMSUtil_VerificationStatusToString(
NSS_CMSSignerInfo_GetVerificationStatus(si)));
2000-06-13 21:56:37 +00:00
/* XXX what do we do if we don't print headers? */
}
break;
case SEC_OID_PKCS7_ENVELOPED_DATA:
if (decodeOptions.headerLevel >= 0)
fprintf(out, "type=envelopedData; ");
envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);
break;
case SEC_OID_PKCS7_ENCRYPTED_DATA:
if (decodeOptions.headerLevel >= 0)
fprintf(out, "type=encryptedData; ");
encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
break;
2000-06-13 21:56:37 +00:00
case SEC_OID_PKCS7_DATA:
if (decodeOptions.headerLevel >= 0)
fprintf(out, "type=data; ");
break;
default:
break;
}
if (decodeOptions.headerLevel >= 0)
fprintf(out, "\n");
}
if (!decodeOptions.suppressContent) {
if (!decodeOptions.contentFile)
item = NSS_CMSMessage_GetContent(cmsg);
SECITEM_CopyItem(NULL, output, item);
2000-06-13 21:56:37 +00:00
}
return cmsg;
loser:
if (cmsg)
NSS_CMSMessage_Destroy(cmsg);
return NULL;
2000-06-13 21:56:37 +00:00
}
/* example of a callback function to use with encoder */
/*
2000-06-13 21:56:37 +00:00
static void
writeout(void *arg, const char *buf, unsigned long len)
{
FILE *f = (FILE *)arg;
if (f != NULL && buf != NULL)
(void)fwrite(buf, len, 1, f);
}
*/
2000-06-13 21:56:37 +00:00
static NSSCMSMessage *
signed_data(struct signOptionsStr signOptions)
2000-06-13 21:56:37 +00:00
{
NSSCMSMessage *cmsg = NULL;
2000-06-13 21:56:37 +00:00
NSSCMSContentInfo *cinfo;
NSSCMSSignedData *sigd;
NSSCMSSignerInfo *signerinfo;
CERTCertificate *cert, *ekpcert;
2000-06-13 21:56:37 +00:00
#ifdef DEBUG
fprintf(stderr, "Input to signed_data:\n");
2000-12-07 18:38:27 +00:00
if (signOptions.options->password)
fprintf(stderr, "password [%s]\n", signOptions.options->password);
else
fprintf(stderr, "password [NULL]\n");
fprintf(stderr, "certUsage [%d]\n", signOptions.options->certUsage);
2000-12-07 18:38:27 +00:00
if (signOptions.options->certHandle)
fprintf(stderr, "certdb [%x]\n", signOptions.options->certHandle);
else
fprintf(stderr, "certdb [NULL]\n");
if (signOptions.nickname)
fprintf(stderr, "nickname [%s]\n", signOptions.nickname);
else
fprintf(stderr, "nickname [NULL]\n");
#endif
2000-06-13 21:56:37 +00:00
if (signOptions.nickname == NULL) {
fprintf(stderr,
"ERROR: please indicate the nickname of a certificate to sign with.\n");
return NULL;
2000-06-13 21:56:37 +00:00
}
if ((cert = CERT_FindCertByNickname(signOptions.options->certHandle,
signOptions.nickname)) == NULL) {
SECU_PrintError(progName,
"the corresponding cert for key \"%s\" does not exist",
signOptions.nickname);
return NULL;
2000-06-13 21:56:37 +00:00
}
#ifdef DEBUG
fprintf(stderr, "Found certificate for %s\n", signOptions.nickname);
#endif
2000-06-13 21:56:37 +00:00
/*
* create the message object
*/
cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
2000-06-13 21:56:37 +00:00
if (cmsg == NULL) {
fprintf(stderr, "ERROR: cannot create CMS message.\n");
return NULL;
2000-06-13 21:56:37 +00:00
}
/*
* build chain of objects: message->signedData->data
*/
if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
fprintf(stderr, "ERROR: cannot create CMS signedData object.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
!= SECSuccess) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
/* we're always passing data in and detaching optionally */
if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL,
signOptions.detached)
!= SECSuccess) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
/*
* create & attach signer information
*/
if ((signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, SEC_OID_SHA1))
== NULL) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot create CMS signerInfo object.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
#ifdef DEBUG
fprintf(stderr, "Created CMS message, added signed data w/ signerinfo\n");
#endif
2000-06-13 21:56:37 +00:00
/* we want the cert chain included for this one */
if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain,
signOptions.options->certUsage)
!= SECSuccess) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot find cert chain.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
#ifdef DEBUG
fprintf(stderr, "imported certificate\n");
#endif
2000-06-13 21:56:37 +00:00
if (signOptions.signingTime) {
if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now())
!= SECSuccess) {
2000-06-14 23:17:52 +00:00
fprintf(stderr, "ERROR: cannot add signingTime attribute.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
}
if (signOptions.smimeProfile) {
2000-06-14 23:17:52 +00:00
if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n");
goto loser;
2000-06-14 23:17:52 +00:00
}
2000-06-13 21:56:37 +00:00
}
if (signOptions.encryptionKeyPreferenceNick) {
/* get the cert, add it to the message */
if ((ekpcert = CERT_FindCertByNickname(signOptions.options->certHandle,
signOptions.encryptionKeyPreferenceNick))
== NULL) {
SECU_PrintError(progName,
"the corresponding cert for key \"%s\" does not exist",
signOptions.encryptionKeyPreferenceNick);
goto loser;
}
if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert,
signOptions.options->certHandle)
!= SECSuccess) {
fprintf(stderr, "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n");
goto loser;
}
if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
fprintf(stderr, "ERROR: cannot add encryption certificate.\n");
goto loser;
}
} else {
/* check signing cert for fitness as encryption cert */
/* if yes, add signing cert as EncryptionKeyPreference */
if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, cert,
signOptions.options->certHandle)
!= SECSuccess) {
fprintf(stderr,
"ERROR: cannot add default SMIMEEncKeyPrefs attribute.\n");
goto loser;
}
2000-06-13 21:56:37 +00:00
}
if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
fprintf(stderr, "ERROR: cannot add CMS signerInfo object.\n");
goto loser;
2000-06-13 21:56:37 +00:00
}
#ifdef DEBUG
fprintf(stderr, "created signed-date message\n");
#endif
return cmsg;
loser:
2000-06-13 21:56:37 +00:00
NSS_CMSMessage_Destroy(cmsg);
return NULL;
2000-06-13 21:56:37 +00:00
}
static NSSCMSMessage *
enveloped_data(struct envelopeOptionsStr envelopeOptions)
2000-06-13 21:56:37 +00:00
{
NSSCMSMessage *cmsg = NULL;
NSSCMSContentInfo *cinfo;
NSSCMSEnvelopedData *envd;
NSSCMSRecipientInfo *recipientinfo;
CERTCertificate **recipientcerts;
CERTCertDBHandle *dbhandle;
2000-06-13 21:56:37 +00:00
PLArenaPool *tmppoolp = NULL;
SECOidTag bulkalgtag;
int keysize, i;
int cnt;
dbhandle = envelopeOptions.options->certHandle;
/* count the recipients */
2000-06-13 21:56:37 +00:00
if ((cnt = NSS_CMSArray_Count(envelopeOptions.recipients)) == 0) {
fprintf(stderr, "ERROR: please name at least one recipient.\n");
2000-06-13 21:56:37 +00:00
goto loser;
}
if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
fprintf(stderr, "ERROR: out of memory.\n");
goto loser;
}
/* XXX find the recipient's certs by email address or nickname */
if ((recipientcerts =
2000-10-05 02:41:09 +00:00
(CERTCertificate **)PORT_ArenaZAlloc(tmppoolp,
(cnt+1)*sizeof(CERTCertificate*)))
== NULL) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: out of memory.\n");
goto loser;
}
for (i=0; envelopeOptions.recipients[i] != NULL; i++) {
if ((recipientcerts[i] =
CERT_FindCertByNicknameOrEmailAddr(dbhandle,
envelopeOptions.recipients[i]))
== NULL) {
SECU_PrintError(progName, "cannot find certificate for \"%s\"",
envelopeOptions.recipients[i]);
2000-06-13 21:56:37 +00:00
goto loser;
}
}
recipientcerts[i] = NULL;
/* find a nice bulk algorithm */
if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientcerts, &bulkalgtag,
&keysize) != SECSuccess) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot find common bulk algorithm.\n");
goto loser;
}
/*
* create the message object
*/
cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
2000-06-13 21:56:37 +00:00
if (cmsg == NULL) {
fprintf(stderr, "ERROR: cannot create CMS message.\n");
goto loser;
}
/*
* build chain of objects: message->envelopedData->data
*/
if ((envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, keysize))
== NULL) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot create CMS envelopedData object.\n");
goto loser;
}
cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd)
!= SECSuccess) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot attach CMS envelopedData object.\n");
goto loser;
}
cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
/* we're always passing data in, so the content is NULL */
if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE)
!= SECSuccess) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
goto loser;
}
/*
* create & attach recipient information
*/
for (i = 0; recipientcerts[i] != NULL; i++) {
if ((recipientinfo = NSS_CMSRecipientInfo_Create(cmsg,
recipientcerts[i]))
== NULL) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot create CMS recipientInfo object.\n");
goto loser;
}
if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientinfo)
!= SECSuccess) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "ERROR: cannot add CMS recipientInfo object.\n");
goto loser;
}
}
if (tmppoolp)
PORT_FreeArena(tmppoolp, PR_FALSE);
return cmsg;
loser:
if (cmsg)
NSS_CMSMessage_Destroy(cmsg);
if (tmppoolp)
PORT_FreeArena(tmppoolp, PR_FALSE);
return NULL;
}
2000-06-13 21:56:37 +00:00
PK11SymKey *dkcb(void *arg, SECAlgorithmID *algid)
{
return (PK11SymKey*)arg;
}
static SECStatus
get_enc_params(struct encryptOptionsStr *encryptOptions)
{
struct envelopeOptionsStr envelopeOptions;
SECStatus rv = SECFailure;
NSSCMSMessage *env_cmsg;
NSSCMSContentInfo *cinfo;
PK11SymKey *bulkkey = NULL;
SECOidTag bulkalgtag;
int keysize;
int i, nlevels;
/*
* construct an enveloped data message to obtain bulk keys
*/
if (encryptOptions->envmsg) {
env_cmsg = encryptOptions->envmsg; /* get it from an old message */
} else {
SECItem dummyOut = { 0, 0, 0 };
SECItem dummyIn = { 0, 0, 0 };
char str[] = "Hello!";
PLArenaPool *tmparena = PORT_NewArena(1024);
dummyIn.data = str;
dummyIn.len = strlen(str);
envelopeOptions.options = encryptOptions->options;
envelopeOptions.recipients = encryptOptions->recipients;
env_cmsg = enveloped_data(envelopeOptions);
NSS_CMSDEREncode(env_cmsg, &dummyIn, &dummyOut, tmparena);
PR_Write(encryptOptions->envFile, dummyOut.data, dummyOut.len);
PORT_FreeArena(tmparena, PR_FALSE);
}
/*
* get the content info for the enveloped data
*/
nlevels = NSS_CMSMessage_ContentLevelCount(env_cmsg);
for (i = 0; i < nlevels; i++) {
SECOidTag typetag;
cinfo = NSS_CMSMessage_ContentLevel(env_cmsg, i);
typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
if (typetag == SEC_OID_PKCS7_DATA) {
/*
* get the symmetric key
*/
bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo);
keysize = NSS_CMSContentInfo_GetBulkKeySize(cinfo);
bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
2000-06-13 21:56:37 +00:00
break;
}
}
if (i == nlevels) {
fprintf(stderr, "%s: could not retrieve enveloped data.", progName);
2000-06-13 21:56:37 +00:00
goto loser;
}
encryptOptions->bulkalgtag = bulkalgtag;
encryptOptions->bulkkey = bulkkey;
encryptOptions->keysize = keysize;
rv = SECSuccess;
loser:
if (env_cmsg)
NSS_CMSMessage_Destroy(env_cmsg);
return rv;
}
2000-06-13 21:56:37 +00:00
static NSSCMSMessage *
encrypted_data(struct encryptOptionsStr encryptOptions)
{
SECStatus rv = SECFailure;
NSSCMSMessage *cmsg = NULL;
NSSCMSContentInfo *cinfo;
NSSCMSEncryptedData *encd;
NSSCMSEncoderContext *ecx = NULL;
PLArenaPool *tmppoolp = NULL;
SECItem derOut = { 0, 0, 0 };
/* arena for output */
tmppoolp = PORT_NewArena(1024);
if (!tmppoolp) {
fprintf(stderr, "%s: out of memory.\n", progName);
return NULL;
}
/*
* create the message object
*/
cmsg = NSS_CMSMessage_Create(NULL);
if (cmsg == NULL) {
fprintf(stderr, "ERROR: cannot create CMS message.\n");
goto loser;
}
/*
* build chain of objects: message->encryptedData->data
*/
if ((encd = NSS_CMSEncryptedData_Create(cmsg, encryptOptions.bulkalgtag,
encryptOptions.keysize))
== NULL) {
fprintf(stderr, "ERROR: cannot create CMS encryptedData object.\n");
goto loser;
}
cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
if (NSS_CMSContentInfo_SetContent_EncryptedData(cmsg, cinfo, encd)
!= SECSuccess) {
fprintf(stderr, "ERROR: cannot attach CMS encryptedData object.\n");
goto loser;
}
cinfo = NSS_CMSEncryptedData_GetContentInfo(encd);
/* we're always passing data in, so the content is NULL */
if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE)
!= SECSuccess) {
fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
goto loser;
}
ecx = NSS_CMSEncoder_Start(cmsg, NULL, NULL, &derOut, tmppoolp, NULL, NULL,
dkcb, encryptOptions.bulkkey, NULL, NULL);
if (!ecx) {
fprintf(stderr, "%s: cannot create encoder context.\n", progName);
goto loser;
}
rv = NSS_CMSEncoder_Update(ecx, encryptOptions.input->data,
encryptOptions.input->len);
if (rv) {
fprintf(stderr, "%s: failed to add data to encoder.\n", progName);
goto loser;
}
rv = NSS_CMSEncoder_Finish(ecx);
if (rv) {
fprintf(stderr, "%s: failed to encrypt data.\n", progName);
goto loser;
}
fwrite(derOut.data, derOut.len, 1, encryptOptions.outfile);
/*
if (bulkkey)
PK11_FreeSymKey(bulkkey);
*/
if (tmppoolp)
PORT_FreeArena(tmppoolp, PR_FALSE);
return cmsg;
loser:
/*
if (bulkkey)
PK11_FreeSymKey(bulkkey);
*/
if (tmppoolp)
PORT_FreeArena(tmppoolp, PR_FALSE);
if (cmsg)
NSS_CMSMessage_Destroy(cmsg);
return NULL;
}
2000-06-13 21:56:37 +00:00
static NSSCMSMessage *
signed_data_certsonly(struct certsonlyOptionsStr certsonlyOptions)
{
NSSCMSMessage *cmsg = NULL;
NSSCMSContentInfo *cinfo;
NSSCMSSignedData *sigd;
CERTCertificate **certs;
CERTCertDBHandle *dbhandle;
PLArenaPool *tmppoolp = NULL;
int i, cnt;
dbhandle = certsonlyOptions.options->certHandle;
if ((cnt = NSS_CMSArray_Count(certsonlyOptions.recipients)) == 0) {
fprintf(stderr,
"ERROR: please indicate the nickname of a certificate to sign with.\n");
goto loser;
}
if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
fprintf(stderr, "ERROR: out of memory.\n");
goto loser;
}
if ((certs =
2000-10-05 02:41:09 +00:00
(CERTCertificate **)PORT_ArenaZAlloc(tmppoolp,
(cnt+1)*sizeof(CERTCertificate*)))
== NULL) {
fprintf(stderr, "ERROR: out of memory.\n");
goto loser;
}
for (i=0; certsonlyOptions.recipients[i] != NULL; i++) {
if ((certs[i] =
CERT_FindCertByNicknameOrEmailAddr(dbhandle,
certsonlyOptions.recipients[i]))
== NULL) {
SECU_PrintError(progName, "cannot find certificate for \"%s\"",
certsonlyOptions.recipients[i]);
goto loser;
}
}
certs[i] = NULL;
/*
* create the message object
*/
cmsg = NSS_CMSMessage_Create(NULL);
if (cmsg == NULL) {
fprintf(stderr, "ERROR: cannot create CMS message.\n");
goto loser;
}
/*
* build chain of objects: message->signedData->data
*/
if ((sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, certs[0], PR_TRUE))
== NULL) {
fprintf(stderr, "ERROR: cannot create CMS signedData object.\n");
goto loser;
}
for (i=1; i<cnt; i++) {
if (NSS_CMSSignedData_AddCertChain(sigd, certs[i])) {
fprintf(stderr, "ERROR: cannot add cert chain for \"%s\".\n",
certsonlyOptions.recipients[i]);
goto loser;
}
}
cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
!= SECSuccess) {
fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n");
goto loser;
}
cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE)
!= SECSuccess) {
fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
goto loser;
}
if (tmppoolp)
PORT_FreeArena(tmppoolp, PR_FALSE);
return cmsg;
2000-06-13 21:56:37 +00:00
loser:
if (cmsg)
NSS_CMSMessage_Destroy(cmsg);
if (tmppoolp)
PORT_FreeArena(tmppoolp, PR_FALSE);
return NULL;
2000-06-13 21:56:37 +00:00
}
typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode;
#if 0
void
parse_message_for_recipients(PRFileDesc *inFile,
struct envelopeOptionsStr *envelopeOptions)
{
SECItem filedata;
SECStatus rv;
rv = SECU_FileToItem(&filedata, inFile);
}
#endif
2000-06-13 21:56:37 +00:00
int
main(int argc, char **argv)
{
FILE *outFile;
NSSCMSMessage *cmsg;
PRFileDesc *inFile;
2000-06-13 21:56:37 +00:00
PLOptState *optstate;
PLOptStatus status;
Mode mode = UNKNOWN;
PK11PasswordFunc pwcb;
void *pwcb_arg;
2000-06-13 21:56:37 +00:00
struct decodeOptionsStr decodeOptions = { 0 };
struct signOptionsStr signOptions = { 0 };
struct envelopeOptionsStr envelopeOptions = { 0 };
struct certsonlyOptionsStr certsonlyOptions = { 0 };
struct encryptOptionsStr encryptOptions = { 0 };
2000-06-13 21:56:37 +00:00
struct optionsStr options = { 0 };
int exitstatus;
static char *ptrarray[128] = { 0 };
int nrecipients = 0;
char *str, *tok;
char *envFileName;
SECItem input = { 0, 0, 0};
SECItem output = { 0, 0, 0};
SECItem dummy = { 0, 0, 0 };
SECItem envmsg = { 0, 0, 0 };
SECStatus rv;
2000-06-13 21:56:37 +00:00
progName = strrchr(argv[0], '/');
progName = progName ? progName+1 : argv[0];
inFile = PR_STDIN;
2000-06-13 21:56:37 +00:00
outFile = stdout;
envFileName = NULL;
2000-06-13 21:56:37 +00:00
mode = UNKNOWN;
decodeOptions.contentFile = NULL;
decodeOptions.suppressContent = PR_FALSE;
decodeOptions.headerLevel = -1;
options.certUsage = certUsageEmailSigner;
options.password = NULL;
signOptions.nickname = NULL;
signOptions.detached = PR_FALSE;
signOptions.signingTime = PR_FALSE;
signOptions.smimeProfile = PR_FALSE;
signOptions.encryptionKeyPreferenceNick = NULL;
envelopeOptions.recipients = NULL;
encryptOptions.recipients = NULL;
encryptOptions.envmsg = NULL;
encryptOptions.envFile = NULL;
encryptOptions.bulkalgtag = SEC_OID_UNKNOWN;
encryptOptions.bulkkey = NULL;
encryptOptions.keysize = -1;
2000-06-13 21:56:37 +00:00
2000-12-06 22:35:52 +00:00
#ifdef DEBUG
fprintf(stderr, "starting program\n");
#endif
2000-06-13 21:56:37 +00:00
/*
* Parse command line arguments
*/
optstate = PL_CreateOptState(argc, argv,
"CDSEOnN:TGPY:h:p:i:c:d:e:o:s:u:r:");
2000-12-06 22:35:52 +00:00
#ifdef DEBUG
fprintf(stderr, "parsed command line\n");
#endif
2000-06-13 21:56:37 +00:00
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
Usage(progName);
break;
case 'C':
mode = ENCRYPT;
break;
2000-06-13 21:56:37 +00:00
case 'D':
mode = DECODE;
break;
case 'S':
mode = SIGN;
break;
case 'E':
mode = ENVELOPE;
break;
case 'O':
mode = CERTSONLY;
2000-06-13 21:56:37 +00:00
break;
case 'n':
if (mode != DECODE) {
fprintf(stderr,
"%s: option -n only supported with option -D.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
decodeOptions.suppressContent = PR_TRUE;
break;
case 'N':
if (mode != SIGN) {
fprintf(stderr,
"%s: option -N only supported with option -S.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
signOptions.nickname = strdup(optstate->value);
break;
case 'Y':
if (mode != SIGN) {
fprintf(stderr,
"%s: option -Y only supported with option -S.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
signOptions.encryptionKeyPreferenceNick = strdup(optstate->value);
break;
case 'T':
if (mode != SIGN) {
fprintf(stderr,
"%s: option -T only supported with option -S.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
signOptions.detached = PR_TRUE;
break;
case 'G':
if (mode != SIGN) {
fprintf(stderr,
"%s: option -G only supported with option -S.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
signOptions.signingTime = PR_TRUE;
break;
case 'P':
if (mode != SIGN) {
fprintf(stderr,
"%s: option -P only supported with option -S.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
signOptions.smimeProfile = PR_TRUE;
break;
case 'h':
if (mode != DECODE) {
fprintf(stderr,
"%s: option -h only supported with option -D.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
decodeOptions.headerLevel = atoi(optstate->value);
if (decodeOptions.headerLevel < 0) {
fprintf(stderr, "option -h cannot have a negative value.\n");
exit(1);
}
break;
case 'p':
if (!optstate->value) {
fprintf(stderr, "%s: option -p must have a value.\n", progName);
Usage(progName);
exit(1);
}
options.password = strdup(optstate->value);
break;
case 'i':
inFile = PR_Open(optstate->value, PR_RDONLY, 00660);
if (inFile == NULL) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
progName, optstate->value);
exit(1);
}
break;
case 'c':
if (mode != DECODE) {
fprintf(stderr,
"%s: option -c only supported with option -D.\n",
progName);
2000-06-13 21:56:37 +00:00
Usage(progName);
exit(1);
}
if ((decodeOptions.contentFile =
PR_Open(optstate->value, PR_RDONLY, 006600)) == NULL) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "%s: unable to open \"%s\" for reading.\n",
progName, optstate->value);
exit(1);
}
break;
case 'o':
2000-10-11 07:04:30 +00:00
#if 0
2000-10-11 06:52:06 +00:00
if (mode == DECODE) {
outFile = fopen(optstate->value, "w");
} else {
outFile = fopen(optstate->value, "wb");
}
2000-10-11 07:04:30 +00:00
#endif
outFile = fopen(optstate->value, "wb");
2000-10-11 06:52:06 +00:00
if (outFile == NULL) {
2000-06-13 21:56:37 +00:00
fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
progName, optstate->value);
exit(1);
}
break;
case 'r':
if (!optstate->value) {
fprintf(stderr, "%s: option -r must have a value.\n", progName);
Usage(progName);
exit(1);
}
#if 0
fprintf(stderr, "recipient = %s\n", optstate->value);
#endif
envelopeOptions.recipients = ptrarray;
str = optstate->value;
do {
tok = strchr(str, ',');
if (tok) *tok = '\0';
envelopeOptions.recipients[nrecipients++] = strdup(str);
if (tok) str = tok + 1;
} while (tok);
2000-06-13 21:56:37 +00:00
envelopeOptions.recipients[nrecipients] = NULL;
encryptOptions.recipients = envelopeOptions.recipients;
certsonlyOptions.recipients = envelopeOptions.recipients;
2000-06-13 21:56:37 +00:00
break;
case 'd':
SECU_ConfigDirectory(optstate->value);
break;
case 'e':
envFileName = strdup(optstate->value);
encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660);
break;
2000-06-13 21:56:37 +00:00
case 'u': {
int usageType;
usageType = atoi (strdup(optstate->value));
if (usageType < certUsageSSLClient || usageType > certUsageAnyCA)
return -1;
options.certUsage = (SECCertUsage)usageType;
break;
}
}
}
2000-12-11 18:42:58 +00:00
SECU_FileToItem(&input, inFile);
if (inFile != PR_STDIN)
PR_Close(inFile);
2000-12-06 22:35:52 +00:00
#ifdef DEBUG
fprintf(stderr, "received commands\n");
#endif
2000-06-13 21:56:37 +00:00
/* Call the libsec initialization routines */
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
if (SECSuccess != rv) {
SECU_PrintError(progName, "NSS_Init failed");
exit(1);
}
2000-12-06 22:35:52 +00:00
#ifdef DEBUG
fprintf(stderr, "NSS has been initialized.\n");
#endif
options.certHandle = CERT_GetDefaultCertDB();
if (!options.certHandle) {
SECU_PrintError(progName, "No default cert DB");
exit(1);
2000-06-13 21:56:37 +00:00
}
#ifdef DEBUG
2000-12-06 22:35:52 +00:00
fprintf(stderr, "Got default certdb\n");
#endif
2000-06-13 21:56:37 +00:00
2000-10-11 06:52:06 +00:00
#if defined(WIN32)
2000-10-11 07:12:45 +00:00
/*if (outFile == stdout && mode != DECODE) {*/
if (outFile == stdout) {
2000-10-11 06:52:06 +00:00
/* If we're going to write binary data to stdout, we must put stdout
2000-10-11 07:21:38 +00:00
** into O_BINARY mode or else outgoing \n's will become \r\n's.
2000-10-11 06:52:06 +00:00
*/
int smrv = _setmode(_fileno(stdout), _O_BINARY);
if (smrv == -1) {
fprintf(stderr,
"%s: Cannot change stdout to binary mode. Use -o option instead.\n",
progName);
return smrv;
}
}
#endif
2000-06-13 21:56:37 +00:00
exitstatus = 0;
switch (mode) {
case DECODE:
decodeOptions.options = &options;
if (encryptOptions.envFile) {
/* Decoding encrypted-data, so get the bulkkey from an
* enveloped-data message.
*/
SECU_FileToItem(&envmsg, encryptOptions.envFile);
decodeOptions.options = &options;
encryptOptions.envmsg = decode(NULL, &dummy, &envmsg,
decodeOptions);
rv = get_enc_params(&encryptOptions);
decodeOptions.dkcb = dkcb;
decodeOptions.bulkkey = encryptOptions.bulkkey;
}
cmsg = decode(outFile, &output, &input, decodeOptions);
if (!cmsg) {
2000-06-13 21:56:37 +00:00
SECU_PrintError(progName, "problem decoding");
exitstatus = 1;
}
fwrite(output.data, output.len, 1, outFile);
2000-06-13 21:56:37 +00:00
break;
case SIGN:
signOptions.options = &options;
cmsg = signed_data(signOptions);
if (!cmsg) {
2000-06-13 21:56:37 +00:00
SECU_PrintError(progName, "problem signing");
exitstatus = 1;
}
break;
case ENCRYPT:
if (!envFileName) {
fprintf(stderr, "%s: you must specify an envelope file with -e.\n",
progName);
exit(1);
}
encryptOptions.options = &options;
encryptOptions.input = &input;
encryptOptions.outfile = outFile;
if (!encryptOptions.envFile) {
encryptOptions.envFile = PR_Open(envFileName,
PR_WRONLY|PR_CREATE_FILE, 00660);
if (!encryptOptions.envFile) {
fprintf(stderr, "%s: failed to create file %s.\n", progName,
envFileName);
exit(1);
}
} else {
SECU_FileToItem(&envmsg, encryptOptions.envFile);
decodeOptions.options = &options;
encryptOptions.envmsg = decode(NULL, &dummy, &envmsg,
decodeOptions);
}
/* decode an enveloped-data message to get the bulkkey (create
* a new one if neccessary)
*/
rv = get_enc_params(&encryptOptions);
/* create the encrypted-data message */
cmsg = encrypted_data(encryptOptions);
if (!cmsg) {
2000-06-13 21:56:37 +00:00
SECU_PrintError(progName, "problem encrypting");
exitstatus = 1;
}
break;
case ENVELOPE:
envelopeOptions.options = &options;
#if 0
if (!envelopeOptions.recipients)
parse_message_for_recipients(myIn, &envelopeOptions);
#endif
cmsg = enveloped_data(envelopeOptions);
if (!cmsg) {
SECU_PrintError(progName, "problem enveloping");
exitstatus = 1;
}
break;
case CERTSONLY:
certsonlyOptions.options = &options;
cmsg = signed_data_certsonly(certsonlyOptions);
if (!cmsg) {
SECU_PrintError(progName, "problem with certs-only");
exitstatus = 1;
}
break;
2000-06-13 21:56:37 +00:00
default:
fprintf(stderr, "One of options -D, -S or -E must be set.\n");
Usage(progName);
exitstatus = 1;
}
if (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY) {
PLArenaPool *arena = PORT_NewArena(1024);
NSSCMSEncoderContext *ecx;
SECItem output = { 0, 0, 0 };
if (!arena) {
fprintf(stderr, "%s: out of memory.\n", progName);
exit(1);
}
pwcb = (options.password != NULL) ? ownpw : NULL;
pwcb_arg = (options.password != NULL) ? (void *)options.password : NULL;
#ifdef DEBUG
fprintf(stderr, "cmsg [%x]\n", cmsg);
fprintf(stderr, "arena [%x]\n", arena);
2000-12-07 18:38:27 +00:00
if (pwcb_arg)
fprintf(stderr, "password [%s]\n", (char *)pwcb_arg);
else
fprintf(stderr, "password [NULL]\n");
#endif
ecx = NSS_CMSEncoder_Start(cmsg,
NULL, NULL, /* DER output callback */
&output, arena, /* destination storage */
pwcb, pwcb_arg, /* password callback */
NULL, NULL, /* decrypt key callback */
NULL, NULL ); /* detached digests */
if (!ecx) {
fprintf(stderr, "%s: cannot create encoder context.\n", progName);
exit(1);
}
#ifdef DEBUG
fprintf(stderr, "input len [%d]\n", input.len);
{ int j;
for(j=0;j<input.len;j++)
fprintf(stderr, "%2x%c", input.data[j], (j>0&&j%35==0)?'\n':' ');
}
#endif
if (input.len > 0) { /* skip if certs-only (or other zero content) */
rv = NSS_CMSEncoder_Update(ecx, input.data, input.len);
if (rv) {
fprintf(stderr,
"%s: failed to add data to encoder.\n", progName);
exit(1);
}
}
rv = NSS_CMSEncoder_Finish(ecx);
if (rv) {
fprintf(stderr, "%s: failed to encode data.\n", progName);
exit(1);
}
#ifdef DEBUG
fprintf(stderr, "encoding passed\n");
#endif
/*PR_Write(output.data, output.len);*/
fwrite(output.data, output.len, 1, outFile);
#ifdef DEBUG
fprintf(stderr, "wrote to file\n");
#endif
PORT_FreeArena(arena, PR_FALSE);
}
if (cmsg)
NSS_CMSMessage_Destroy(cmsg);
2000-06-13 21:56:37 +00:00
if (outFile != stdout)
fclose(outFile);
if (decodeOptions.contentFile)
PR_Close(decodeOptions.contentFile);
2000-06-13 21:56:37 +00:00
exit(exitstatus);
}