security/nss/cmd/smimetools/cmsutil.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/cmd/smimetools/cmsutil.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1617 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * cmsutil -- A command to work with CMS data
    1.10 + */
    1.11 +
    1.12 +#include "nspr.h"
    1.13 +#include "secutil.h"
    1.14 +#include "plgetopt.h"
    1.15 +#include "secpkcs7.h"
    1.16 +#include "cert.h"
    1.17 +#include "certdb.h"
    1.18 +#include "secoid.h"
    1.19 +#include "cms.h"
    1.20 +#include "nss.h"
    1.21 +#include "smime.h"
    1.22 +#include "pk11func.h"
    1.23 +
    1.24 +#if defined(XP_UNIX)
    1.25 +#include <unistd.h>
    1.26 +#endif
    1.27 +
    1.28 +#if defined(_WIN32)
    1.29 +#include "fcntl.h"
    1.30 +#include "io.h"
    1.31 +#endif
    1.32 +
    1.33 +#include <stdio.h>
    1.34 +#include <string.h>
    1.35 +
    1.36 +char *progName = NULL;
    1.37 +static int cms_verbose = 0;
    1.38 +static secuPWData pwdata = { PW_NONE, 0 };
    1.39 +static PK11PasswordFunc pwcb = NULL;
    1.40 +static void *pwcb_arg = NULL;
    1.41 +
    1.42 +
    1.43 +/* XXX stolen from cmsarray.c
    1.44 + * nss_CMSArray_Count - count number of elements in array
    1.45 + */
    1.46 +int
    1.47 +nss_CMSArray_Count(void **array)
    1.48 +{
    1.49 +    int n = 0;
    1.50 +    if (array == NULL)
    1.51 +	return 0;
    1.52 +    while (*array++ != NULL)
    1.53 +	n++;
    1.54 +    return n;
    1.55 +}
    1.56 +
    1.57 +static SECStatus
    1.58 +DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input,
    1.59 +           SECAlgorithmID **algids)
    1.60 +{
    1.61 +    NSSCMSDigestContext *digcx;
    1.62 +    SECStatus rv;
    1.63 +
    1.64 +    digcx = NSS_CMSDigestContext_StartMultiple(algids);
    1.65 +    if (digcx == NULL)
    1.66 +	return SECFailure;
    1.67 +
    1.68 +    NSS_CMSDigestContext_Update(digcx, input->data, input->len);
    1.69 +
    1.70 +    rv = NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests);
    1.71 +    return rv;
    1.72 +}
    1.73 +
    1.74 +
    1.75 +static void
    1.76 +Usage(char *progName)
    1.77 +{
    1.78 +    fprintf(stderr, 
    1.79 +"Usage:  %s [-C|-D|-E|-O|-S] [<options>] [-d dbdir] [-u certusage]\n"
    1.80 +" -C            create a CMS encrypted data message\n"
    1.81 +" -D            decode a CMS message\n"
    1.82 +"  -b           decode a batch of files named in infile\n"
    1.83 +"  -c content   use this detached content\n"
    1.84 +"  -n           suppress output of content\n"
    1.85 +"  -h num       display num levels of CMS message info as email headers\n"
    1.86 +"  -k           keep decoded encryption certs in perm cert db\n"
    1.87 +" -E            create a CMS enveloped data message\n"
    1.88 +"  -r id,...    create envelope for these recipients,\n"
    1.89 +"               where id can be a certificate nickname or email address\n"
    1.90 +" -S            create a CMS signed data message\n"
    1.91 +"  -G           include a signing time attribute\n"
    1.92 +"  -H hash      use hash (default:SHA1)\n"
    1.93 +"  -N nick      use certificate named \"nick\" for signing\n"
    1.94 +"  -P           include a SMIMECapabilities attribute\n"
    1.95 +"  -T           do not include content in CMS message\n"
    1.96 +"  -Y nick      include a EncryptionKeyPreference attribute with cert\n"
    1.97 +"                 (use \"NONE\" to omit)\n"
    1.98 +" -O            create a CMS signed message containing only certificates\n"
    1.99 +" General Options:\n"
   1.100 +" -d dbdir      key/cert database directory (default: ~/.netscape)\n"
   1.101 +" -e envelope   enveloped data message in this file is used for bulk key\n"
   1.102 +" -i infile     use infile as source of data (default: stdin)\n"
   1.103 +" -o outfile    use outfile as destination of data (default: stdout)\n"
   1.104 +" -p password   use password as key db password (default: prompt)\n"
   1.105 +" -f pwfile     use password file to set password on all PKCS#11 tokens)\n"
   1.106 +" -u certusage  set type of certificate usage (default: certUsageEmailSigner)\n"
   1.107 +" -v            print debugging information\n"
   1.108 +"\n"
   1.109 +"Cert usage codes:\n",
   1.110 +	    progName);
   1.111 +    fprintf(stderr, "%-25s  0 - certUsageSSLClient\n", " ");
   1.112 +    fprintf(stderr, "%-25s  1 - certUsageSSLServer\n", " ");
   1.113 +    fprintf(stderr, "%-25s  2 - certUsageSSLServerWithStepUp\n", " ");
   1.114 +    fprintf(stderr, "%-25s  3 - certUsageSSLCA\n", " ");
   1.115 +    fprintf(stderr, "%-25s  4 - certUsageEmailSigner\n", " ");
   1.116 +    fprintf(stderr, "%-25s  5 - certUsageEmailRecipient\n", " ");
   1.117 +    fprintf(stderr, "%-25s  6 - certUsageObjectSigner\n", " ");
   1.118 +    fprintf(stderr, "%-25s  7 - certUsageUserCertImport\n", " ");
   1.119 +    fprintf(stderr, "%-25s  8 - certUsageVerifyCA\n", " ");
   1.120 +    fprintf(stderr, "%-25s  9 - certUsageProtectedObjectSigner\n", " ");
   1.121 +    fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " ");
   1.122 +    fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " ");
   1.123 +
   1.124 +    exit(-1);
   1.125 +}
   1.126 +
   1.127 +struct optionsStr {
   1.128 +    char *pwfile;
   1.129 +    char *password;
   1.130 +    SECCertUsage certUsage;
   1.131 +    CERTCertDBHandle *certHandle;
   1.132 +};
   1.133 +
   1.134 +struct decodeOptionsStr {
   1.135 +    struct optionsStr *options;
   1.136 +    SECItem            content;
   1.137 +    int headerLevel;
   1.138 +    PRBool suppressContent;
   1.139 +    NSSCMSGetDecryptKeyCallback dkcb;
   1.140 +    PK11SymKey *bulkkey;
   1.141 +    PRBool      keepCerts;
   1.142 +};
   1.143 +
   1.144 +struct signOptionsStr {
   1.145 +    struct optionsStr *options;
   1.146 +    char *nickname;
   1.147 +    char *encryptionKeyPreferenceNick;
   1.148 +    PRBool signingTime;
   1.149 +    PRBool smimeProfile;
   1.150 +    PRBool detached;
   1.151 +    SECOidTag hashAlgTag;
   1.152 +};
   1.153 +
   1.154 +struct envelopeOptionsStr {
   1.155 +    struct optionsStr *options;
   1.156 +    char **recipients;
   1.157 +};
   1.158 +
   1.159 +struct certsonlyOptionsStr {
   1.160 +    struct optionsStr *options;
   1.161 +    char **recipients;
   1.162 +};
   1.163 +
   1.164 +struct encryptOptionsStr {
   1.165 +    struct optionsStr *options;
   1.166 +    char **recipients;
   1.167 +    NSSCMSMessage *envmsg;
   1.168 +    SECItem *input;
   1.169 +    FILE *outfile;
   1.170 +    PRFileDesc *envFile;
   1.171 +    PK11SymKey *bulkkey;
   1.172 +    SECOidTag bulkalgtag;
   1.173 +    int keysize;
   1.174 +};
   1.175 +
   1.176 +static NSSCMSMessage *
   1.177 +decode(FILE *out, SECItem *input, const struct decodeOptionsStr *decodeOptions)
   1.178 +{
   1.179 +    NSSCMSDecoderContext *dcx;
   1.180 +    SECStatus rv;
   1.181 +    NSSCMSMessage *cmsg;
   1.182 +    int nlevels, i;
   1.183 +    SECItem sitem = { 0, 0, 0 };
   1.184 +
   1.185 +    PORT_SetError(0);
   1.186 +    dcx = NSS_CMSDecoder_Start(NULL, 
   1.187 +                               NULL, NULL,         /* content callback     */
   1.188 +                               pwcb, pwcb_arg,     /* password callback    */
   1.189 +			       decodeOptions->dkcb, /* decrypt key callback */
   1.190 +                               decodeOptions->bulkkey);
   1.191 +    if (dcx == NULL) {
   1.192 +	fprintf(stderr, "%s: failed to set up message decoder.\n", progName);
   1.193 +	return NULL;
   1.194 +    }
   1.195 +    rv = NSS_CMSDecoder_Update(dcx, (char *)input->data, input->len);
   1.196 +    if (rv != SECSuccess) {
   1.197 +	fprintf(stderr, "%s: failed to decode message.\n", progName);
   1.198 +	NSS_CMSDecoder_Cancel(dcx);
   1.199 +	return NULL;
   1.200 +    }
   1.201 +    cmsg = NSS_CMSDecoder_Finish(dcx);
   1.202 +    if (cmsg == NULL) {
   1.203 +	fprintf(stderr, "%s: failed to decode message.\n", progName);
   1.204 +	return NULL;
   1.205 +    }
   1.206 +
   1.207 +    if (decodeOptions->headerLevel >= 0) {
   1.208 +	/*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/
   1.209 +	fprintf(out, "SMIME: ");
   1.210 +    }
   1.211 +
   1.212 +    nlevels = NSS_CMSMessage_ContentLevelCount(cmsg);
   1.213 +    for (i = 0; i < nlevels; i++) {
   1.214 +	NSSCMSContentInfo *cinfo;
   1.215 +	SECOidTag typetag;
   1.216 +
   1.217 +	cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);
   1.218 +	typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
   1.219 +
   1.220 +	if (decodeOptions->headerLevel >= 0)
   1.221 +	    fprintf(out, "\tlevel=%d.%d; ", decodeOptions->headerLevel, nlevels - i);
   1.222 +
   1.223 +	switch (typetag) {
   1.224 +	case SEC_OID_PKCS7_SIGNED_DATA:
   1.225 +	  {
   1.226 +	    NSSCMSSignedData *sigd = NULL;
   1.227 +	    SECItem **digests;
   1.228 +	    int nsigners;
   1.229 +	    int j;
   1.230 +
   1.231 +	    if (decodeOptions->headerLevel >= 0)
   1.232 +		fprintf(out, "type=signedData; ");
   1.233 +	    sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
   1.234 +	    if (sigd == NULL) {
   1.235 +		SECU_PrintError(progName, "signedData component missing");
   1.236 +		goto loser;
   1.237 +	    }
   1.238 +
   1.239 +	    /* if we have a content file, but no digests for this signedData */
   1.240 +	    if (decodeOptions->content.data != NULL && 
   1.241 +	        !NSS_CMSSignedData_HasDigests(sigd)) {
   1.242 +		PLArenaPool     *poolp;
   1.243 +		SECAlgorithmID **digestalgs;
   1.244 +
   1.245 +		/* detached content: grab content file */
   1.246 +		sitem = decodeOptions->content;
   1.247 +
   1.248 +		if ((poolp = PORT_NewArena(1024)) == NULL) {
   1.249 +		    fprintf(stderr, "cmsutil: Out of memory.\n");
   1.250 +		    goto loser;
   1.251 +		}
   1.252 +		digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
   1.253 +		if (DigestFile (poolp, &digests, &sitem, digestalgs) 
   1.254 +		      != SECSuccess) {
   1.255 +		    SECU_PrintError(progName, 
   1.256 +		                    "problem computing message digest");
   1.257 +		    PORT_FreeArena(poolp, PR_FALSE);
   1.258 +		    goto loser;
   1.259 +		}
   1.260 +		if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) 
   1.261 +		    != SECSuccess) {
   1.262 +		    SECU_PrintError(progName, 
   1.263 +		                    "problem setting message digests");
   1.264 +		    PORT_FreeArena(poolp, PR_FALSE);
   1.265 +		    goto loser;
   1.266 +		}
   1.267 +		PORT_FreeArena(poolp, PR_FALSE);
   1.268 +	    }
   1.269 +
   1.270 +	    /* import the certificates */
   1.271 +	    if (NSS_CMSSignedData_ImportCerts(sigd, 
   1.272 +	                                   decodeOptions->options->certHandle, 
   1.273 +	                                   decodeOptions->options->certUsage, 
   1.274 +	                                   decodeOptions->keepCerts) 
   1.275 +	          != SECSuccess) {
   1.276 +		SECU_PrintError(progName, "cert import failed");
   1.277 +		goto loser;
   1.278 +	    }
   1.279 +
   1.280 +	    /* find out about signers */
   1.281 +	    nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
   1.282 +	    if (decodeOptions->headerLevel >= 0)
   1.283 +		fprintf(out, "nsigners=%d; ", nsigners);
   1.284 +	    if (nsigners == 0) {
   1.285 +		/* Might be a cert transport message
   1.286 +		** or might be an invalid message, such as a QA test message
   1.287 +		** or a message from an attacker.
   1.288 +		*/
   1.289 +		SECStatus rv;
   1.290 +		rv = NSS_CMSSignedData_VerifyCertsOnly(sigd, 
   1.291 +		                            decodeOptions->options->certHandle, 
   1.292 +		                            decodeOptions->options->certUsage);
   1.293 +		if (rv != SECSuccess) {
   1.294 +		    fprintf(stderr, "cmsutil: Verify certs-only failed!\n");
   1.295 +		    goto loser;
   1.296 +		}
   1.297 +		return cmsg;
   1.298 +	    }
   1.299 +
   1.300 +	    /* still no digests? */
   1.301 +	    if (!NSS_CMSSignedData_HasDigests(sigd)) {
   1.302 +		SECU_PrintError(progName, "no message digests");
   1.303 +		goto loser;
   1.304 +	    }
   1.305 +
   1.306 +	    for (j = 0; j < nsigners; j++) {
   1.307 +		const char * svs;
   1.308 +		NSSCMSSignerInfo *si;
   1.309 +		NSSCMSVerificationStatus vs;
   1.310 +		SECStatus bad;
   1.311 +
   1.312 +		si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
   1.313 +		if (decodeOptions->headerLevel >= 0) {
   1.314 +		    char *signercn;
   1.315 +		    static char empty[] = { "" };
   1.316 +
   1.317 +		    signercn = NSS_CMSSignerInfo_GetSignerCommonName(si);
   1.318 +		    if (signercn == NULL)
   1.319 +			signercn = empty;
   1.320 +		    fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j, signercn);
   1.321 +		    if (signercn != empty)
   1.322 +		        PORT_Free(signercn);
   1.323 +		}
   1.324 +		bad = NSS_CMSSignedData_VerifySignerInfo(sigd, j, 
   1.325 +		                           decodeOptions->options->certHandle, 
   1.326 +		                           decodeOptions->options->certUsage);
   1.327 +		vs  = NSS_CMSSignerInfo_GetVerificationStatus(si);
   1.328 +		svs = NSS_CMSUtil_VerificationStatusToString(vs);
   1.329 +		if (decodeOptions->headerLevel >= 0) {
   1.330 +		    fprintf(out, "signer%d.status=%s; ", j, svs);
   1.331 +		    /* goto loser ? */
   1.332 +		} else if (bad && out) {
   1.333 +		    fprintf(stderr, "signer %d status = %s\n", j, svs);
   1.334 +		    goto loser;
   1.335 +		}
   1.336 +	    }
   1.337 +	  }
   1.338 +	  break;
   1.339 +	case SEC_OID_PKCS7_ENVELOPED_DATA:
   1.340 +	  {
   1.341 +	    NSSCMSEnvelopedData *envd;
   1.342 +	    if (decodeOptions->headerLevel >= 0)
   1.343 +		fprintf(out, "type=envelopedData; ");
   1.344 +	    envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);
   1.345 +	    if (envd == NULL) {
   1.346 +		SECU_PrintError(progName, "envelopedData component missing");
   1.347 +		goto loser;
   1.348 +	    }
   1.349 +	  }
   1.350 +	  break;
   1.351 +	case SEC_OID_PKCS7_ENCRYPTED_DATA:
   1.352 +	  {
   1.353 +	    NSSCMSEncryptedData *encd;
   1.354 +	    if (decodeOptions->headerLevel >= 0)
   1.355 +		fprintf(out, "type=encryptedData; ");
   1.356 +	    encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
   1.357 +	    if (encd == NULL) {
   1.358 +		SECU_PrintError(progName, "encryptedData component missing");
   1.359 +		goto loser;
   1.360 +	    }
   1.361 +	  }
   1.362 +	  break;
   1.363 +	case SEC_OID_PKCS7_DATA:
   1.364 +	    if (decodeOptions->headerLevel >= 0)
   1.365 +		fprintf(out, "type=data; ");
   1.366 +	    break;
   1.367 +	default:
   1.368 +	    break;
   1.369 +	}
   1.370 +	if (decodeOptions->headerLevel >= 0)
   1.371 +	    fprintf(out, "\n");
   1.372 +    }
   1.373 +
   1.374 +    if (!decodeOptions->suppressContent && out) {
   1.375 +	SECItem *item = (sitem.data ? &sitem 
   1.376 +	                            : NSS_CMSMessage_GetContent(cmsg));
   1.377 +	if (item && item->data && item->len) {
   1.378 +	    fwrite(item->data, item->len, 1, out);
   1.379 +    	}
   1.380 +    }
   1.381 +    return cmsg;
   1.382 +
   1.383 +loser:
   1.384 +    if (cmsg)
   1.385 +	NSS_CMSMessage_Destroy(cmsg);
   1.386 +    return NULL;
   1.387 +}
   1.388 +
   1.389 +/* example of a callback function to use with encoder */
   1.390 +/*
   1.391 +static void
   1.392 +writeout(void *arg, const char *buf, unsigned long len)
   1.393 +{
   1.394 +    FILE *f = (FILE *)arg;
   1.395 +
   1.396 +    if (f != NULL && buf != NULL)
   1.397 +	(void)fwrite(buf, len, 1, f);
   1.398 +}
   1.399 +*/
   1.400 +
   1.401 +static NSSCMSMessage *
   1.402 +signed_data(struct signOptionsStr *signOptions)
   1.403 +{
   1.404 +    NSSCMSMessage *cmsg = NULL;
   1.405 +    NSSCMSContentInfo *cinfo;
   1.406 +    NSSCMSSignedData *sigd;
   1.407 +    NSSCMSSignerInfo *signerinfo;
   1.408 +    CERTCertificate *cert= NULL, *ekpcert = NULL;
   1.409 +
   1.410 +    if (cms_verbose) {
   1.411 +	fprintf(stderr, "Input to signed_data:\n");
   1.412 +	if (signOptions->options->password)
   1.413 +	    fprintf(stderr, "password [%s]\n", signOptions->options->password);
   1.414 +        else if (signOptions->options->pwfile)
   1.415 +	    fprintf(stderr, "password file [%s]\n", signOptions->options->pwfile);
   1.416 +	else
   1.417 +	    fprintf(stderr, "password [NULL]\n");
   1.418 +	fprintf(stderr, "certUsage [%d]\n", signOptions->options->certUsage);
   1.419 +	if (signOptions->options->certHandle)
   1.420 +	    fprintf(stderr, "certdb [%p]\n", signOptions->options->certHandle);
   1.421 +	else
   1.422 +	    fprintf(stderr, "certdb [NULL]\n");
   1.423 +	if (signOptions->nickname)
   1.424 +	    fprintf(stderr, "nickname [%s]\n", signOptions->nickname);
   1.425 +	else
   1.426 +	    fprintf(stderr, "nickname [NULL]\n");
   1.427 +    }
   1.428 +    if (signOptions->nickname == NULL) {
   1.429 +	fprintf(stderr, 
   1.430 +        "ERROR: please indicate the nickname of a certificate to sign with.\n");
   1.431 +	return NULL;
   1.432 +    }
   1.433 +    if ((cert = CERT_FindUserCertByUsage(signOptions->options->certHandle, 
   1.434 +                                         signOptions->nickname,
   1.435 +                                         signOptions->options->certUsage,
   1.436 +                                         PR_FALSE,
   1.437 +                                         &pwdata)) == NULL) {
   1.438 +	SECU_PrintError(progName, 
   1.439 +	                "the corresponding cert for key \"%s\" does not exist",
   1.440 +	                signOptions->nickname);
   1.441 +	return NULL;
   1.442 +    }
   1.443 +    if (cms_verbose) {
   1.444 +	fprintf(stderr, "Found certificate for %s\n", signOptions->nickname);
   1.445 +    }
   1.446 +    /*
   1.447 +     * create the message object
   1.448 +     */
   1.449 +    cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
   1.450 +    if (cmsg == NULL) {
   1.451 +	fprintf(stderr, "ERROR: cannot create CMS message.\n");
   1.452 +	return NULL;
   1.453 +    }
   1.454 +    /*
   1.455 +     * build chain of objects: message->signedData->data
   1.456 +     */
   1.457 +    if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
   1.458 +	fprintf(stderr, "ERROR: cannot create CMS signedData object.\n");
   1.459 +	goto loser;
   1.460 +    }
   1.461 +    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
   1.462 +    if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) 
   1.463 +          != SECSuccess) {
   1.464 +	fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n");
   1.465 +	goto loser;
   1.466 +    }
   1.467 +    cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
   1.468 +    /* we're always passing data in and detaching optionally */
   1.469 +    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, 
   1.470 +                                           signOptions->detached) 
   1.471 +          != SECSuccess) {
   1.472 +	fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
   1.473 +	goto loser;
   1.474 +    }
   1.475 +    /* 
   1.476 +     * create & attach signer information
   1.477 +     */
   1.478 +    signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, signOptions->hashAlgTag);
   1.479 +    if (signerinfo == NULL) {
   1.480 +	fprintf(stderr, "ERROR: cannot create CMS signerInfo object.\n");
   1.481 +	goto loser;
   1.482 +    }
   1.483 +    if (cms_verbose) {
   1.484 +	fprintf(stderr,
   1.485 +		 "Created CMS message, added signed data w/ signerinfo\n");
   1.486 +    }
   1.487 +    /* we want the cert chain included for this one */
   1.488 +    if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, 
   1.489 +                                       signOptions->options->certUsage) 
   1.490 +          != SECSuccess) {
   1.491 +	fprintf(stderr, "ERROR: cannot find cert chain.\n");
   1.492 +	goto loser;
   1.493 +    }
   1.494 +    if (cms_verbose) {
   1.495 +	fprintf(stderr, "imported certificate\n");
   1.496 +    }
   1.497 +    if (signOptions->signingTime) {
   1.498 +	if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) 
   1.499 +	      != SECSuccess) {
   1.500 +	    fprintf(stderr, "ERROR: cannot add signingTime attribute.\n");
   1.501 +	    goto loser;
   1.502 +	}
   1.503 +    }
   1.504 +    if (signOptions->smimeProfile) {
   1.505 +	if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
   1.506 +	    fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n");
   1.507 +	    goto loser;
   1.508 +	}
   1.509 +    }
   1.510 +
   1.511 +    if (!signOptions->encryptionKeyPreferenceNick) {
   1.512 +	/* check signing cert for fitness as encryption cert */
   1.513 +        SECStatus FitForEncrypt = CERT_CheckCertUsage(cert,
   1.514 +                                                      certUsageEmailRecipient);
   1.515 +
   1.516 +        if (SECSuccess == FitForEncrypt) {
   1.517 +            /* if yes, add signing cert as EncryptionKeyPreference */
   1.518 +            if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, cert, 
   1.519 +                                              signOptions->options->certHandle)
   1.520 +                  != SECSuccess) {
   1.521 +                fprintf(stderr, 
   1.522 +                    "ERROR: cannot add default SMIMEEncKeyPrefs attribute.\n");
   1.523 +                goto loser;
   1.524 +            }
   1.525 +            if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, cert, 
   1.526 +                                              signOptions->options->certHandle)
   1.527 +                  != SECSuccess) {
   1.528 +                fprintf(stderr, 
   1.529 +                    "ERROR: cannot add default MS SMIMEEncKeyPrefs attribute.\n");
   1.530 +                goto loser;
   1.531 +            }
   1.532 +        } else {
   1.533 +            /* this is a dual-key cert case, we need to look for the encryption
   1.534 +               certificate under the same nickname as the signing cert */
   1.535 +            /* get the cert, add it to the message */
   1.536 +            if ((ekpcert = CERT_FindUserCertByUsage(
   1.537 +                                              signOptions->options->certHandle,
   1.538 +                                              signOptions->nickname,
   1.539 +                                              certUsageEmailRecipient,
   1.540 +                                              PR_FALSE,
   1.541 +                                              &pwdata)) == NULL) {
   1.542 +                SECU_PrintError(progName, 
   1.543 +                         "the corresponding cert for key \"%s\" does not exist",
   1.544 +                         signOptions->encryptionKeyPreferenceNick);
   1.545 +                goto loser;
   1.546 +            }
   1.547 +            if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert, 
   1.548 +                                              signOptions->options->certHandle)
   1.549 +                  != SECSuccess) {
   1.550 +                fprintf(stderr, 
   1.551 +                        "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n");
   1.552 +                goto loser;
   1.553 +            }
   1.554 +            if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, 
   1.555 +                                              signOptions->options->certHandle)
   1.556 +                  != SECSuccess) {
   1.557 +                fprintf(stderr, 
   1.558 +                        "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n");
   1.559 +                goto loser;
   1.560 +            }
   1.561 +            if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
   1.562 +                fprintf(stderr, "ERROR: cannot add encryption certificate.\n");
   1.563 +                goto loser;
   1.564 +            }
   1.565 +        }
   1.566 +    } else if (PL_strcmp(signOptions->encryptionKeyPreferenceNick, "NONE") == 0) {
   1.567 +        /* No action */
   1.568 +    } else {
   1.569 +	/* get the cert, add it to the message */
   1.570 +	if ((ekpcert = CERT_FindUserCertByUsage(
   1.571 +                                     signOptions->options->certHandle, 
   1.572 +	                             signOptions->encryptionKeyPreferenceNick,
   1.573 +                                     certUsageEmailRecipient, PR_FALSE, &pwdata))
   1.574 +	      == NULL) {
   1.575 +	    SECU_PrintError(progName, 
   1.576 +	               "the corresponding cert for key \"%s\" does not exist",
   1.577 +	                signOptions->encryptionKeyPreferenceNick);
   1.578 +	    goto loser;
   1.579 +	}
   1.580 +	if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert, 
   1.581 +	                                     signOptions->options->certHandle)
   1.582 +	      != SECSuccess) {
   1.583 +	    fprintf(stderr, "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n");
   1.584 +	    goto loser;
   1.585 +	}
   1.586 +	if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, 
   1.587 +	                                     signOptions->options->certHandle)
   1.588 +	      != SECSuccess) {
   1.589 +	    fprintf(stderr, "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n");
   1.590 +	    goto loser;
   1.591 +	}
   1.592 +	if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
   1.593 +	    fprintf(stderr, "ERROR: cannot add encryption certificate.\n");
   1.594 +	    goto loser;
   1.595 +	}
   1.596 +    }
   1.597 +
   1.598 +    if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
   1.599 +	fprintf(stderr, "ERROR: cannot add CMS signerInfo object.\n");
   1.600 +	goto loser;
   1.601 +    }
   1.602 +    if (cms_verbose) {
   1.603 +	fprintf(stderr, "created signed-data message\n");
   1.604 +    }
   1.605 +    if (ekpcert) {
   1.606 +	CERT_DestroyCertificate(ekpcert);
   1.607 +    }
   1.608 +    if (cert) {
   1.609 +	CERT_DestroyCertificate(cert);
   1.610 +    }
   1.611 +    return cmsg;
   1.612 +loser:
   1.613 +    if (ekpcert) {
   1.614 +	CERT_DestroyCertificate(ekpcert);
   1.615 +    }
   1.616 +    if (cert) {
   1.617 +	CERT_DestroyCertificate(cert);
   1.618 +    }
   1.619 +    NSS_CMSMessage_Destroy(cmsg);
   1.620 +    return NULL;
   1.621 +}
   1.622 +
   1.623 +static NSSCMSMessage *
   1.624 +enveloped_data(struct envelopeOptionsStr *envelopeOptions)
   1.625 +{
   1.626 +    NSSCMSMessage *cmsg = NULL;
   1.627 +    NSSCMSContentInfo *cinfo;
   1.628 +    NSSCMSEnvelopedData *envd;
   1.629 +    NSSCMSRecipientInfo *recipientinfo;
   1.630 +    CERTCertificate **recipientcerts = NULL;
   1.631 +    CERTCertDBHandle *dbhandle;
   1.632 +    PLArenaPool *tmppoolp = NULL;
   1.633 +    SECOidTag bulkalgtag;
   1.634 +    int keysize, i = 0;
   1.635 +    int cnt;
   1.636 +    dbhandle = envelopeOptions->options->certHandle;
   1.637 +    /* count the recipients */
   1.638 +    if ((cnt = nss_CMSArray_Count((void **)envelopeOptions->recipients)) == 0) {
   1.639 +	fprintf(stderr, "ERROR: please name at least one recipient.\n");
   1.640 +	goto loser;
   1.641 +    }
   1.642 +    if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
   1.643 +	fprintf(stderr, "ERROR: out of memory.\n");
   1.644 +	goto loser;
   1.645 +    }
   1.646 +    /* XXX find the recipient's certs by email address or nickname */
   1.647 +    if ((recipientcerts = 
   1.648 +         (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp, 
   1.649 +					     (cnt+1)*sizeof(CERTCertificate*)))
   1.650 +            == NULL) {
   1.651 +	fprintf(stderr, "ERROR: out of memory.\n");
   1.652 +	goto loser;
   1.653 +    }
   1.654 +    for (i=0; envelopeOptions->recipients[i] != NULL; i++) {
   1.655 +	if ((recipientcerts[i] = 
   1.656 +	      CERT_FindCertByNicknameOrEmailAddr(dbhandle,  
   1.657 +	                                        envelopeOptions->recipients[i]))
   1.658 +	        == NULL) {
   1.659 +	    SECU_PrintError(progName, "cannot find certificate for \"%s\"", 
   1.660 +	                    envelopeOptions->recipients[i]);
   1.661 +	    i=0;
   1.662 +	    goto loser;
   1.663 +	}
   1.664 +    }
   1.665 +    recipientcerts[i] = NULL;
   1.666 +    i=0;
   1.667 +    /* find a nice bulk algorithm */
   1.668 +    if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientcerts, &bulkalgtag, 
   1.669 +                                               &keysize) != SECSuccess) {
   1.670 +	fprintf(stderr, "ERROR: cannot find common bulk algorithm.\n");
   1.671 +	goto loser;
   1.672 +    }
   1.673 +    /*
   1.674 +     * create the message object
   1.675 +     */
   1.676 +    cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
   1.677 +    if (cmsg == NULL) {
   1.678 +	fprintf(stderr, "ERROR: cannot create CMS message.\n");
   1.679 +	goto loser;
   1.680 +    }
   1.681 +    /*
   1.682 +     * build chain of objects: message->envelopedData->data
   1.683 +     */
   1.684 +    if ((envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, keysize)) 
   1.685 +          == NULL) {
   1.686 +	fprintf(stderr, "ERROR: cannot create CMS envelopedData object.\n");
   1.687 +	goto loser;
   1.688 +    }
   1.689 +    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
   1.690 +    if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) 
   1.691 +          != SECSuccess) {
   1.692 +	fprintf(stderr, "ERROR: cannot attach CMS envelopedData object.\n");
   1.693 +	goto loser;
   1.694 +    }
   1.695 +    cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
   1.696 +    /* we're always passing data in, so the content is NULL */
   1.697 +    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
   1.698 +          != SECSuccess) {
   1.699 +	fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
   1.700 +	goto loser;
   1.701 +    }
   1.702 +    /* 
   1.703 +     * create & attach recipient information
   1.704 +     */
   1.705 +    for (i = 0; recipientcerts[i] != NULL; i++) {
   1.706 +	if ((recipientinfo = NSS_CMSRecipientInfo_Create(cmsg, 
   1.707 +	                                                 recipientcerts[i])) 
   1.708 +	      == NULL) {
   1.709 +	    fprintf(stderr, "ERROR: cannot create CMS recipientInfo object.\n");
   1.710 +	    goto loser;
   1.711 +	}
   1.712 +	if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientinfo) 
   1.713 +	      != SECSuccess) {
   1.714 +	    fprintf(stderr, "ERROR: cannot add CMS recipientInfo object.\n");
   1.715 +	    goto loser;
   1.716 +	}
   1.717 +	CERT_DestroyCertificate(recipientcerts[i]);
   1.718 +    }
   1.719 +    if (tmppoolp)
   1.720 +	PORT_FreeArena(tmppoolp, PR_FALSE);
   1.721 +    return cmsg;
   1.722 +loser:
   1.723 +    if (recipientcerts) {
   1.724 +	for (; recipientcerts[i] != NULL; i++) {
   1.725 +	    CERT_DestroyCertificate(recipientcerts[i]);
   1.726 +	}
   1.727 +    }
   1.728 +    if (cmsg)
   1.729 +	NSS_CMSMessage_Destroy(cmsg);
   1.730 +    if (tmppoolp)
   1.731 +	PORT_FreeArena(tmppoolp, PR_FALSE);
   1.732 +    return NULL;
   1.733 +}
   1.734 +
   1.735 +PK11SymKey *dkcb(void *arg, SECAlgorithmID *algid)
   1.736 +{
   1.737 +    return (PK11SymKey*)arg;
   1.738 +}
   1.739 +
   1.740 +static SECStatus
   1.741 +get_enc_params(struct encryptOptionsStr *encryptOptions)
   1.742 +{
   1.743 +    struct envelopeOptionsStr envelopeOptions;
   1.744 +    SECStatus rv = SECFailure;
   1.745 +    NSSCMSMessage *env_cmsg;
   1.746 +    NSSCMSContentInfo *cinfo;
   1.747 +    int i, nlevels;
   1.748 +    /*
   1.749 +     * construct an enveloped data message to obtain bulk keys
   1.750 +     */
   1.751 +    if (encryptOptions->envmsg) {
   1.752 +	env_cmsg = encryptOptions->envmsg; /* get it from an old message */
   1.753 +    } else {
   1.754 +	SECItem dummyOut = { 0, 0, 0 };
   1.755 +	SECItem dummyIn  = { 0, 0, 0 };
   1.756 +	char str[] = "Hello!";
   1.757 +	PLArenaPool *tmparena = PORT_NewArena(1024);
   1.758 +	dummyIn.data = (unsigned char *)str;
   1.759 +	dummyIn.len = strlen(str);
   1.760 +	envelopeOptions.options = encryptOptions->options;
   1.761 +	envelopeOptions.recipients = encryptOptions->recipients;
   1.762 +	env_cmsg = enveloped_data(&envelopeOptions);
   1.763 +	NSS_CMSDEREncode(env_cmsg, &dummyIn, &dummyOut, tmparena);
   1.764 +	PR_Write(encryptOptions->envFile, dummyOut.data, dummyOut.len);
   1.765 +	PORT_FreeArena(tmparena, PR_FALSE);
   1.766 +    }
   1.767 +    /*
   1.768 +     * get the content info for the enveloped data 
   1.769 +     */
   1.770 +    nlevels = NSS_CMSMessage_ContentLevelCount(env_cmsg);
   1.771 +    for (i = 0; i < nlevels; i++) {
   1.772 +    	SECOidTag typetag;
   1.773 +	cinfo = NSS_CMSMessage_ContentLevel(env_cmsg, i);
   1.774 +	typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
   1.775 +	if (typetag == SEC_OID_PKCS7_DATA) {
   1.776 +	    /*
   1.777 +	     * get the symmetric key
   1.778 +	     */
   1.779 +	    encryptOptions->bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo);
   1.780 +	    encryptOptions->keysize = NSS_CMSContentInfo_GetBulkKeySize(cinfo);
   1.781 +	    encryptOptions->bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
   1.782 +	    rv = SECSuccess;
   1.783 +	    break;
   1.784 +	}
   1.785 +    }
   1.786 +    if (i == nlevels) {
   1.787 +	fprintf(stderr, "%s: could not retrieve enveloped data.", progName);
   1.788 +    }
   1.789 +    if (env_cmsg)
   1.790 +	NSS_CMSMessage_Destroy(env_cmsg);
   1.791 +    return rv;
   1.792 +}
   1.793 +
   1.794 +static NSSCMSMessage *
   1.795 +encrypted_data(struct encryptOptionsStr *encryptOptions)
   1.796 +{
   1.797 +    SECStatus rv = SECFailure;
   1.798 +    NSSCMSMessage *cmsg = NULL;
   1.799 +    NSSCMSContentInfo *cinfo;
   1.800 +    NSSCMSEncryptedData *encd;
   1.801 +    NSSCMSEncoderContext *ecx = NULL;
   1.802 +    PLArenaPool *tmppoolp = NULL;
   1.803 +    SECItem derOut = { 0, 0, 0 };
   1.804 +    /* arena for output */
   1.805 +    tmppoolp = PORT_NewArena(1024);
   1.806 +    if (!tmppoolp) {
   1.807 +	fprintf(stderr, "%s: out of memory.\n", progName);
   1.808 +	return NULL;
   1.809 +    }
   1.810 +    /*
   1.811 +     * create the message object
   1.812 +     */
   1.813 +    cmsg = NSS_CMSMessage_Create(NULL);
   1.814 +    if (cmsg == NULL) {
   1.815 +	fprintf(stderr, "ERROR: cannot create CMS message.\n");
   1.816 +	goto loser;
   1.817 +    }
   1.818 +    /*
   1.819 +     * build chain of objects: message->encryptedData->data
   1.820 +     */
   1.821 +    if ((encd = NSS_CMSEncryptedData_Create(cmsg, encryptOptions->bulkalgtag, 
   1.822 +                                                  encryptOptions->keysize)) 
   1.823 +           == NULL) {
   1.824 +	fprintf(stderr, "ERROR: cannot create CMS encryptedData object.\n");
   1.825 +	goto loser;
   1.826 +    }
   1.827 +    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
   1.828 +    if (NSS_CMSContentInfo_SetContent_EncryptedData(cmsg, cinfo, encd)
   1.829 +          != SECSuccess) {
   1.830 +	fprintf(stderr, "ERROR: cannot attach CMS encryptedData object.\n");
   1.831 +	goto loser;
   1.832 +    }
   1.833 +    cinfo = NSS_CMSEncryptedData_GetContentInfo(encd);
   1.834 +    /* we're always passing data in, so the content is NULL */
   1.835 +    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
   1.836 +          != SECSuccess) {
   1.837 +	fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
   1.838 +	goto loser;
   1.839 +    }
   1.840 +    ecx = NSS_CMSEncoder_Start(cmsg, NULL, NULL, &derOut, tmppoolp, NULL, NULL,
   1.841 +                               dkcb, encryptOptions->bulkkey, NULL, NULL);
   1.842 +    if (!ecx) {
   1.843 +	fprintf(stderr, "%s: cannot create encoder context.\n", progName);
   1.844 +	goto loser;
   1.845 +    }
   1.846 +    rv = NSS_CMSEncoder_Update(ecx, (char *)encryptOptions->input->data, 
   1.847 +                                    encryptOptions->input->len);
   1.848 +    if (rv) {
   1.849 +	fprintf(stderr, "%s: failed to add data to encoder.\n", progName);
   1.850 +	goto loser;
   1.851 +    }
   1.852 +    rv = NSS_CMSEncoder_Finish(ecx);
   1.853 +    if (rv) {
   1.854 +	fprintf(stderr, "%s: failed to encrypt data.\n", progName);
   1.855 +	goto loser;
   1.856 +    }
   1.857 +    fwrite(derOut.data, derOut.len, 1, encryptOptions->outfile);
   1.858 +    /*
   1.859 +    if (bulkkey)
   1.860 +	PK11_FreeSymKey(bulkkey);
   1.861 +	*/
   1.862 +    if (tmppoolp)
   1.863 +	PORT_FreeArena(tmppoolp, PR_FALSE);
   1.864 +    return cmsg;
   1.865 +loser:
   1.866 +    /*
   1.867 +    if (bulkkey)
   1.868 +	PK11_FreeSymKey(bulkkey);
   1.869 +	*/
   1.870 +    if (tmppoolp)
   1.871 +	PORT_FreeArena(tmppoolp, PR_FALSE);
   1.872 +    if (cmsg)
   1.873 +	NSS_CMSMessage_Destroy(cmsg);
   1.874 +    return NULL;
   1.875 +}
   1.876 +
   1.877 +static NSSCMSMessage *
   1.878 +signed_data_certsonly(struct certsonlyOptionsStr *certsonlyOptions)
   1.879 +{
   1.880 +    NSSCMSMessage *cmsg = NULL;
   1.881 +    NSSCMSContentInfo *cinfo;
   1.882 +    NSSCMSSignedData *sigd;
   1.883 +    CERTCertificate **certs = NULL;
   1.884 +    CERTCertDBHandle *dbhandle;
   1.885 +    PLArenaPool *tmppoolp = NULL;
   1.886 +    int i = 0, cnt;
   1.887 +    dbhandle = certsonlyOptions->options->certHandle;
   1.888 +    if ((cnt = nss_CMSArray_Count((void**)certsonlyOptions->recipients)) == 0) {
   1.889 +	fprintf(stderr, 
   1.890 +        "ERROR: please indicate the nickname of a certificate to sign with.\n");
   1.891 +	goto loser;
   1.892 +    }
   1.893 +    if (!(tmppoolp = PORT_NewArena(1024))) {
   1.894 +	fprintf(stderr, "ERROR: out of memory.\n");
   1.895 +	goto loser;
   1.896 +    }
   1.897 +    if (!(certs = PORT_ArenaZNewArray(tmppoolp, CERTCertificate *, cnt + 1))) {
   1.898 +	fprintf(stderr, "ERROR: out of memory.\n");
   1.899 +	goto loser;
   1.900 +    }
   1.901 +    for (i=0; certsonlyOptions->recipients[i] != NULL; i++) {
   1.902 +	if ((certs[i] = 
   1.903 +	      CERT_FindCertByNicknameOrEmailAddr(dbhandle,
   1.904 +	                                      certsonlyOptions->recipients[i]))
   1.905 +	        == NULL) {
   1.906 +	    SECU_PrintError(progName, "cannot find certificate for \"%s\"", 
   1.907 +	                    certsonlyOptions->recipients[i]);
   1.908 +	    i=0;
   1.909 +	    goto loser;
   1.910 +	}
   1.911 +    }
   1.912 +    certs[i] = NULL;
   1.913 +    i=0;
   1.914 +    /*
   1.915 +     * create the message object
   1.916 +     */
   1.917 +    cmsg = NSS_CMSMessage_Create(NULL);
   1.918 +    if (cmsg == NULL) {
   1.919 +	fprintf(stderr, "ERROR: cannot create CMS message.\n");
   1.920 +	goto loser;
   1.921 +    }
   1.922 +    /*
   1.923 +     * build chain of objects: message->signedData->data
   1.924 +     */
   1.925 +    if ((sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, certs[0], PR_TRUE))
   1.926 +          == NULL) {
   1.927 +	fprintf(stderr, "ERROR: cannot create CMS signedData object.\n");
   1.928 +	goto loser;
   1.929 +    }
   1.930 +    CERT_DestroyCertificate(certs[0]);
   1.931 +    for (i=1; i<cnt; i++) {
   1.932 +	if (NSS_CMSSignedData_AddCertChain(sigd, certs[i])) {
   1.933 +	    fprintf(stderr, "ERROR: cannot add cert chain for \"%s\".\n",
   1.934 +	            certsonlyOptions->recipients[i]);
   1.935 +	    goto loser;
   1.936 +	}
   1.937 +	CERT_DestroyCertificate(certs[i]);
   1.938 +    }
   1.939 +    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
   1.940 +    if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) 
   1.941 +          != SECSuccess) {
   1.942 +	fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n");
   1.943 +	goto loser;
   1.944 +    }
   1.945 +    cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
   1.946 +    if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
   1.947 +	   != SECSuccess) {
   1.948 +	fprintf(stderr, "ERROR: cannot attach CMS data object.\n");
   1.949 +	goto loser;
   1.950 +    }
   1.951 +    if (tmppoolp)
   1.952 +	PORT_FreeArena(tmppoolp, PR_FALSE);
   1.953 +    return cmsg;
   1.954 +loser:
   1.955 +    if (certs) {
   1.956 +	for (; i<cnt; i++) {
   1.957 +	    CERT_DestroyCertificate(certs[i]);
   1.958 +	}
   1.959 +    }
   1.960 +    if (cmsg)
   1.961 +	NSS_CMSMessage_Destroy(cmsg);
   1.962 +    if (tmppoolp)
   1.963 +	PORT_FreeArena(tmppoolp, PR_FALSE);
   1.964 +    return NULL;
   1.965 +}
   1.966 +
   1.967 +static char *
   1.968 +pl_fgets(char * buf, int size, PRFileDesc * fd)
   1.969 +{
   1.970 +    char * bp = buf;
   1.971 +    int    nb = 0;;
   1.972 +
   1.973 +    while (size > 1) {
   1.974 +    	nb = PR_Read(fd, bp, 1);
   1.975 +	if (nb < 0) {
   1.976 +	    /* deal with error */
   1.977 +	    return NULL;
   1.978 +	} else if (nb == 0) {
   1.979 +	    /* deal with EOF */
   1.980 +	    return NULL;
   1.981 +	} else if (*bp == '\n') {
   1.982 +	    /* deal with EOL */
   1.983 +	    ++bp;  /* keep EOL character */
   1.984 +	    break;
   1.985 +	} else {
   1.986 +	    /* ordinary character */
   1.987 +	    ++bp;
   1.988 +	    --size;
   1.989 +	}
   1.990 +    }
   1.991 +    *bp = '\0';
   1.992 +    return buf;
   1.993 +}
   1.994 +
   1.995 +typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode;
   1.996 +
   1.997 +static int 
   1.998 +doBatchDecode(FILE *outFile, PRFileDesc *batchFile, 
   1.999 +              const struct decodeOptionsStr *decodeOptions)
  1.1000 +{
  1.1001 +    char * str;
  1.1002 +    int    exitStatus = 0;
  1.1003 +    char   batchLine[512];
  1.1004 +
  1.1005 +    while (NULL != (str = pl_fgets(batchLine, sizeof batchLine, batchFile))) {
  1.1006 +	NSSCMSMessage *cmsg = NULL;
  1.1007 +	PRFileDesc *   inFile;
  1.1008 +    	int            len = strlen(str);
  1.1009 +	SECStatus      rv;
  1.1010 +	SECItem        input = {0, 0, 0};
  1.1011 +	char           cc;
  1.1012 +
  1.1013 +	while (len > 0 && 
  1.1014 +	       ((cc = str[len - 1]) == '\n' || cc == '\r')) {
  1.1015 +	    str[--len] = '\0';
  1.1016 +	}
  1.1017 +	if (!len) /* skip empty line */
  1.1018 +	    continue;
  1.1019 +	if (str[0] == '#')
  1.1020 +	    continue;  /* skip comment line */
  1.1021 +	fprintf(outFile, "========== %s ==========\n", str);
  1.1022 +	inFile = PR_Open(str, PR_RDONLY, 00660);
  1.1023 +	if (inFile == NULL) {
  1.1024 +	    fprintf(outFile, "%s: unable to open \"%s\" for reading\n",
  1.1025 +		    progName, str);
  1.1026 +	    exitStatus = 1;
  1.1027 +	    continue;
  1.1028 +	}
  1.1029 +	rv = SECU_FileToItem(&input, inFile);
  1.1030 +	PR_Close(inFile);
  1.1031 +	if (rv != SECSuccess) {
  1.1032 +	    SECU_PrintError(progName, "unable to read infile");
  1.1033 +	    exitStatus = 1;
  1.1034 +	    continue;
  1.1035 +	}
  1.1036 +	cmsg = decode(outFile, &input, decodeOptions);
  1.1037 +	SECITEM_FreeItem(&input, PR_FALSE);
  1.1038 +	if (cmsg)
  1.1039 +	    NSS_CMSMessage_Destroy(cmsg);
  1.1040 +	else {
  1.1041 +	    SECU_PrintError(progName, "problem decoding");
  1.1042 +	    exitStatus = 1;
  1.1043 +	}
  1.1044 +    }
  1.1045 +    return exitStatus;
  1.1046 +}
  1.1047 +
  1.1048 +int
  1.1049 +main(int argc, char **argv)
  1.1050 +{
  1.1051 +    FILE *outFile;
  1.1052 +    NSSCMSMessage *cmsg = NULL;
  1.1053 +    PRFileDesc *inFile;
  1.1054 +    PLOptState *optstate;
  1.1055 +    PLOptStatus status;
  1.1056 +    Mode mode = UNKNOWN;
  1.1057 +    struct decodeOptionsStr decodeOptions = { 0 };
  1.1058 +    struct signOptionsStr signOptions = { 0 };
  1.1059 +    struct envelopeOptionsStr envelopeOptions = { 0 };
  1.1060 +    struct certsonlyOptionsStr certsonlyOptions = { 0 };
  1.1061 +    struct encryptOptionsStr encryptOptions = { 0 };
  1.1062 +    struct optionsStr options = { 0 };
  1.1063 +    int exitstatus;
  1.1064 +    static char *ptrarray[128] = { 0 };
  1.1065 +    int nrecipients = 0;
  1.1066 +    char *str, *tok;
  1.1067 +    char *envFileName;
  1.1068 +    SECItem input = { 0, 0, 0};
  1.1069 +    SECItem envmsg = { 0, 0, 0 };
  1.1070 +    SECStatus rv;
  1.1071 +    PRFileDesc *contentFile = NULL;
  1.1072 +    PRBool      batch = PR_FALSE;
  1.1073 +
  1.1074 +#ifdef NISCC_TEST
  1.1075 +    const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
  1.1076 +    PORT_Assert(ev); 
  1.1077 +    ev = PR_GetEnv("NSS_STRICT_SHUTDOWN");
  1.1078 +    PORT_Assert(ev); 
  1.1079 +#endif 
  1.1080 +
  1.1081 +    progName = strrchr(argv[0], '/');
  1.1082 +    if (!progName)
  1.1083 +       progName = strrchr(argv[0], '\\');
  1.1084 +    progName = progName ? progName+1 : argv[0];
  1.1085 +
  1.1086 +    inFile = PR_STDIN;
  1.1087 +    outFile = stdout;
  1.1088 +    envFileName = NULL;
  1.1089 +    mode = UNKNOWN;
  1.1090 +    decodeOptions.content.data = NULL;
  1.1091 +    decodeOptions.content.len  = 0;
  1.1092 +    decodeOptions.suppressContent = PR_FALSE;
  1.1093 +    decodeOptions.headerLevel = -1;
  1.1094 +    decodeOptions.keepCerts = PR_FALSE;
  1.1095 +    options.certUsage = certUsageEmailSigner;
  1.1096 +    options.password = NULL;
  1.1097 +    options.pwfile = NULL;
  1.1098 +    signOptions.nickname = NULL;
  1.1099 +    signOptions.detached = PR_FALSE;
  1.1100 +    signOptions.signingTime = PR_FALSE;
  1.1101 +    signOptions.smimeProfile = PR_FALSE;
  1.1102 +    signOptions.encryptionKeyPreferenceNick = NULL;
  1.1103 +    signOptions.hashAlgTag = SEC_OID_SHA1;
  1.1104 +    envelopeOptions.recipients = NULL;
  1.1105 +    encryptOptions.recipients = NULL;
  1.1106 +    encryptOptions.envmsg = NULL;
  1.1107 +    encryptOptions.envFile = NULL;
  1.1108 +    encryptOptions.bulkalgtag = SEC_OID_UNKNOWN;
  1.1109 +    encryptOptions.bulkkey = NULL;
  1.1110 +    encryptOptions.keysize = -1;
  1.1111 +
  1.1112 +    /*
  1.1113 +     * Parse command line arguments
  1.1114 +     */
  1.1115 +    optstate = PL_CreateOptState(argc, argv, 
  1.1116 +				 "CDEGH:N:OPSTY:bc:d:e:f:h:i:kno:p:r:s:u:v");
  1.1117 +    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
  1.1118 +	switch (optstate->option) {
  1.1119 +	case 'C':
  1.1120 +	    mode = ENCRYPT;
  1.1121 +	    break;
  1.1122 +	case 'D':
  1.1123 +	    mode = DECODE;
  1.1124 +	    break;
  1.1125 +	case 'E':
  1.1126 +	    mode = ENVELOPE;
  1.1127 +	    break;
  1.1128 +	case 'G':
  1.1129 +	    if (mode != SIGN) {
  1.1130 +		fprintf(stderr, 
  1.1131 +		        "%s: option -G only supported with option -S.\n", 
  1.1132 +		        progName);
  1.1133 +		Usage(progName);
  1.1134 +		exit(1);
  1.1135 +	    }
  1.1136 +	    signOptions.signingTime = PR_TRUE;
  1.1137 +	    break;
  1.1138 +       case 'H':
  1.1139 +           if (mode != SIGN) {
  1.1140 +               fprintf(stderr,
  1.1141 +                       "%s: option -H only supported with option -S.\n",
  1.1142 +                       progName);
  1.1143 +               Usage(progName);
  1.1144 +               exit(1);
  1.1145 +           }
  1.1146 +           decodeOptions.suppressContent = PR_TRUE;
  1.1147 +           if (!strcmp(optstate->value, "MD2"))
  1.1148 +               signOptions.hashAlgTag = SEC_OID_MD2;
  1.1149 +           else if (!strcmp(optstate->value, "MD4"))
  1.1150 +               signOptions.hashAlgTag = SEC_OID_MD4;
  1.1151 +           else if (!strcmp(optstate->value, "MD5"))
  1.1152 +               signOptions.hashAlgTag = SEC_OID_MD5;
  1.1153 +           else if (!strcmp(optstate->value, "SHA1"))
  1.1154 +               signOptions.hashAlgTag = SEC_OID_SHA1;
  1.1155 +           else if (!strcmp(optstate->value, "SHA256"))
  1.1156 +               signOptions.hashAlgTag = SEC_OID_SHA256;
  1.1157 +           else if (!strcmp(optstate->value, "SHA384"))
  1.1158 +               signOptions.hashAlgTag = SEC_OID_SHA384;
  1.1159 +           else if (!strcmp(optstate->value, "SHA512"))
  1.1160 +               signOptions.hashAlgTag = SEC_OID_SHA512;
  1.1161 +           else {
  1.1162 +               fprintf(stderr,
  1.1163 +           "%s: -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512\n",
  1.1164 +                       progName);
  1.1165 +               exit(1);
  1.1166 +           }
  1.1167 +           break;
  1.1168 +	case 'N':
  1.1169 +	    if (mode != SIGN) {
  1.1170 +		fprintf(stderr, 
  1.1171 +		        "%s: option -N only supported with option -S.\n", 
  1.1172 +		        progName);
  1.1173 +		Usage(progName);
  1.1174 +		exit(1);
  1.1175 +	    }
  1.1176 +	    signOptions.nickname = strdup(optstate->value);
  1.1177 +	    break;
  1.1178 +	case 'O':
  1.1179 +	    mode = CERTSONLY;
  1.1180 +	    break;
  1.1181 +	case 'P':
  1.1182 +	    if (mode != SIGN) {
  1.1183 +		fprintf(stderr, 
  1.1184 +		        "%s: option -P only supported with option -S.\n", 
  1.1185 +		        progName);
  1.1186 +		Usage(progName);
  1.1187 +		exit(1);
  1.1188 +	    }
  1.1189 +	    signOptions.smimeProfile = PR_TRUE;
  1.1190 +	    break;
  1.1191 +	case 'S':
  1.1192 +	    mode = SIGN;
  1.1193 +	    break;
  1.1194 +	case 'T':
  1.1195 +	    if (mode != SIGN) {
  1.1196 +		fprintf(stderr, 
  1.1197 +		        "%s: option -T only supported with option -S.\n", 
  1.1198 +		        progName);
  1.1199 +		Usage(progName);
  1.1200 +		exit(1);
  1.1201 +	    }
  1.1202 +	    signOptions.detached = PR_TRUE;
  1.1203 +	    break;
  1.1204 +	case 'Y':
  1.1205 +	    if (mode != SIGN) {
  1.1206 +		fprintf(stderr, 
  1.1207 +		        "%s: option -Y only supported with option -S.\n", 
  1.1208 +		        progName);
  1.1209 +		Usage(progName);
  1.1210 +		exit(1);
  1.1211 +	    }
  1.1212 +	    signOptions.encryptionKeyPreferenceNick = strdup(optstate->value);
  1.1213 +	    break;
  1.1214 +
  1.1215 +	case 'b':
  1.1216 +	    if (mode != DECODE) {
  1.1217 +		fprintf(stderr, 
  1.1218 +		        "%s: option -b only supported with option -D.\n", 
  1.1219 +		        progName);
  1.1220 +		Usage(progName);
  1.1221 +		exit(1);
  1.1222 +	    }
  1.1223 +	    batch = PR_TRUE;
  1.1224 +	    break;
  1.1225 +
  1.1226 +	case 'c':
  1.1227 +	    if (mode != DECODE) {
  1.1228 +		fprintf(stderr, 
  1.1229 +		        "%s: option -c only supported with option -D.\n", 
  1.1230 +		        progName);
  1.1231 +		Usage(progName);
  1.1232 +		exit(1);
  1.1233 +	    }
  1.1234 +	    contentFile = PR_Open(optstate->value, PR_RDONLY, 006600);
  1.1235 +	    if (contentFile == NULL) {
  1.1236 +		fprintf(stderr, "%s: unable to open \"%s\" for reading.\n",
  1.1237 +			progName, optstate->value);
  1.1238 +		exit(1);
  1.1239 +	    }
  1.1240 +
  1.1241 +	    rv = SECU_FileToItem(&decodeOptions.content, contentFile);
  1.1242 +	    PR_Close(contentFile);
  1.1243 +	    if (rv != SECSuccess) {
  1.1244 +		SECU_PrintError(progName, "problem reading content file");
  1.1245 +		exit(1);
  1.1246 +	    }
  1.1247 +	    if (!decodeOptions.content.data) {
  1.1248 +		/* file was zero length */
  1.1249 +		decodeOptions.content.data = (unsigned char *)PORT_Strdup("");
  1.1250 +		decodeOptions.content.len  = 0;
  1.1251 +	    }
  1.1252 +
  1.1253 +	    break;
  1.1254 +	case 'd':
  1.1255 +	    SECU_ConfigDirectory(optstate->value);
  1.1256 +	    break;
  1.1257 +	case 'e':
  1.1258 +	    envFileName = strdup(optstate->value);
  1.1259 +	    encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660);
  1.1260 +	    break;
  1.1261 +
  1.1262 +	case 'h':
  1.1263 +	    if (mode != DECODE) {
  1.1264 +		fprintf(stderr, 
  1.1265 +		        "%s: option -h only supported with option -D.\n", 
  1.1266 +		        progName);
  1.1267 +		Usage(progName);
  1.1268 +		exit(1);
  1.1269 +	    }
  1.1270 +	    decodeOptions.headerLevel = atoi(optstate->value);
  1.1271 +	    if (decodeOptions.headerLevel < 0) {
  1.1272 +		fprintf(stderr, "option -h cannot have a negative value.\n");
  1.1273 +		exit(1);
  1.1274 +	    }
  1.1275 +	    break;
  1.1276 +	case 'i':
  1.1277 +	    if (!optstate->value) {
  1.1278 +	        fprintf(stderr, "-i option requires filename argument\n");
  1.1279 +	        exit(1);
  1.1280 +	    }
  1.1281 +	    inFile = PR_Open(optstate->value, PR_RDONLY, 00660);
  1.1282 +	    if (inFile == NULL) {
  1.1283 +		fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
  1.1284 +			progName, optstate->value);
  1.1285 +		exit(1);
  1.1286 +	    }
  1.1287 +	    break;
  1.1288 +
  1.1289 +	case 'k':
  1.1290 +	    if (mode != DECODE) {
  1.1291 +		fprintf(stderr, 
  1.1292 +		        "%s: option -k only supported with option -D.\n", 
  1.1293 +		        progName);
  1.1294 +		Usage(progName);
  1.1295 +		exit(1);
  1.1296 +	    }
  1.1297 +	    decodeOptions.keepCerts = PR_TRUE;
  1.1298 +	    break;
  1.1299 +
  1.1300 +	case 'n':
  1.1301 +	    if (mode != DECODE) {
  1.1302 +		fprintf(stderr, 
  1.1303 +		        "%s: option -n only supported with option -D.\n", 
  1.1304 +		        progName);
  1.1305 +		Usage(progName);
  1.1306 +		exit(1);
  1.1307 +	    }
  1.1308 +	    decodeOptions.suppressContent = PR_TRUE;
  1.1309 +	    break;
  1.1310 +	case 'o':
  1.1311 +	    outFile = fopen(optstate->value, "wb");
  1.1312 +	    if (outFile == NULL) {
  1.1313 +		fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
  1.1314 +			progName, optstate->value);
  1.1315 +		exit(1);
  1.1316 +	    }
  1.1317 +	    break;
  1.1318 +	case 'p':
  1.1319 +	    if (!optstate->value) {
  1.1320 +		fprintf(stderr, "%s: option -p must have a value.\n", progName);
  1.1321 +		Usage(progName);
  1.1322 +		exit(1);
  1.1323 +	    }
  1.1324 +		
  1.1325 +	    options.password = strdup(optstate->value);
  1.1326 +	    break;
  1.1327 +
  1.1328 +        case 'f':
  1.1329 +            if (!optstate->value) {
  1.1330 +                fprintf(stderr, "%s: option -f must have a value.\n", progName);
  1.1331 +                Usage(progName);
  1.1332 +                exit(1);
  1.1333 +            }
  1.1334 +
  1.1335 +            options.pwfile = strdup(optstate->value);
  1.1336 +            break;
  1.1337 +
  1.1338 +	case 'r':
  1.1339 +	    if (!optstate->value) {
  1.1340 +		fprintf(stderr, "%s: option -r must have a value.\n", progName);
  1.1341 +		Usage(progName);
  1.1342 +		exit(1);
  1.1343 +	    }
  1.1344 +	    envelopeOptions.recipients = ptrarray;
  1.1345 +	    str = (char *)optstate->value;
  1.1346 +	    do {
  1.1347 +		tok = strchr(str, ',');
  1.1348 +		if (tok) *tok = '\0';
  1.1349 +		envelopeOptions.recipients[nrecipients++] = strdup(str);
  1.1350 +		if (tok) str = tok + 1;
  1.1351 +	    } while (tok);
  1.1352 +	    envelopeOptions.recipients[nrecipients] = NULL;
  1.1353 +	    encryptOptions.recipients = envelopeOptions.recipients;
  1.1354 +	    certsonlyOptions.recipients = envelopeOptions.recipients;
  1.1355 +	    break;
  1.1356 +
  1.1357 +	case 'u': {
  1.1358 +	    int usageType;
  1.1359 +
  1.1360 +	    usageType = atoi (strdup(optstate->value));
  1.1361 +	    if (usageType < certUsageSSLClient || usageType > certUsageAnyCA)
  1.1362 +		return -1;
  1.1363 +	    options.certUsage = (SECCertUsage)usageType;
  1.1364 +	    break;
  1.1365 +	  }
  1.1366 +	case 'v':
  1.1367 +	    cms_verbose = 1;
  1.1368 +	    break;
  1.1369 +
  1.1370 +	}
  1.1371 +    }
  1.1372 +    if (status == PL_OPT_BAD)
  1.1373 +	Usage(progName);
  1.1374 +    PL_DestroyOptState(optstate);
  1.1375 +
  1.1376 +    if (mode == UNKNOWN)
  1.1377 +	Usage(progName);
  1.1378 +
  1.1379 +    if (mode != CERTSONLY && !batch) {
  1.1380 +	rv = SECU_FileToItem(&input, inFile);
  1.1381 +	if (rv != SECSuccess) {
  1.1382 +	    SECU_PrintError(progName, "unable to read infile");
  1.1383 +	    exit(1);
  1.1384 +	}
  1.1385 +	if (inFile != PR_STDIN) {
  1.1386 +	    PR_Close(inFile);
  1.1387 +    	}
  1.1388 +    }
  1.1389 +    if (cms_verbose) {
  1.1390 +	fprintf(stderr, "received commands\n");
  1.1391 +    }
  1.1392 +
  1.1393 +    /* Call the NSS initialization routines */
  1.1394 +    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
  1.1395 +    rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
  1.1396 +    if (SECSuccess != rv) {
  1.1397 +	SECU_PrintError(progName, "NSS_Init failed");
  1.1398 +	exit(1);
  1.1399 +    }
  1.1400 +    if (cms_verbose) {
  1.1401 +	fprintf(stderr, "NSS has been initialized.\n");
  1.1402 +    }
  1.1403 +    options.certHandle = CERT_GetDefaultCertDB();
  1.1404 +    if (!options.certHandle) {
  1.1405 +	SECU_PrintError(progName, "No default cert DB");
  1.1406 +	exit(1);
  1.1407 +    }
  1.1408 +    if (cms_verbose) {
  1.1409 +	fprintf(stderr, "Got default certdb\n");
  1.1410 +    }
  1.1411 +    if (options.password)
  1.1412 +    {
  1.1413 +    	pwdata.source = PW_PLAINTEXT;
  1.1414 +    	pwdata.data = options.password;
  1.1415 +    }
  1.1416 +    if (options.pwfile)
  1.1417 +    {
  1.1418 +    	pwdata.source = PW_FROMFILE;
  1.1419 +    	pwdata.data = options.pwfile;
  1.1420 +    }
  1.1421 +    pwcb = SECU_GetModulePassword;
  1.1422 +    pwcb_arg = (void *)&pwdata;
  1.1423 +
  1.1424 +    PK11_SetPasswordFunc(&SECU_GetModulePassword);
  1.1425 +
  1.1426 +
  1.1427 +#if defined(_WIN32)
  1.1428 +    if (outFile == stdout) {
  1.1429 +	/* If we're going to write binary data to stdout, we must put stdout
  1.1430 +	** into O_BINARY mode or else outgoing \n's will become \r\n's.
  1.1431 +	*/
  1.1432 +	int smrv = _setmode(_fileno(stdout), _O_BINARY);
  1.1433 +	if (smrv == -1) {
  1.1434 +	    fprintf(stderr,
  1.1435 +	    "%s: Cannot change stdout to binary mode. Use -o option instead.\n",
  1.1436 +	            progName);
  1.1437 +	    return smrv;
  1.1438 +	}
  1.1439 +    }
  1.1440 +#endif
  1.1441 +
  1.1442 +    exitstatus = 0;
  1.1443 +    switch (mode) {
  1.1444 +    case DECODE:       /* -D */
  1.1445 +	decodeOptions.options = &options;
  1.1446 +	if (encryptOptions.envFile) {
  1.1447 +	    /* Decoding encrypted-data, so get the bulkkey from an
  1.1448 +	     * enveloped-data message.
  1.1449 +	     */
  1.1450 +	    SECU_FileToItem(&envmsg, encryptOptions.envFile);
  1.1451 +	    decodeOptions.options = &options;
  1.1452 +	    encryptOptions.envmsg = decode(NULL, &envmsg, &decodeOptions);
  1.1453 +	    if (!encryptOptions.envmsg) {
  1.1454 +		SECU_PrintError(progName, "problem decoding env msg");
  1.1455 +		exitstatus = 1;
  1.1456 +		break;
  1.1457 +	    }
  1.1458 +	    rv = get_enc_params(&encryptOptions);
  1.1459 +	    decodeOptions.dkcb = dkcb;
  1.1460 +	    decodeOptions.bulkkey = encryptOptions.bulkkey;
  1.1461 +	}
  1.1462 +	if (!batch) {
  1.1463 +	    cmsg = decode(outFile, &input, &decodeOptions);
  1.1464 +	    if (!cmsg) {
  1.1465 +		SECU_PrintError(progName, "problem decoding");
  1.1466 +		exitstatus = 1;
  1.1467 +	    }
  1.1468 +	} else {
  1.1469 +	    exitstatus = doBatchDecode(outFile, inFile, &decodeOptions);
  1.1470 +	    if (inFile != PR_STDIN) {
  1.1471 +		PR_Close(inFile);
  1.1472 +	    }
  1.1473 +	}
  1.1474 +	break;
  1.1475 +    case SIGN:         /* -S */
  1.1476 +	signOptions.options = &options;
  1.1477 +	cmsg = signed_data(&signOptions);
  1.1478 +	if (!cmsg) {
  1.1479 +	    SECU_PrintError(progName, "problem signing");
  1.1480 +	    exitstatus = 1;
  1.1481 +	}
  1.1482 +	break;
  1.1483 +    case ENCRYPT:      /* -C */
  1.1484 +	if (!envFileName) {
  1.1485 +	    fprintf(stderr, "%s: you must specify an envelope file with -e.\n",
  1.1486 +	            progName);
  1.1487 +	    exit(1);
  1.1488 +	}
  1.1489 +	encryptOptions.options = &options;
  1.1490 +	encryptOptions.input = &input;
  1.1491 +	encryptOptions.outfile = outFile;
  1.1492 +	/* decode an enveloped-data message to get the bulkkey (create
  1.1493 +	 * a new one if neccessary)
  1.1494 +	 */
  1.1495 +	if (!encryptOptions.envFile) {
  1.1496 +	    encryptOptions.envFile = PR_Open(envFileName, 
  1.1497 +	                                     PR_WRONLY|PR_CREATE_FILE, 00660);
  1.1498 +	    if (!encryptOptions.envFile) {
  1.1499 +		fprintf(stderr, "%s: failed to create file %s.\n", progName,
  1.1500 +		        envFileName);
  1.1501 +		exit(1);
  1.1502 +	    }
  1.1503 +	} else {
  1.1504 +	    SECU_FileToItem(&envmsg, encryptOptions.envFile);
  1.1505 +	    decodeOptions.options = &options;
  1.1506 +	    encryptOptions.envmsg = decode(NULL, &envmsg, &decodeOptions);
  1.1507 +	    if (encryptOptions.envmsg == NULL) {
  1.1508 +	    	SECU_PrintError(progName, "problem decrypting env msg");
  1.1509 +		exitstatus = 1;
  1.1510 +	    	break;
  1.1511 +	    }
  1.1512 +	}
  1.1513 +	rv = get_enc_params(&encryptOptions);
  1.1514 +	/* create the encrypted-data message */
  1.1515 +	cmsg = encrypted_data(&encryptOptions);
  1.1516 +	if (!cmsg) {
  1.1517 +	    SECU_PrintError(progName, "problem encrypting");
  1.1518 +	    exitstatus = 1;
  1.1519 +	}
  1.1520 +	if (encryptOptions.bulkkey) {
  1.1521 +	    PK11_FreeSymKey(encryptOptions.bulkkey);
  1.1522 +	    encryptOptions.bulkkey = NULL;
  1.1523 +	}
  1.1524 +	break;
  1.1525 +    case ENVELOPE:     /* -E */
  1.1526 +	envelopeOptions.options = &options;
  1.1527 +	cmsg = enveloped_data(&envelopeOptions);
  1.1528 +	if (!cmsg) {
  1.1529 +	    SECU_PrintError(progName, "problem enveloping");
  1.1530 +	    exitstatus = 1;
  1.1531 +	}
  1.1532 +	break;
  1.1533 +    case CERTSONLY:    /* -O */
  1.1534 +	certsonlyOptions.options = &options;
  1.1535 +	cmsg = signed_data_certsonly(&certsonlyOptions);
  1.1536 +	if (!cmsg) {
  1.1537 +	    SECU_PrintError(progName, "problem with certs-only");
  1.1538 +	    exitstatus = 1;
  1.1539 +	}
  1.1540 +	break;
  1.1541 +    default:
  1.1542 +	fprintf(stderr, "One of options -D, -S or -E must be set.\n");
  1.1543 +	Usage(progName);
  1.1544 +	exitstatus = 1;
  1.1545 +    }
  1.1546 +    if ( (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY)
  1.1547 +         && (!exitstatus) ) {
  1.1548 +	PLArenaPool *arena = PORT_NewArena(1024);
  1.1549 +	NSSCMSEncoderContext *ecx;
  1.1550 +	SECItem output = { 0, 0, 0 };
  1.1551 +
  1.1552 +	if (!arena) {
  1.1553 +	    fprintf(stderr, "%s: out of memory.\n", progName);
  1.1554 +	    exit(1);
  1.1555 +	}
  1.1556 +
  1.1557 +	if (cms_verbose) {
  1.1558 +	    fprintf(stderr, "cmsg [%p]\n", cmsg);
  1.1559 +	    fprintf(stderr, "arena [%p]\n", arena);
  1.1560 +	    if (pwcb_arg && (PW_PLAINTEXT == ((secuPWData*)pwcb_arg)->source))
  1.1561 +		fprintf(stderr, "password [%s]\n",
  1.1562 +                        ((secuPWData*)pwcb_arg)->data);
  1.1563 +	    else
  1.1564 +		fprintf(stderr, "password [NULL]\n");
  1.1565 +	}
  1.1566 +	ecx = NSS_CMSEncoder_Start(cmsg, 
  1.1567 +                                   NULL, NULL,     /* DER output callback  */
  1.1568 +                                   &output, arena, /* destination storage  */
  1.1569 +                                   pwcb, pwcb_arg, /* password callback    */
  1.1570 +                                   NULL, NULL,     /* decrypt key callback */
  1.1571 +                                   NULL, NULL );   /* detached digests    */
  1.1572 +	if (!ecx) {
  1.1573 +	    fprintf(stderr, "%s: cannot create encoder context.\n", progName);
  1.1574 +	    exit(1);
  1.1575 +	}
  1.1576 +	if (cms_verbose) {
  1.1577 +	    fprintf(stderr, "input len [%d]\n", input.len);
  1.1578 +	    { unsigned int j; 
  1.1579 +		for(j=0;j<input.len;j++)
  1.1580 +	     fprintf(stderr, "%2x%c", input.data[j], (j>0&&j%35==0)?'\n':' ');
  1.1581 +	    }
  1.1582 +	}
  1.1583 +	if (input.len > 0) { /* skip if certs-only (or other zero content) */
  1.1584 +	    rv = NSS_CMSEncoder_Update(ecx, (char *)input.data, input.len);
  1.1585 +	    if (rv) {
  1.1586 +		fprintf(stderr, 
  1.1587 +		        "%s: failed to add data to encoder.\n", progName);
  1.1588 +		exit(1);
  1.1589 +	    }
  1.1590 +	}
  1.1591 +	rv = NSS_CMSEncoder_Finish(ecx);
  1.1592 +	if (rv) {
  1.1593 +            SECU_PrintError(progName, "failed to encode data");
  1.1594 +	    exit(1);
  1.1595 +	}
  1.1596 +
  1.1597 +	if (cms_verbose) {
  1.1598 +	    fprintf(stderr, "encoding passed\n");
  1.1599 +	}
  1.1600 +	fwrite(output.data, output.len, 1, outFile);
  1.1601 +	if (cms_verbose) {
  1.1602 +	    fprintf(stderr, "wrote to file\n");
  1.1603 +	}
  1.1604 +	PORT_FreeArena(arena, PR_FALSE);
  1.1605 +    }
  1.1606 +    if (cmsg)
  1.1607 +	NSS_CMSMessage_Destroy(cmsg);
  1.1608 +    if (outFile != stdout)
  1.1609 +	fclose(outFile);
  1.1610 +
  1.1611 +    SECITEM_FreeItem(&decodeOptions.content, PR_FALSE);
  1.1612 +    SECITEM_FreeItem(&envmsg, PR_FALSE);
  1.1613 +    SECITEM_FreeItem(&input, PR_FALSE);
  1.1614 +    if (NSS_Shutdown() != SECSuccess) {
  1.1615 +	SECU_PrintError(progName, "NSS_Shutdown failed");
  1.1616 +	exitstatus = 1;
  1.1617 +    }
  1.1618 +    PR_Cleanup();
  1.1619 +    return exitstatus;
  1.1620 +}

mercurial