cmsutil.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:38k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34.  * cmsutil -- A command to work with CMS data
  35.  *
  36.  * $Id: cmsutil.c,v 1.15 2000/10/11 07:21:38 wtc%netscape.com Exp $
  37.  */
  38. #include "nspr.h"
  39. #include "secutil.h"
  40. #include "plgetopt.h"
  41. #include "secpkcs7.h"
  42. #include "cert.h"
  43. #include "certdb.h"
  44. #include "cdbhdl.h"
  45. #include "secoid.h"
  46. #include "cms.h"
  47. #include "nss.h"
  48. #include "smime.h"
  49. #if defined(XP_UNIX)
  50. #include <unistd.h>
  51. #endif
  52. #include <stdio.h>
  53. #include <string.h>
  54. extern void SEC_Init(void); /* XXX */
  55. char *progName = NULL;
  56. static SECStatus
  57. DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input,
  58.            SECAlgorithmID **algids)
  59. {
  60.     NSSCMSDigestContext *digcx;
  61.     digcx = NSS_CMSDigestContext_StartMultiple(algids);
  62.     if (digcx == NULL)
  63. return SECFailure;
  64.     NSS_CMSDigestContext_Update(digcx, input->data, input->len);
  65.     return NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests);
  66. }
  67. static void
  68. Usage(char *progName)
  69. {
  70.     fprintf(stderr, "Usage:  %s [-D|-S|-E] [<options>] [-d dbdir] [-u certusage]n", progName);
  71.     fprintf(stderr, " -i infile     use infile as source of data (default: stdin)n");
  72.     fprintf(stderr, " -o outfile    use outfile as destination of data (default: stdout)n");
  73.     fprintf(stderr, " -d dbdir      key/cert database directory (default: ~/.netscape)n");
  74.     fprintf(stderr, " -p password   use password as key db password (default: prompt)n");
  75.     fprintf(stderr, " -u certusage  set type of certificate usage (default: certUsageEmailSigner)n");
  76.     fprintf(stderr, "n");
  77.     fprintf(stderr, " -D            decode a CMS messagen");
  78.     fprintf(stderr, "  -c content   use this detached contentn");
  79.     fprintf(stderr, "  -n           suppress output of contentn");
  80.     fprintf(stderr, "  -h num       generate email headers with info about CMS messagen");
  81.     fprintf(stderr, " -S            create a CMS signed messagen");
  82.     fprintf(stderr, "  -N nick      use certificate named "nick" for signingn");
  83.     fprintf(stderr, "  -T           do not include content in CMS messagen");
  84.     fprintf(stderr, "  -G           include a signing time attributen");
  85.     fprintf(stderr, "  -P           include a SMIMECapabilities attributen");
  86.     fprintf(stderr, "  -Y nick      include a EncryptionKeyPreference attribute with certn");
  87.     fprintf(stderr, " -E            create a CMS enveloped message (NYI)n");
  88.     fprintf(stderr, "  -r id,...    create envelope for these recipients,n");
  89.     fprintf(stderr, "               where id can be a certificate nickname or email addressn");
  90.     fprintf(stderr, "nCert usage codes:n");
  91.     fprintf(stderr, "%-25s  0 - certUsageSSLClientn", " ");
  92.     fprintf(stderr, "%-25s  1 - certUsageSSLServern", " ");
  93.     fprintf(stderr, "%-25s  2 - certUsageSSLServerWithStepUpn", " ");
  94.     fprintf(stderr, "%-25s  3 - certUsageSSLCAn", " ");
  95.     fprintf(stderr, "%-25s  4 - certUsageEmailSignern", " ");
  96.     fprintf(stderr, "%-25s  5 - certUsageEmailRecipientn", " ");
  97.     fprintf(stderr, "%-25s  6 - certUsageObjectSignern", " ");
  98.     fprintf(stderr, "%-25s  7 - certUsageUserCertImportn", " ");
  99.     fprintf(stderr, "%-25s  8 - certUsageVerifyCAn", " ");
  100.     fprintf(stderr, "%-25s  9 - certUsageProtectedObjectSignern", " ");
  101.     fprintf(stderr, "%-25s 10 - certUsageStatusRespondern", " ");
  102.     fprintf(stderr, "%-25s 11 - certUsageAnyCAn", " ");
  103.     exit(-1);
  104. }
  105. static CERTCertDBHandle certHandleStatic; /* avoid having to allocate */
  106. static CERTCertDBHandle *
  107. OpenCertDB(char *progName)
  108. {
  109.     CERTCertDBHandle *certHandle;
  110.     SECStatus rv;
  111.     certHandle = &certHandleStatic;
  112.     rv = CERT_OpenCertDB(certHandle, PR_FALSE, SECU_CertDBNameCallback, NULL);
  113.     if (rv != SECSuccess) {
  114.         SECU_PrintError(progName, "could not open cert database");
  115. return NULL;
  116.     }
  117.     return certHandle;
  118. }
  119. char *
  120. ownpw(PK11SlotInfo *info, PRBool retry, void *arg)
  121. {
  122. char * passwd = NULL;
  123. if ( (!retry) && arg ) {
  124. passwd = PL_strdup((char *)arg);
  125. }
  126. return passwd;
  127. }
  128. struct optionsStr {
  129.     char *password;
  130.     SECCertUsage certUsage;
  131.     CERTCertDBHandle *certHandle;
  132. };
  133. struct decodeOptionsStr {
  134.     struct optionsStr *options;
  135.     PRFileDesc *contentFile;
  136.     int headerLevel;
  137.     PRBool suppressContent;
  138.     NSSCMSGetDecryptKeyCallback dkcb;
  139.     PK11SymKey *bulkkey;
  140. };
  141. struct signOptionsStr {
  142.     struct optionsStr *options;
  143.     char *nickname;
  144.     char *encryptionKeyPreferenceNick;
  145.     PRBool signingTime;
  146.     PRBool smimeProfile;
  147.     PRBool detached;
  148. };
  149. struct envelopeOptionsStr {
  150.     struct optionsStr *options;
  151.     char **recipients;
  152. };
  153. struct certsonlyOptionsStr {
  154.     struct optionsStr *options;
  155.     char **recipients;
  156. };
  157. struct encryptOptionsStr {
  158.     struct optionsStr *options;
  159.     char **recipients;
  160.     NSSCMSMessage *envmsg;
  161.     SECItem *input;
  162.     FILE *outfile;
  163.     PRFileDesc *envFile;
  164.     PK11SymKey *bulkkey;
  165.     SECOidTag bulkalgtag;
  166.     int keysize;
  167. };
  168. static NSSCMSMessage *
  169. decode(FILE *out, SECItem *output, SECItem *input, 
  170.        struct decodeOptionsStr decodeOptions)
  171. {
  172.     NSSCMSDecoderContext *dcx;
  173.     NSSCMSMessage *cmsg;
  174.     NSSCMSContentInfo *cinfo;
  175.     NSSCMSSignedData *sigd = NULL;
  176.     NSSCMSEnvelopedData *envd;
  177.     NSSCMSEncryptedData *encd;
  178.     SECAlgorithmID **digestalgs;
  179.     int nlevels, i, nsigners, j;
  180.     char *signercn;
  181.     NSSCMSSignerInfo *si;
  182.     SECOidTag typetag;
  183.     SECItem **digests;
  184.     PLArenaPool *poolp;
  185.     PK11PasswordFunc pwcb;
  186.     void *pwcb_arg;
  187.     SECItem *item, sitem = { 0, 0, 0 };
  188.     pwcb     = (decodeOptions.options->password != NULL) ? ownpw : NULL;
  189.     pwcb_arg = (decodeOptions.options->password != NULL) ? 
  190.                   (void *)decodeOptions.options->password : NULL;
  191.     if (decodeOptions.contentFile) {
  192. /* detached content: grab content file */
  193. SECU_FileToItem(&sitem, decodeOptions.contentFile);
  194. item = &sitem;
  195.     }
  196.     dcx = NSS_CMSDecoder_Start(NULL, 
  197.                                NULL, NULL,         /* content callback     */
  198.                                pwcb, pwcb_arg,     /* password callback    */
  199.        decodeOptions.dkcb, /* decrypt key callback */
  200.                                decodeOptions.bulkkey);
  201.     (void)NSS_CMSDecoder_Update(dcx, input->data, input->len);
  202.     cmsg = NSS_CMSDecoder_Finish(dcx);
  203.     if (cmsg == NULL) {
  204. fprintf(stderr, "%s: failed to decode message.n", progName);
  205. return NULL;
  206.     }
  207.     if (decodeOptions.headerLevel >= 0) {
  208. /*fprintf(out, "SMIME: ", decodeOptions.headerLevel, i);*/
  209. fprintf(out, "SMIME: ");
  210.     }
  211.     nlevels = NSS_CMSMessage_ContentLevelCount(cmsg);
  212.     for (i = 0; i < nlevels; i++) {
  213. cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);
  214. typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
  215. if (decodeOptions.headerLevel >= 0)
  216.     fprintf(out, "tlevel=%d.%d; ", decodeOptions.headerLevel, nlevels - i);
  217. switch (typetag) {
  218. case SEC_OID_PKCS7_SIGNED_DATA:
  219.     if (decodeOptions.headerLevel >= 0)
  220. fprintf(out, "type=signedData; ");
  221.     sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
  222.     if (sigd == NULL) {
  223. SECU_PrintError(progName, 
  224.                 "problem finding signedData component");
  225. goto loser;
  226.     }
  227.     /* if we have a content file, but no digests for this signedData */
  228.     if (decodeOptions.contentFile != NULL && !NSS_CMSSignedData_HasDigests(sigd)) {
  229. if ((poolp = PORT_NewArena(1024)) == NULL) {
  230.     fprintf(stderr, "cmsutil: Out of memory.n");
  231.     goto loser;
  232. }
  233. digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
  234. if (DigestFile (poolp, &digests, item, digestalgs) 
  235.       != SECSuccess) {
  236.     SECU_PrintError(progName, 
  237.                     "problem computing message digest");
  238.     goto loser;
  239. }
  240. if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) {
  241.     
  242.     SECU_PrintError(progName, 
  243.                     "problem setting message digests");
  244.     goto loser;
  245. }
  246. PORT_FreeArena(poolp, PR_FALSE);
  247.     }
  248.     /* import the certificates */
  249.     if (NSS_CMSSignedData_ImportCerts(sigd, 
  250.                                      decodeOptions.options->certHandle, 
  251.                                      decodeOptions.options->certUsage, 
  252.                                      PR_FALSE) 
  253.           != SECSuccess) {
  254. SECU_PrintError(progName, "cert import failed");
  255. goto loser;
  256.     }
  257.     /* find out about signers */
  258.     nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
  259.     if (decodeOptions.headerLevel >= 0)
  260. fprintf(out, "nsigners=%d; ", nsigners);
  261.     if (nsigners == 0) {
  262. /* must be a cert transport message */
  263. SECStatus rv;
  264. /* XXX workaround for bug #54014 */
  265. NSS_CMSSignedData_ImportCerts(sigd, 
  266.                                              decodeOptions.options->certHandle, 
  267.                              decodeOptions.options->certUsage, 
  268.                              PR_TRUE);
  269. rv = NSS_CMSSignedData_VerifyCertsOnly(sigd, 
  270.                              decodeOptions.options->certHandle, 
  271.                              decodeOptions.options->certUsage);
  272. if (rv != SECSuccess) {
  273.     fprintf(stderr, "cmsutil: Verify certs-only failed!n");
  274.     goto loser;
  275. }
  276. return cmsg;
  277.     }
  278.     /* still no digests? */
  279.     if (!NSS_CMSSignedData_HasDigests(sigd)) {
  280. SECU_PrintError(progName, "no message digests");
  281. goto loser;
  282.     }
  283.     for (j = 0; j < nsigners; j++) {
  284. si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
  285. signercn = NSS_CMSSignerInfo_GetSignerCommonName(si);
  286. if (signercn == NULL)
  287.     signercn = "";
  288. if (decodeOptions.headerLevel >= 0)
  289.     fprintf(out, "nttsigner%d.id="%s"; ", j, signercn);
  290. (void)NSS_CMSSignedData_VerifySignerInfo(sigd, j, 
  291.                              decodeOptions.options->certHandle, 
  292.                              decodeOptions.options->certUsage);
  293. if (decodeOptions.headerLevel >= 0)
  294.     fprintf(out, "signer%d.status=%s; ", j, 
  295.             NSS_CMSUtil_VerificationStatusToString(
  296.                   NSS_CMSSignerInfo_GetVerificationStatus(si)));
  297.     /* XXX what do we do if we don't print headers? */
  298.     }
  299.     break;
  300. case SEC_OID_PKCS7_ENVELOPED_DATA:
  301.     if (decodeOptions.headerLevel >= 0)
  302. fprintf(out, "type=envelopedData; ");
  303.     envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);
  304.     break;
  305. case SEC_OID_PKCS7_ENCRYPTED_DATA:
  306.     if (decodeOptions.headerLevel >= 0)
  307. fprintf(out, "type=encryptedData; ");
  308.     encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
  309.     break;
  310. case SEC_OID_PKCS7_DATA:
  311.     if (decodeOptions.headerLevel >= 0)
  312. fprintf(out, "type=data; ");
  313.     break;
  314. default:
  315.     break;
  316. }
  317. if (decodeOptions.headerLevel >= 0)
  318.     fprintf(out, "n");
  319.     }
  320.     if (!decodeOptions.suppressContent) {
  321. if (!decodeOptions.contentFile) 
  322.     item = NSS_CMSMessage_GetContent(cmsg);
  323. SECITEM_CopyItem(NULL, output, item);
  324.     }
  325.     return cmsg;
  326. loser:
  327.     if (cmsg)
  328. NSS_CMSMessage_Destroy(cmsg);
  329.     return NULL;
  330. }
  331. /* example of a callback function to use with encoder */
  332. /*
  333. static void
  334. writeout(void *arg, const char *buf, unsigned long len)
  335. {
  336.     FILE *f = (FILE *)arg;
  337.     if (f != NULL && buf != NULL)
  338. (void)fwrite(buf, len, 1, f);
  339. }
  340. */
  341. static NSSCMSMessage *
  342. signed_data(struct signOptionsStr signOptions)
  343. {
  344.     NSSCMSMessage *cmsg = NULL;
  345.     NSSCMSContentInfo *cinfo;
  346.     NSSCMSSignedData *sigd;
  347.     NSSCMSSignerInfo *signerinfo;
  348.     CERTCertificate *cert, *ekpcert;
  349.     if (signOptions.nickname == NULL) {
  350. fprintf(stderr, 
  351.         "ERROR: please indicate the nickname of a certificate to sign with.n");
  352. return NULL;
  353.     }
  354.     if ((cert = CERT_FindCertByNickname(signOptions.options->certHandle, 
  355.                                         signOptions.nickname)) == NULL) {
  356. SECU_PrintError(progName, 
  357.                 "the corresponding cert for key "%s" does not exist",
  358.                 signOptions.nickname);
  359. return NULL;
  360.     }
  361.     /*
  362.      * create the message object
  363.      */
  364.     cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
  365.     if (cmsg == NULL) {
  366. fprintf(stderr, "ERROR: cannot create CMS message.n");
  367. return NULL;
  368.     }
  369.     /*
  370.      * build chain of objects: message->signedData->data
  371.      */
  372.     if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
  373. fprintf(stderr, "ERROR: cannot create CMS signedData object.n");
  374. goto loser;
  375.     }
  376.     cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  377.     if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) 
  378.           != SECSuccess) {
  379. fprintf(stderr, "ERROR: cannot attach CMS signedData object.n");
  380. goto loser;
  381.     }
  382.     cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
  383.     /* we're always passing data in and detaching optionally */
  384.     if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, 
  385.                                            signOptions.detached) 
  386.           != SECSuccess) {
  387. fprintf(stderr, "ERROR: cannot attach CMS data object.n");
  388. goto loser;
  389.     }
  390.     /* 
  391.      * create & attach signer information
  392.      */
  393.     if ((signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, SEC_OID_SHA1)) 
  394.           == NULL) {
  395. fprintf(stderr, "ERROR: cannot create CMS signerInfo object.n");
  396. goto loser;
  397.     }
  398.     /* we want the cert chain included for this one */
  399.     if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, 
  400.                                        signOptions.options->certUsage) 
  401.           != SECSuccess) {
  402. fprintf(stderr, "ERROR: cannot find cert chain.n");
  403. goto loser;
  404.     }
  405.     if (signOptions.signingTime) {
  406. if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) 
  407.       != SECSuccess) {
  408.     fprintf(stderr, "ERROR: cannot add signingTime attribute.n");
  409.     goto loser;
  410. }
  411.     }
  412.     if (signOptions.smimeProfile) {
  413. if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
  414.     fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.n");
  415.     goto loser;
  416. }
  417.     }
  418.     if (signOptions.encryptionKeyPreferenceNick) {
  419. /* get the cert, add it to the message */
  420. if ((ekpcert = CERT_FindCertByNickname(signOptions.options->certHandle, 
  421.                                signOptions.encryptionKeyPreferenceNick))
  422.       == NULL) {
  423.     SECU_PrintError(progName, 
  424.                  "the corresponding cert for key "%s" does not exist",
  425.                     signOptions.encryptionKeyPreferenceNick);
  426.     goto loser;
  427. }
  428. if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert, 
  429.                                         signOptions.options->certHandle)
  430.       != SECSuccess) {
  431.     fprintf(stderr, "ERROR: cannot add SMIMEEncKeyPrefs attribute.n");
  432.     goto loser;
  433. }
  434. if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
  435.     fprintf(stderr, "ERROR: cannot add encryption certificate.n");
  436.     goto loser;
  437. }
  438.     } else {
  439. /* check signing cert for fitness as encryption cert */
  440. /* if yes, add signing cert as EncryptionKeyPreference */
  441. if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, cert, 
  442.                                         signOptions.options->certHandle)
  443.       != SECSuccess) {
  444.     fprintf(stderr, 
  445.             "ERROR: cannot add default SMIMEEncKeyPrefs attribute.n");
  446.     goto loser;
  447. }
  448.     }
  449.     if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
  450. fprintf(stderr, "ERROR: cannot add CMS signerInfo object.n");
  451. goto loser;
  452.     }
  453.     return cmsg;
  454. loser:
  455.     NSS_CMSMessage_Destroy(cmsg);
  456.     return NULL;
  457. }
  458. static NSSCMSMessage *
  459. enveloped_data(struct envelopeOptionsStr envelopeOptions)
  460. {
  461.     NSSCMSMessage *cmsg = NULL;
  462.     NSSCMSContentInfo *cinfo;
  463.     NSSCMSEnvelopedData *envd;
  464.     NSSCMSRecipientInfo *recipientinfo;
  465.     CERTCertificate **recipientcerts;
  466.     CERTCertDBHandle *dbhandle;
  467.     PLArenaPool *tmppoolp = NULL;
  468.     SECOidTag bulkalgtag;
  469.     int keysize, i;
  470.     int cnt;
  471.     dbhandle = envelopeOptions.options->certHandle;
  472.     /* count the recipients */
  473.     if ((cnt = NSS_CMSArray_Count(envelopeOptions.recipients)) == 0) {
  474. fprintf(stderr, "ERROR: please name at least one recipient.n");
  475. goto loser;
  476.     }
  477.     if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
  478. fprintf(stderr, "ERROR: out of memory.n");
  479. goto loser;
  480.     }
  481.     /* XXX find the recipient's certs by email address or nickname */
  482.     if ((recipientcerts = 
  483.          (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp, 
  484.      (cnt+1)*sizeof(CERTCertificate*)))
  485.             == NULL) {
  486. fprintf(stderr, "ERROR: out of memory.n");
  487. goto loser;
  488.     }
  489.     for (i=0; envelopeOptions.recipients[i] != NULL; i++) {
  490. if ((recipientcerts[i] = 
  491.       CERT_FindCertByNicknameOrEmailAddr(dbhandle,  
  492.                                         envelopeOptions.recipients[i]))
  493.         == NULL) {
  494.     SECU_PrintError(progName, "cannot find certificate for "%s"", 
  495.                     envelopeOptions.recipients[i]);
  496.     goto loser;
  497. }
  498.     }
  499.     recipientcerts[i] = NULL;
  500.     /* find a nice bulk algorithm */
  501.     if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientcerts, &bulkalgtag, 
  502.                                                &keysize) != SECSuccess) {
  503. fprintf(stderr, "ERROR: cannot find common bulk algorithm.n");
  504. goto loser;
  505.     }
  506.     /*
  507.      * create the message object
  508.      */
  509.     cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
  510.     if (cmsg == NULL) {
  511. fprintf(stderr, "ERROR: cannot create CMS message.n");
  512. goto loser;
  513.     }
  514.     /*
  515.      * build chain of objects: message->envelopedData->data
  516.      */
  517.     if ((envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, keysize)) 
  518.           == NULL) {
  519. fprintf(stderr, "ERROR: cannot create CMS envelopedData object.n");
  520. goto loser;
  521.     }
  522.     cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  523.     if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) 
  524.           != SECSuccess) {
  525. fprintf(stderr, "ERROR: cannot attach CMS envelopedData object.n");
  526. goto loser;
  527.     }
  528.     cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
  529.     /* we're always passing data in, so the content is NULL */
  530.     if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
  531.           != SECSuccess) {
  532. fprintf(stderr, "ERROR: cannot attach CMS data object.n");
  533. goto loser;
  534.     }
  535.     /* 
  536.      * create & attach recipient information
  537.      */
  538.     for (i = 0; recipientcerts[i] != NULL; i++) {
  539. if ((recipientinfo = NSS_CMSRecipientInfo_Create(cmsg, 
  540.                                                  recipientcerts[i])) 
  541.       == NULL) {
  542.     fprintf(stderr, "ERROR: cannot create CMS recipientInfo object.n");
  543.     goto loser;
  544. }
  545. if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientinfo) 
  546.       != SECSuccess) {
  547.     fprintf(stderr, "ERROR: cannot add CMS recipientInfo object.n");
  548.     goto loser;
  549. }
  550.     }
  551.     if (tmppoolp)
  552. PORT_FreeArena(tmppoolp, PR_FALSE);
  553.     return cmsg;
  554. loser:
  555.     if (cmsg)
  556. NSS_CMSMessage_Destroy(cmsg);
  557.     if (tmppoolp)
  558. PORT_FreeArena(tmppoolp, PR_FALSE);
  559.     return NULL;
  560. }
  561. PK11SymKey *dkcb(void *arg, SECAlgorithmID *algid)
  562. {
  563.     return (PK11SymKey*)arg;
  564. }
  565. static SECStatus
  566. get_enc_params(struct encryptOptionsStr *encryptOptions)
  567. {
  568.     struct envelopeOptionsStr envelopeOptions;
  569.     SECStatus rv = SECFailure;
  570.     NSSCMSMessage *env_cmsg;
  571.     NSSCMSContentInfo *cinfo;
  572.     PK11SymKey *bulkkey = NULL;
  573.     SECOidTag bulkalgtag;
  574.     int keysize;
  575.     int i, nlevels;
  576.     /*
  577.      * construct an enveloped data message to obtain bulk keys
  578.      */
  579.     if (encryptOptions->envmsg) {
  580. env_cmsg = encryptOptions->envmsg; /* get it from an old message */
  581.     } else {
  582. SECItem dummyOut = { 0, 0, 0 };
  583. SECItem dummyIn  = { 0, 0, 0 };
  584. char str[] = "Hello!";
  585. PLArenaPool *tmparena = PORT_NewArena(1024);
  586. dummyIn.data = str;
  587. dummyIn.len = strlen(str);
  588. envelopeOptions.options = encryptOptions->options;
  589. envelopeOptions.recipients = encryptOptions->recipients;
  590. env_cmsg = enveloped_data(envelopeOptions);
  591. NSS_CMSDEREncode(env_cmsg, &dummyIn, &dummyOut, tmparena);
  592. PR_Write(encryptOptions->envFile, dummyOut.data, dummyOut.len);
  593. PORT_FreeArena(tmparena, PR_FALSE);
  594.     }
  595.     /*
  596.      * get the content info for the enveloped data 
  597.      */
  598.     nlevels = NSS_CMSMessage_ContentLevelCount(env_cmsg);
  599.     for (i = 0; i < nlevels; i++) {
  600.      SECOidTag typetag;
  601. cinfo = NSS_CMSMessage_ContentLevel(env_cmsg, i);
  602. typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
  603. if (typetag == SEC_OID_PKCS7_DATA) {
  604.     /*
  605.      * get the symmetric key
  606.      */
  607.     bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo);
  608.     keysize = NSS_CMSContentInfo_GetBulkKeySize(cinfo);
  609.     bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
  610.     break;
  611. }
  612.     }
  613.     if (i == nlevels) {
  614. fprintf(stderr, "%s: could not retrieve enveloped data.", progName);
  615. goto loser;
  616.     }
  617.     encryptOptions->bulkalgtag = bulkalgtag;
  618.     encryptOptions->bulkkey = bulkkey;
  619.     encryptOptions->keysize = keysize;
  620.     rv = SECSuccess;
  621. loser:
  622.     if (env_cmsg)
  623. NSS_CMSMessage_Destroy(env_cmsg);
  624.     return rv;
  625. }
  626. static NSSCMSMessage *
  627. encrypted_data(struct encryptOptionsStr encryptOptions)
  628. {
  629.     SECStatus rv = SECFailure;
  630.     NSSCMSMessage *cmsg = NULL;
  631.     NSSCMSContentInfo *cinfo;
  632.     NSSCMSEncryptedData *encd;
  633.     NSSCMSEncoderContext *ecx = NULL;
  634.     PLArenaPool *tmppoolp = NULL;
  635.     SECItem derOut = { 0, 0, 0 };
  636.     /* arena for output */
  637.     tmppoolp = PORT_NewArena(1024);
  638.     if (!tmppoolp) {
  639. fprintf(stderr, "%s: out of memory.n", progName);
  640. return NULL;
  641.     }
  642.     /*
  643.      * create the message object
  644.      */
  645.     cmsg = NSS_CMSMessage_Create(NULL);
  646.     if (cmsg == NULL) {
  647. fprintf(stderr, "ERROR: cannot create CMS message.n");
  648. goto loser;
  649.     }
  650.     /*
  651.      * build chain of objects: message->encryptedData->data
  652.      */
  653.     if ((encd = NSS_CMSEncryptedData_Create(cmsg, encryptOptions.bulkalgtag, 
  654.                                                   encryptOptions.keysize)) 
  655.            == NULL) {
  656. fprintf(stderr, "ERROR: cannot create CMS encryptedData object.n");
  657. goto loser;
  658.     }
  659.     cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  660.     if (NSS_CMSContentInfo_SetContent_EncryptedData(cmsg, cinfo, encd)
  661.           != SECSuccess) {
  662. fprintf(stderr, "ERROR: cannot attach CMS encryptedData object.n");
  663. goto loser;
  664.     }
  665.     cinfo = NSS_CMSEncryptedData_GetContentInfo(encd);
  666.     /* we're always passing data in, so the content is NULL */
  667.     if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
  668.           != SECSuccess) {
  669. fprintf(stderr, "ERROR: cannot attach CMS data object.n");
  670. goto loser;
  671.     }
  672.     ecx = NSS_CMSEncoder_Start(cmsg, NULL, NULL, &derOut, tmppoolp, NULL, NULL,
  673.                                dkcb, encryptOptions.bulkkey, NULL, NULL);
  674.     if (!ecx) {
  675. fprintf(stderr, "%s: cannot create encoder context.n", progName);
  676. goto loser;
  677.     }
  678.     rv = NSS_CMSEncoder_Update(ecx, encryptOptions.input->data, 
  679.                                     encryptOptions.input->len);
  680.     if (rv) {
  681. fprintf(stderr, "%s: failed to add data to encoder.n", progName);
  682. goto loser;
  683.     }
  684.     rv = NSS_CMSEncoder_Finish(ecx);
  685.     if (rv) {
  686. fprintf(stderr, "%s: failed to encrypt data.n", progName);
  687. goto loser;
  688.     }
  689.     fwrite(derOut.data, derOut.len, 1, encryptOptions.outfile);
  690.     /*
  691.     if (bulkkey)
  692. PK11_FreeSymKey(bulkkey);
  693. */
  694.     if (tmppoolp)
  695. PORT_FreeArena(tmppoolp, PR_FALSE);
  696.     return cmsg;
  697. loser:
  698.     /*
  699.     if (bulkkey)
  700. PK11_FreeSymKey(bulkkey);
  701. */
  702.     if (tmppoolp)
  703. PORT_FreeArena(tmppoolp, PR_FALSE);
  704.     if (cmsg)
  705. NSS_CMSMessage_Destroy(cmsg);
  706.     return NULL;
  707. }
  708. static NSSCMSMessage *
  709. signed_data_certsonly(struct certsonlyOptionsStr certsonlyOptions)
  710. {
  711.     NSSCMSMessage *cmsg = NULL;
  712.     NSSCMSContentInfo *cinfo;
  713.     NSSCMSSignedData *sigd;
  714.     CERTCertificate **certs;
  715.     CERTCertDBHandle *dbhandle;
  716.     PLArenaPool *tmppoolp = NULL;
  717.     int i, cnt;
  718.     dbhandle = certsonlyOptions.options->certHandle;
  719.     if ((cnt = NSS_CMSArray_Count(certsonlyOptions.recipients)) == 0) {
  720. fprintf(stderr, 
  721.         "ERROR: please indicate the nickname of a certificate to sign with.n");
  722. goto loser;
  723.     }
  724.     if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
  725. fprintf(stderr, "ERROR: out of memory.n");
  726. goto loser;
  727.     }
  728.     if ((certs = 
  729.          (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp, 
  730.      (cnt+1)*sizeof(CERTCertificate*)))
  731.             == NULL) {
  732. fprintf(stderr, "ERROR: out of memory.n");
  733. goto loser;
  734.     }
  735.     for (i=0; certsonlyOptions.recipients[i] != NULL; i++) {
  736. if ((certs[i] = 
  737.       CERT_FindCertByNicknameOrEmailAddr(dbhandle,
  738.                                         certsonlyOptions.recipients[i]))
  739.         == NULL) {
  740.     SECU_PrintError(progName, "cannot find certificate for "%s"", 
  741.                     certsonlyOptions.recipients[i]);
  742.     goto loser;
  743. }
  744.     }
  745.     certs[i] = NULL;
  746.     /*
  747.      * create the message object
  748.      */
  749.     cmsg = NSS_CMSMessage_Create(NULL);
  750.     if (cmsg == NULL) {
  751. fprintf(stderr, "ERROR: cannot create CMS message.n");
  752. goto loser;
  753.     }
  754.     /*
  755.      * build chain of objects: message->signedData->data
  756.      */
  757.     if ((sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, certs[0], PR_TRUE))
  758.           == NULL) {
  759. fprintf(stderr, "ERROR: cannot create CMS signedData object.n");
  760. goto loser;
  761.     }
  762.     for (i=1; i<cnt; i++) {
  763. if (NSS_CMSSignedData_AddCertChain(sigd, certs[i])) {
  764.     fprintf(stderr, "ERROR: cannot add cert chain for "%s".n",
  765.             certsonlyOptions.recipients[i]);
  766.     goto loser;
  767. }
  768.     }
  769.     cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  770.     if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) 
  771.           != SECSuccess) {
  772. fprintf(stderr, "ERROR: cannot attach CMS signedData object.n");
  773. goto loser;
  774.     }
  775.     cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
  776.     if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) 
  777.    != SECSuccess) {
  778. fprintf(stderr, "ERROR: cannot attach CMS data object.n");
  779. goto loser;
  780.     }
  781.     if (tmppoolp)
  782. PORT_FreeArena(tmppoolp, PR_FALSE);
  783.     return cmsg;
  784. loser:
  785.     if (cmsg)
  786. NSS_CMSMessage_Destroy(cmsg);
  787.     if (tmppoolp)
  788. PORT_FreeArena(tmppoolp, PR_FALSE);
  789.     return NULL;
  790. }
  791. typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode;
  792. #if 0
  793. void
  794. parse_message_for_recipients(PRFileDesc *inFile, 
  795.                              struct envelopeOptionsStr *envelopeOptions)
  796. {
  797.     SECItem filedata;
  798.     SECStatus rv;
  799.     rv = SECU_FileToItem(&filedata, inFile);
  800. }
  801. #endif
  802. int
  803. main(int argc, char **argv)
  804. {
  805.     FILE *outFile;
  806.     NSSCMSMessage *cmsg;
  807.     PRFileDesc *inFile;
  808.     PLOptState *optstate;
  809.     PLOptStatus status;
  810.     Mode mode = UNKNOWN;
  811.     PK11PasswordFunc pwcb;
  812.     void *pwcb_arg;
  813.     struct decodeOptionsStr decodeOptions = { 0 };
  814.     struct signOptionsStr signOptions = { 0 };
  815.     struct envelopeOptionsStr envelopeOptions = { 0 };
  816.     struct certsonlyOptionsStr certsonlyOptions = { 0 };
  817.     struct encryptOptionsStr encryptOptions = { 0 };
  818.     struct optionsStr options = { 0 };
  819.     int exitstatus;
  820.     static char *ptrarray[128] = { 0 };
  821.     int nrecipients = 0;
  822.     char *str, *tok;
  823.     char *envFileName;
  824.     SECItem input = { 0, 0, 0};
  825.     SECItem output = { 0, 0, 0};
  826.     SECItem dummy = { 0, 0, 0 };
  827.     SECItem envmsg = { 0, 0, 0 };
  828.     SECStatus rv;
  829.     progName = strrchr(argv[0], '/');
  830.     progName = progName ? progName+1 : argv[0];
  831.     inFile = PR_STDIN;
  832.     outFile = stdout;
  833.     envFileName = NULL;
  834.     mode = UNKNOWN;
  835.     decodeOptions.contentFile = NULL;
  836.     decodeOptions.suppressContent = PR_FALSE;
  837.     decodeOptions.headerLevel = -1;
  838.     options.certUsage = certUsageEmailSigner;
  839.     options.password = NULL;
  840.     signOptions.nickname = NULL;
  841.     signOptions.detached = PR_FALSE;
  842.     signOptions.signingTime = PR_FALSE;
  843.     signOptions.smimeProfile = PR_FALSE;
  844.     signOptions.encryptionKeyPreferenceNick = NULL;
  845.     envelopeOptions.recipients = NULL;
  846.     encryptOptions.recipients = NULL;
  847.     encryptOptions.envmsg = NULL;
  848.     encryptOptions.envFile = NULL;
  849.     encryptOptions.bulkalgtag = SEC_OID_UNKNOWN;
  850.     encryptOptions.bulkkey = NULL;
  851.     encryptOptions.keysize = -1;
  852.     /*
  853.      * Parse command line arguments
  854.      */
  855.     optstate = PL_CreateOptState(argc, argv, 
  856.                                  "CDSEOnN:TGPY:h:p:i:c:d:e:o:s:u:r:");
  857.     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
  858. switch (optstate->option) {
  859. case '?':
  860.     Usage(progName);
  861.     break;
  862. case 'C':
  863.     mode = ENCRYPT;
  864.     break;
  865. case 'D':
  866.     mode = DECODE;
  867.     break;
  868. case 'S':
  869.     mode = SIGN;
  870.     break;
  871. case 'E':
  872.     mode = ENVELOPE;
  873.     break;
  874. case 'O':
  875.     mode = CERTSONLY;
  876.     break;
  877. case 'n':
  878.     if (mode != DECODE) {
  879. fprintf(stderr, 
  880.         "%s: option -n only supported with option -D.n", 
  881.         progName);
  882. Usage(progName);
  883. exit(1);
  884.     }
  885.     decodeOptions.suppressContent = PR_TRUE;
  886.     break;
  887. case 'N':
  888.     if (mode != SIGN) {
  889. fprintf(stderr, 
  890.         "%s: option -N only supported with option -S.n", 
  891.         progName);
  892. Usage(progName);
  893. exit(1);
  894.     }
  895.     signOptions.nickname = strdup(optstate->value);
  896.     break;
  897. case 'Y':
  898.     if (mode != SIGN) {
  899. fprintf(stderr, 
  900.         "%s: option -Y only supported with option -S.n", 
  901.         progName);
  902. Usage(progName);
  903. exit(1);
  904.     }
  905.     signOptions.encryptionKeyPreferenceNick = strdup(optstate->value);
  906.     break;
  907. case 'T':
  908.     if (mode != SIGN) {
  909. fprintf(stderr, 
  910.         "%s: option -T only supported with option -S.n", 
  911.         progName);
  912. Usage(progName);
  913. exit(1);
  914.     }
  915.     signOptions.detached = PR_TRUE;
  916.     break;
  917. case 'G':
  918.     if (mode != SIGN) {
  919. fprintf(stderr, 
  920.         "%s: option -G only supported with option -S.n", 
  921.         progName);
  922. Usage(progName);
  923. exit(1);
  924.     }
  925.     signOptions.signingTime = PR_TRUE;
  926.     break;
  927. case 'P':
  928.     if (mode != SIGN) {
  929. fprintf(stderr, 
  930.         "%s: option -P only supported with option -S.n", 
  931.         progName);
  932. Usage(progName);
  933. exit(1);
  934.     }
  935.     signOptions.smimeProfile = PR_TRUE;
  936.     break;
  937. case 'h':
  938.     if (mode != DECODE) {
  939. fprintf(stderr, 
  940.         "%s: option -h only supported with option -D.n", 
  941.         progName);
  942. Usage(progName);
  943. exit(1);
  944.     }
  945.     decodeOptions.headerLevel = atoi(optstate->value);
  946.     if (decodeOptions.headerLevel < 0) {
  947. fprintf(stderr, "option -h cannot have a negative value.n");
  948. exit(1);
  949.     }
  950.     break;
  951. case 'p':
  952.     if (!optstate->value) {
  953. fprintf(stderr, "%s: option -p must have a value.n", progName);
  954. Usage(progName);
  955. exit(1);
  956.     }
  957.     options.password = strdup(optstate->value);
  958.     break;
  959. case 'i':
  960.     inFile = PR_Open(optstate->value, PR_RDONLY, 00660);
  961.     if (inFile == NULL) {
  962. fprintf(stderr, "%s: unable to open "%s" for readingn",
  963. progName, optstate->value);
  964. exit(1);
  965.     }
  966.     SECU_FileToItem(&input, inFile);
  967.     PR_Close(inFile);
  968.     break;
  969. case 'c':
  970.     if (mode != DECODE) {
  971. fprintf(stderr, 
  972.         "%s: option -c only supported with option -D.n", 
  973.         progName);
  974. Usage(progName);
  975. exit(1);
  976.     }
  977.     if ((decodeOptions.contentFile = 
  978.           PR_Open(optstate->value, PR_RDONLY, 006600)) == NULL) {
  979. fprintf(stderr, "%s: unable to open "%s" for reading.n",
  980. progName, optstate->value);
  981. exit(1);
  982.     }
  983.     break;
  984. case 'o':
  985. #if 0
  986.     if (mode == DECODE) {
  987. outFile = fopen(optstate->value, "w");
  988.     } else {
  989. outFile = fopen(optstate->value, "wb");
  990.     }
  991. #endif
  992.     outFile = fopen(optstate->value, "wb");
  993.     if (outFile == NULL) {
  994. fprintf(stderr, "%s: unable to open "%s" for writingn",
  995. progName, optstate->value);
  996. exit(1);
  997.     }
  998.     break;
  999. case 'r':
  1000.     if (!optstate->value) {
  1001. fprintf(stderr, "%s: option -r must have a value.n", progName);
  1002. Usage(progName);
  1003. exit(1);
  1004.     }
  1005. #if 0
  1006.     fprintf(stderr, "recipient = %sn", optstate->value);
  1007. #endif
  1008.     envelopeOptions.recipients = ptrarray;
  1009.     str = optstate->value;
  1010.     do {
  1011. tok = strchr(str, ',');
  1012. if (tok) *tok = '';
  1013. envelopeOptions.recipients[nrecipients++] = strdup(str);
  1014. if (tok) str = tok + 1;
  1015.     } while (tok);
  1016.     envelopeOptions.recipients[nrecipients] = NULL;
  1017.     encryptOptions.recipients = envelopeOptions.recipients;
  1018.     certsonlyOptions.recipients = envelopeOptions.recipients;
  1019.     break;
  1020. case 'd':
  1021.     SECU_ConfigDirectory(optstate->value);
  1022.     break;
  1023. case 'e':
  1024.     envFileName = strdup(optstate->value);
  1025.     encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660);
  1026.     break;
  1027. case 'u': {
  1028.     int usageType;
  1029.     usageType = atoi (strdup(optstate->value));
  1030.     if (usageType < certUsageSSLClient || usageType > certUsageAnyCA)
  1031. return -1;
  1032.     options.certUsage = (SECCertUsage)usageType;
  1033.     break;
  1034.   }
  1035.       
  1036. }
  1037.     }
  1038.     /* Call the libsec initialization routines */
  1039.     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
  1040.     rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
  1041.     if (SECSuccess != rv) {
  1042. SECU_PrintError(progName, "NSS_Init failed");
  1043. exit(1);
  1044.     }
  1045.     options.certHandle = CERT_GetDefaultCertDB();
  1046.     if (!options.certHandle) {
  1047. SECU_PrintError(progName, "No default cert DB");
  1048. exit(1);
  1049.     }
  1050. #if defined(WIN32)
  1051.     /*if (outFile == stdout && mode != DECODE) {*/
  1052.     if (outFile == stdout) {
  1053. /* If we're going to write binary data to stdout, we must put stdout
  1054. ** into O_BINARY mode or else outgoing n's will become rn's.
  1055. */
  1056. int smrv = _setmode(_fileno(stdout), _O_BINARY);
  1057. if (smrv == -1) {
  1058.     fprintf(stderr,
  1059.     "%s: Cannot change stdout to binary mode. Use -o option instead.n",
  1060.             progName);
  1061.     return smrv;
  1062. }
  1063.     }
  1064. #endif
  1065.     exitstatus = 0;
  1066.     switch (mode) {
  1067.     case DECODE:
  1068. decodeOptions.options = &options;
  1069. if (encryptOptions.envFile) {
  1070.     /* Decoding encrypted-data, so get the bulkkey from an
  1071.      * enveloped-data message.
  1072.      */
  1073.     SECU_FileToItem(&envmsg, encryptOptions.envFile);
  1074.     decodeOptions.options = &options;
  1075.     encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, 
  1076.                                    decodeOptions);
  1077.     rv = get_enc_params(&encryptOptions);
  1078.     decodeOptions.dkcb = dkcb;
  1079.     decodeOptions.bulkkey = encryptOptions.bulkkey;
  1080. }
  1081. cmsg = decode(outFile, &output, &input, decodeOptions);
  1082. if (!cmsg) {
  1083.     SECU_PrintError(progName, "problem decoding");
  1084.     exitstatus = 1;
  1085. }
  1086. fwrite(output.data, output.len, 1, outFile);
  1087. break;
  1088.     case SIGN:
  1089. signOptions.options = &options;
  1090. cmsg = signed_data(signOptions);
  1091. if (!cmsg) {
  1092.     SECU_PrintError(progName, "problem signing");
  1093.     exitstatus = 1;
  1094. }
  1095. break;
  1096.     case ENCRYPT:
  1097. if (!envFileName) {
  1098.     fprintf(stderr, "%s: you must specify an envelope file with -e.n",
  1099.             progName);
  1100.     exit(1);
  1101. }
  1102. encryptOptions.options = &options;
  1103. encryptOptions.input = &input;
  1104. encryptOptions.outfile = outFile;
  1105. if (!encryptOptions.envFile) {
  1106.     encryptOptions.envFile = PR_Open(envFileName, 
  1107.                                      PR_WRONLY|PR_CREATE_FILE, 00660);
  1108.     if (!encryptOptions.envFile) {
  1109. fprintf(stderr, "%s: failed to create file %s.n", progName,
  1110.         envFileName);
  1111. exit(1);
  1112.     }
  1113. } else {
  1114.     SECU_FileToItem(&envmsg, encryptOptions.envFile);
  1115.     decodeOptions.options = &options;
  1116.     encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, 
  1117.                                    decodeOptions);
  1118. }
  1119. /* decode an enveloped-data message to get the bulkkey (create
  1120.  * a new one if neccessary)
  1121.  */
  1122. rv = get_enc_params(&encryptOptions);
  1123. /* create the encrypted-data message */
  1124. cmsg = encrypted_data(encryptOptions);
  1125. if (!cmsg) {
  1126.     SECU_PrintError(progName, "problem encrypting");
  1127.     exitstatus = 1;
  1128. }
  1129. break;
  1130.     case ENVELOPE:
  1131. envelopeOptions.options = &options;
  1132. #if 0
  1133. if (!envelopeOptions.recipients)
  1134.     parse_message_for_recipients(myIn, &envelopeOptions);
  1135. #endif
  1136. cmsg = enveloped_data(envelopeOptions);
  1137. if (!cmsg) {
  1138.     SECU_PrintError(progName, "problem enveloping");
  1139.     exitstatus = 1;
  1140. }
  1141. break;
  1142.     case CERTSONLY:
  1143. certsonlyOptions.options = &options;
  1144. cmsg = signed_data_certsonly(certsonlyOptions);
  1145. if (!cmsg) {
  1146.     SECU_PrintError(progName, "problem with certs-only");
  1147.     exitstatus = 1;
  1148. }
  1149. break;
  1150.     default:
  1151. fprintf(stderr, "One of options -D, -S or -E must be set.n");
  1152. Usage(progName);
  1153. exitstatus = 1;
  1154.     }
  1155.     if (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY) {
  1156. PLArenaPool *arena = PORT_NewArena(1024);
  1157. NSSCMSEncoderContext *ecx;
  1158. SECItem output = { 0, 0, 0 };
  1159. if (!arena) {
  1160.     fprintf(stderr, "%s: out of memory.n", progName);
  1161.     exit(1);
  1162. }
  1163. pwcb     = (options.password != NULL) ? ownpw                    : NULL;
  1164. pwcb_arg = (options.password != NULL) ? (void *)options.password : NULL;
  1165. ecx = NSS_CMSEncoder_Start(cmsg, 
  1166.                                    NULL, NULL,     /* DER output callback  */
  1167.                                    &output, arena, /* destination storage  */
  1168.                                    pwcb, pwcb_arg, /* password callback    */
  1169.                                    NULL, NULL,     /* decrypt key callback */
  1170.                                    NULL, NULL );   /* detached digests    */
  1171. if (!ecx) {
  1172.     fprintf(stderr, "%s: cannot create encoder context.n", progName);
  1173.     exit(1);
  1174. }
  1175. if (input.len > 0) { /* skip if certs-only (or other zero content) */
  1176.     rv = NSS_CMSEncoder_Update(ecx, input.data, input.len);
  1177.     if (rv) {
  1178. fprintf(stderr, 
  1179.         "%s: failed to add data to encoder.n", progName);
  1180. exit(1);
  1181.     }
  1182. }
  1183. rv = NSS_CMSEncoder_Finish(ecx);
  1184. if (rv) {
  1185.     fprintf(stderr, "%s: failed to encode data.n", progName);
  1186.     exit(1);
  1187. }
  1188. /*PR_Write(output.data, output.len);*/
  1189. fwrite(output.data, output.len, 1, outFile);
  1190. PORT_FreeArena(arena, PR_FALSE);
  1191.     }
  1192.     if (cmsg)
  1193. NSS_CMSMessage_Destroy(cmsg);
  1194.     if (outFile != stdout)
  1195. fclose(outFile);
  1196.     if (decodeOptions.contentFile)
  1197. PR_Close(decodeOptions.contentFile);
  1198.     exit(exitstatus);
  1199. }