PageRenderTime 70ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/security/nss/cmd/smimetools/cmsutil.c

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