security/nss/cmd/smimetools/cmsutil.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial