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

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.  * PKCS7 encoding.
  35.  *
  36.  * $Id: p7encode.c,v 1.1 2000/03/31 19:16:06 relyea%netscape.com Exp $
  37.  */
  38. #include "p7local.h"
  39. #include "cert.h"
  40. #include "cryptohi.h"
  41. #include "keyhi.h"
  42. #include "secasn1.h"
  43. #include "secoid.h"
  44. #include "secitem.h"
  45. #include "pk11func.h"
  46. #include "secerr.h"
  47. struct sec_pkcs7_encoder_output {
  48.     SEC_PKCS7EncoderOutputCallback outputfn;
  49.     void *outputarg;
  50. };
  51. struct SEC_PKCS7EncoderContextStr {
  52.     SEC_ASN1EncoderContext *ecx;
  53.     SEC_PKCS7ContentInfo *cinfo;
  54.     struct sec_pkcs7_encoder_output output;
  55.     sec_PKCS7CipherObject *encryptobj;
  56.     SECHashObject *digestobj;
  57.     void *digestcx;
  58. };
  59. /*
  60.  * The little output function that the ASN.1 encoder calls to hand
  61.  * us bytes which we in turn hand back to our caller (via the callback
  62.  * they gave us).
  63.  */
  64. static void
  65. sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len,
  66.       int depth, SEC_ASN1EncodingPart data_kind)
  67. {
  68.     struct sec_pkcs7_encoder_output *output;
  69.     output = (struct sec_pkcs7_encoder_output*)arg;
  70.     output->outputfn (output->outputarg, buf, len);
  71. }
  72. static sec_PKCS7CipherObject *
  73. sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo,
  74.  PK11SymKey *orig_bulkkey)
  75. {
  76.     SECOidTag kind;
  77.     sec_PKCS7CipherObject *encryptobj;
  78.     SEC_PKCS7RecipientInfo **recipientinfos, *ri;
  79.     SEC_PKCS7EncryptedContentInfo *enccinfo;
  80.     SEC_PKCS7SMIMEKEAParameters   keaParams;
  81.     SECKEYPublicKey *publickey = NULL;
  82.     SECKEYPrivateKey *ourPrivKey = NULL;
  83.     PK11SymKey  *bulkkey;
  84.     void *mark, *wincx;
  85.     int i;
  86.     PRArenaPool *arena = NULL;
  87.     unsigned char zero = 0;
  88.     /* Get the context in case we need it below. */
  89.     wincx = cinfo->pwfn_arg;
  90.     /* Clear keaParams, since cleanup code checks the lengths */
  91.     (void) memset(&keaParams, 0, sizeof(keaParams));
  92.     kind = SEC_PKCS7ContentType (cinfo);
  93.     switch (kind) {
  94.       default:
  95.       case SEC_OID_PKCS7_DATA:
  96.       case SEC_OID_PKCS7_DIGESTED_DATA:
  97.       case SEC_OID_PKCS7_SIGNED_DATA:
  98. recipientinfos = NULL;
  99. enccinfo = NULL;
  100. break;
  101.       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  102. {
  103.     SEC_PKCS7EncryptedData *encdp;
  104.     /* To do EncryptedData we *must* be given a bulk key. */
  105.     PORT_Assert (orig_bulkkey != NULL);
  106.     if (orig_bulkkey == NULL) {
  107. /* XXX error? */
  108. return NULL;
  109.     }
  110.     encdp = cinfo->content.encryptedData;
  111.     recipientinfos = NULL;
  112.     enccinfo = &(encdp->encContentInfo);
  113. }
  114. break;
  115.       case SEC_OID_PKCS7_ENVELOPED_DATA:
  116. {
  117.     SEC_PKCS7EnvelopedData *envdp;
  118.     envdp = cinfo->content.envelopedData;
  119.     recipientinfos = envdp->recipientInfos;
  120.     enccinfo = &(envdp->encContentInfo);
  121. }
  122. break;
  123.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  124. {
  125.     SEC_PKCS7SignedAndEnvelopedData *saedp;
  126.     saedp = cinfo->content.signedAndEnvelopedData;
  127.     recipientinfos = saedp->recipientInfos;
  128.     enccinfo = &(saedp->encContentInfo);
  129. }
  130. break;
  131.     }
  132.     if (enccinfo == NULL)
  133. return NULL;
  134.     bulkkey = orig_bulkkey;
  135.     if (bulkkey == NULL) {
  136. CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
  137. PK11SlotInfo *slot;
  138. slot = PK11_GetBestSlot(type,cinfo->pwfn_arg);
  139. if (slot == NULL) {
  140.     return NULL;
  141. }
  142. bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8,
  143.       cinfo->pwfn_arg);
  144. PK11_FreeSlot(slot);
  145. if (bulkkey == NULL) {
  146.     return NULL;
  147. }
  148.     }
  149.     encryptobj = NULL;
  150.     mark = PORT_ArenaMark (cinfo->poolp);
  151.     /*
  152.      * Encrypt the bulk key with the public key of each recipient.
  153.      */
  154.     for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
  155. CERTCertificate *cert;
  156. SECOidTag certalgtag, encalgtag;
  157. SECStatus rv;
  158. int data_len;
  159. SECItem *params = NULL;
  160. cert = ri->cert;
  161. PORT_Assert (cert != NULL);
  162. if (cert == NULL)
  163.     continue;
  164. /*
  165.  * XXX Want an interface that takes a cert and some data and
  166.  * fills in an algorithmID and encrypts the data with the public
  167.  * key from the cert.  Or, give me two interfaces -- one which
  168.  * gets the algorithm tag from a cert (I should not have to go
  169.  * down into the subjectPublicKeyInfo myself) and another which
  170.  * takes a public key and algorithm tag and data and encrypts
  171.  * the data.  Or something like that.  The point is that all
  172.  * of the following hardwired RSA and KEA stuff should be done
  173.  * elsewhere.
  174.  */
  175. certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
  176. switch (certalgtag) {
  177. case SEC_OID_PKCS1_RSA_ENCRYPTION:
  178.     encalgtag = certalgtag;
  179.     publickey = CERT_ExtractPublicKey (cert);
  180.     if (publickey == NULL) goto loser;
  181.     data_len = SECKEY_PublicKeyStrength(publickey);
  182.     ri->encKey.data = 
  183.         (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len);
  184.     ri->encKey.len = data_len;
  185.     if (ri->encKey.data == NULL) goto loser;
  186.     rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey,
  187. bulkkey,&ri->encKey);
  188.     SECKEY_DestroyPublicKey(publickey);
  189.     publickey = NULL;
  190.     if (rv != SECSuccess) goto loser;
  191.     params = NULL; /* paranoia */
  192.     break;
  193. /* ### mwelch -- KEA */ 
  194.       case SEC_OID_MISSI_KEA_DSS_OLD:
  195.       case SEC_OID_MISSI_KEA_DSS:
  196.       case SEC_OID_MISSI_KEA:
  197.     {
  198. #define SMIME_FORTEZZA_RA_LENGTH 128
  199. #define SMIME_FORTEZZA_IV_LENGTH 24
  200. #define SMIME_FORTEZZA_MAX_KEY_SIZE 256
  201. SECStatus err;
  202. PK11SymKey *tek;
  203. CERTCertificate *ourCert;
  204. SECKEYPublicKey *ourPubKey;
  205. SECKEATemplateSelector whichKEA;
  206. /* We really want to show our KEA tag as the
  207.    key exchange algorithm tag. */
  208. encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
  209. /* Get the public key of the recipient. */
  210. publickey = CERT_ExtractPublicKey(cert);
  211. if (publickey == NULL) goto loser;
  212. /* Find our own cert, and extract its keys. */
  213. ourCert = PK11_FindBestKEAMatch(cert,wincx);
  214. if (ourCert == NULL) goto loser;
  215. arena = PORT_NewArena(1024);
  216. if (arena == NULL) goto loser;
  217. ourPubKey = CERT_ExtractPublicKey(ourCert);
  218. if (ourPubKey == NULL)
  219. {
  220.     CERT_DestroyCertificate(ourCert);
  221.     goto loser;
  222. }
  223. /* While we're here, copy the public key into the outgoing
  224.  * KEA parameters. */
  225. SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey),
  226.  &(ourPubKey->u.fortezza.KEAKey));
  227. SECKEY_DestroyPublicKey(ourPubKey);
  228. ourPubKey = NULL;
  229. /* Extract our private key in order to derive the 
  230.  * KEA key. */
  231. ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
  232. CERT_DestroyCertificate(ourCert); /* we're done with this */
  233. if (!ourPrivKey) goto loser;
  234. /* Prepare raItem with 128 bytes (filled with zeros). */
  235. keaParams.originatorRA.data = 
  236.   (unsigned char*)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
  237. keaParams.originatorRA.len = SMIME_FORTEZZA_RA_LENGTH;
  238. /* Generate the TEK (token exchange key) which we use
  239.  * to wrap the bulk encryption key. (raItem) will be
  240.  * filled with a random seed which we need to send to
  241.  * the recipient. */
  242. tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
  243.      &keaParams.originatorRA, NULL,
  244.      CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
  245.      CKA_WRAP, 0, wincx);
  246.     SECKEY_DestroyPublicKey(publickey);
  247.     SECKEY_DestroyPrivateKey(ourPrivKey);
  248.     publickey = NULL;
  249.     ourPrivKey = NULL;
  250. if (!tek)
  251.     goto loser;
  252. ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp,
  253.   SMIME_FORTEZZA_MAX_KEY_SIZE);
  254. ri->encKey.len = SMIME_FORTEZZA_MAX_KEY_SIZE;
  255. if (ri->encKey.data == NULL)
  256. {
  257.     PK11_FreeSymKey(tek);
  258.     goto loser;
  259. }
  260. /* Wrap the bulk key. What we do with the resulting data
  261.    depends on whether we're using Skipjack to wrap the key. */
  262. switch(PK11_AlgtagToMechanism(enccinfo->encalg))
  263. {
  264. case CKM_SKIPJACK_CBC64:
  265. case CKM_SKIPJACK_ECB64:
  266. case CKM_SKIPJACK_OFB64:
  267. case CKM_SKIPJACK_CFB64:
  268. case CKM_SKIPJACK_CFB32:
  269. case CKM_SKIPJACK_CFB16:
  270. case CKM_SKIPJACK_CFB8:
  271.     /* do SKIPJACK, we use the wrap mechanism */
  272.     err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, 
  273.       tek, bulkkey, &ri->encKey);
  274.     whichKEA = SECKEAUsesSkipjack;
  275.     break;
  276. default:
  277.     /* Not SKIPJACK, we encrypt the raw key data */
  278.     keaParams.nonSkipjackIV .data = 
  279.       (unsigned char*)PORT_ArenaAlloc(arena,
  280.      SMIME_FORTEZZA_IV_LENGTH);
  281.     keaParams.nonSkipjackIV.len = SMIME_FORTEZZA_IV_LENGTH;
  282.     err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64,
  283.   &keaParams.nonSkipjackIV, 
  284.           tek, bulkkey, &ri->encKey);
  285.     if (err != SECSuccess)
  286. goto loser;
  287.     if (ri->encKey.len != PK11_GetKeyLength(bulkkey))
  288.     {
  289. /* The size of the encrypted key is not the same as
  290.    that of the original bulk key, presumably due to
  291.    padding. Encode and store the real size of the
  292.    bulk key. */
  293. if (SEC_ASN1EncodeInteger(arena, 
  294.   &keaParams.bulkKeySize,
  295.   PK11_GetKeyLength(bulkkey))
  296.     == NULL)
  297.     err = (SECStatus)PORT_GetError();
  298. else
  299.     /* use full template for encoding */
  300.     whichKEA = SECKEAUsesNonSkipjackWithPaddedEncKey;
  301.     }
  302.     else
  303. /* enc key length == bulk key length */
  304. whichKEA = SECKEAUsesNonSkipjack; 
  305.     break;
  306. }
  307. PK11_FreeSymKey(tek);
  308. if (err != SECSuccess)
  309.     goto loser;
  310. /* Encode the KEA parameters into the recipient info. */
  311. params = SEC_ASN1EncodeItem(arena,NULL, &keaParams, 
  312.       sec_pkcs7_get_kea_template(whichKEA));
  313. if (params == NULL) goto loser;
  314. break;
  315.     }
  316. default:
  317.     PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
  318.     goto loser;
  319. }
  320. rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, 
  321. params);
  322. if (rv != SECSuccess)
  323.     goto loser;
  324. if (arena) PORT_FreeArena(arena,PR_FALSE);
  325. arena = NULL;
  326.     }
  327.     encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey,
  328.        enccinfo->encalg,
  329.        &(enccinfo->contentEncAlg));
  330.     if (encryptobj != NULL) {
  331. PORT_ArenaUnmark (cinfo->poolp, mark);
  332. mark = NULL; /* good one; do not want to release */
  333.     }
  334.     /* fallthru */
  335. loser:
  336.     if (arena) {
  337. PORT_FreeArena(arena, PR_FALSE);
  338.     }
  339.     if (publickey) {
  340.         SECKEY_DestroyPublicKey(publickey);
  341.     }
  342.     if (ourPrivKey) {
  343.         SECKEY_DestroyPrivateKey(ourPrivKey);
  344.     }
  345.     if (mark != NULL) {
  346. PORT_ArenaRelease (cinfo->poolp, mark);
  347.     }
  348.     if (orig_bulkkey == NULL) {
  349. if (bulkkey) PK11_FreeSymKey(bulkkey);
  350.     }
  351.     return encryptobj;
  352. }
  353. static void
  354. sec_pkcs7_encoder_notify (void *arg, PRBool before, void *dest, int depth)
  355. {
  356.     SEC_PKCS7EncoderContext *p7ecx;
  357.     SEC_PKCS7ContentInfo *cinfo;
  358.     SECOidTag kind;
  359.     PRBool before_content;
  360.     /*
  361.      * We want to notice just before the content field.  After fields are
  362.      * not interesting to us.
  363.      */
  364.     if (!before)
  365. return;
  366.     p7ecx = (SEC_PKCS7EncoderContext*)arg;
  367.     cinfo = p7ecx->cinfo;
  368.     before_content = PR_FALSE;
  369.     /*
  370.      * Watch for the content field, at which point we want to instruct
  371.      * the ASN.1 encoder to start taking bytes from the buffer.
  372.      *
  373.      * XXX The following assumes the inner content type is data;
  374.      * if/when we want to handle fully nested types, this will have
  375.      * to recurse until reaching the innermost data content.
  376.      */
  377.     kind = SEC_PKCS7ContentType (cinfo);
  378.     switch (kind) {
  379.       default:
  380.       case SEC_OID_PKCS7_DATA:
  381. if (dest == &(cinfo->content.data))
  382.     before_content = PR_TRUE;
  383. break;
  384.       case SEC_OID_PKCS7_DIGESTED_DATA:
  385. {
  386.     SEC_PKCS7DigestedData *digd;
  387.     digd = cinfo->content.digestedData;
  388.     if (digd == NULL)
  389. break;
  390.     if (dest == &(digd->contentInfo.content))
  391. before_content = PR_TRUE;
  392. }
  393. break;
  394.       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  395. {
  396.     SEC_PKCS7EncryptedData *encd;
  397.     encd = cinfo->content.encryptedData;
  398.     if (encd == NULL)
  399. break;
  400.     if (dest == &(encd->encContentInfo.encContent))
  401. before_content = PR_TRUE;
  402. }
  403. break;
  404.       case SEC_OID_PKCS7_ENVELOPED_DATA:
  405. {
  406.     SEC_PKCS7EnvelopedData *envd;
  407.     envd = cinfo->content.envelopedData;
  408.     if (envd == NULL)
  409. break;
  410.     if (dest == &(envd->encContentInfo.encContent))
  411. before_content = PR_TRUE;
  412. }
  413. break;
  414.       case SEC_OID_PKCS7_SIGNED_DATA:
  415. {
  416.     SEC_PKCS7SignedData *sigd;
  417.     sigd = cinfo->content.signedData;
  418.     if (sigd == NULL)
  419. break;
  420.     if (dest == &(sigd->contentInfo.content))
  421. before_content = PR_TRUE;
  422. }
  423. break;
  424.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  425. {
  426.     SEC_PKCS7SignedAndEnvelopedData *saed;
  427.     saed = cinfo->content.signedAndEnvelopedData;
  428.     if (saed == NULL)
  429. break;
  430.     if (dest == &(saed->encContentInfo.encContent))
  431. before_content = PR_TRUE;
  432. }
  433. break;
  434.     }
  435.     if (before_content) {
  436. /*
  437.  * This will cause the next SEC_ASN1EncoderUpdate to take the
  438.  * contents bytes from the passed-in buffer.
  439.  */
  440. SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx);
  441. /*
  442.  * And that is all we needed this notify function for.
  443.  */
  444. SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx);
  445.     }
  446. }
  447. static SEC_PKCS7EncoderContext *
  448. sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo,
  449.   PK11SymKey *bulkkey)
  450. {
  451.     SEC_PKCS7EncoderContext *p7ecx;
  452.     SECOidTag kind;
  453.     PRBool encrypt;
  454.     SECItem **digests;
  455.     SECAlgorithmID *digestalg, **digestalgs;
  456.     p7ecx = 
  457.       (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext));
  458.     if (p7ecx == NULL)
  459. return NULL;
  460.     digests = NULL;
  461.     digestalg = NULL;
  462.     digestalgs = NULL;
  463.     encrypt = PR_FALSE;
  464.     kind = SEC_PKCS7ContentType (cinfo);
  465.     switch (kind) {
  466.       default:
  467.       case SEC_OID_PKCS7_DATA:
  468. break;
  469.       case SEC_OID_PKCS7_DIGESTED_DATA:
  470. digestalg = &(cinfo->content.digestedData->digestAlg);
  471. break;
  472.       case SEC_OID_PKCS7_SIGNED_DATA:
  473. digests = cinfo->content.signedData->digests;
  474. digestalgs = cinfo->content.signedData->digestAlgorithms;
  475. break;
  476.       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  477.       case SEC_OID_PKCS7_ENVELOPED_DATA:
  478. encrypt = PR_TRUE;
  479. break;
  480.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  481. digests = cinfo->content.signedAndEnvelopedData->digests;
  482. digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
  483. encrypt = PR_TRUE;
  484. break;
  485.     }
  486.     if (encrypt) {
  487. p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey);
  488. if (p7ecx->encryptobj == NULL) {
  489.     PORT_Free (p7ecx);
  490.     return NULL;
  491. }
  492.     }
  493.     if (digestalgs != NULL) {
  494. if (digests != NULL) {
  495.     /* digests already created (probably for detached data) */
  496.     digestalg = NULL;
  497. } else {
  498.     /*
  499.      * XXX Some day we should handle multiple digests; for now,
  500.      * assume only one will be done.
  501.      */
  502.     PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL);
  503.     digestalg = digestalgs[0];
  504. }
  505.     }
  506.     if (digestalg != NULL) {
  507. SECOidData *oiddata;
  508. oiddata = SECOID_FindOID (&(digestalg->algorithm));
  509. if (oiddata != NULL) {
  510.     switch (oiddata->offset) {
  511.       case SEC_OID_MD2:
  512. p7ecx->digestobj = &SECHashObjects[HASH_AlgMD2];
  513. break;
  514.       case SEC_OID_MD5:
  515. p7ecx->digestobj = &SECHashObjects[HASH_AlgMD5];
  516. break;
  517.       case SEC_OID_SHA1:
  518. p7ecx->digestobj = &SECHashObjects[HASH_AlgSHA1];
  519. break;
  520.       default:
  521. /* XXX right error? */
  522. PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
  523. break;
  524.     }
  525. }
  526. if (p7ecx->digestobj != NULL) {
  527.     p7ecx->digestcx = (* p7ecx->digestobj->create) ();
  528.     if (p7ecx->digestcx == NULL)
  529. p7ecx->digestobj = NULL;
  530.     else
  531. (* p7ecx->digestobj->begin) (p7ecx->digestcx);
  532. }
  533. if (p7ecx->digestobj == NULL) {
  534.     if (p7ecx->encryptobj != NULL)
  535. sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
  536.     PORT_Free (p7ecx);
  537.     return NULL;
  538. }
  539.     }
  540.     p7ecx->cinfo = cinfo;
  541.     return p7ecx;
  542. }
  543. SEC_PKCS7EncoderContext *
  544. SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo,
  545.        SEC_PKCS7EncoderOutputCallback outputfn,
  546.        void *outputarg,
  547.        PK11SymKey *bulkkey)
  548. {
  549.     SEC_PKCS7EncoderContext *p7ecx;
  550.     SECStatus rv;
  551.     p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
  552.     if (p7ecx == NULL)
  553. return NULL;
  554.     p7ecx->output.outputfn = outputfn;
  555.     p7ecx->output.outputarg = outputarg;
  556.     /*
  557.      * Initialize the BER encoder.
  558.      */
  559.     p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate,
  560.        sec_pkcs7_encoder_out, &(p7ecx->output));
  561.     if (p7ecx->ecx == NULL) {
  562. PORT_Free (p7ecx);
  563. return NULL;
  564.     }
  565.     /*
  566.      * Indicate that we are streaming.  We will be streaming until we
  567.      * get past the contents bytes.
  568.      */
  569.     SEC_ASN1EncoderSetStreaming (p7ecx->ecx);
  570.     /*
  571.      * The notify function will watch for the contents field.
  572.      */
  573.     SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);
  574.     /*
  575.      * This will encode everything up to the content bytes.  (The notify
  576.      * function will then cause the encoding to stop there.)  Then our
  577.      * caller can start passing contents bytes to our Update, which we
  578.      * will pass along.
  579.      */
  580.     rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
  581.     if (rv != SECSuccess) {
  582. PORT_Free (p7ecx);
  583. return NULL;
  584.     }
  585.     return p7ecx;
  586. }
  587. /*
  588.  * XXX If/when we support nested contents, this needs to be revised.
  589.  */
  590. static SECStatus
  591. sec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest,
  592.      const unsigned char *data, unsigned long len,
  593.      PRBool final)
  594. {
  595.     unsigned char *buf = NULL;
  596.     SECStatus rv;
  597.     rv = SECSuccess; /* may as well be optimistic */
  598.     /*
  599.      * We should really have data to process, or we should be trying
  600.      * to finish/flush the last block.  (This is an overly paranoid
  601.      * check since all callers are in this file and simple inspection
  602.      * proves they do it right.  But it could find a bug in future
  603.      * modifications/development, that is why it is here.)
  604.      */
  605.     PORT_Assert ((data != NULL && len) || final);
  606.     /*
  607.      * Update the running digest.
  608.      * XXX This needs modification if/when we handle multiple digests.
  609.      */
  610.     if (len && p7ecx->digestobj != NULL) {
  611. (* p7ecx->digestobj->update) (p7ecx->digestcx, data, len);
  612.     }
  613.     /*
  614.      * Encrypt this chunk.
  615.      */
  616.     if (p7ecx->encryptobj != NULL) {
  617. /* XXX the following lengths should all be longs? */
  618. unsigned int inlen; /* length of data being encrypted */
  619. unsigned int outlen; /* length of encrypted data */
  620. unsigned int buflen; /* length available for encrypted data */
  621. inlen = len;
  622. buflen = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final);
  623. if (buflen == 0) {
  624.     /*
  625.      * No output is expected, but the input data may be buffered
  626.      * so we still have to call Encrypt.
  627.      */
  628.     rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0,
  629.    data, inlen, final);
  630.     if (final) {
  631. len = 0;
  632. goto done;
  633.     }
  634.     return rv;
  635. }
  636. if (dest != NULL)
  637.     buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen);
  638. else
  639.     buf = (unsigned char*)PORT_Alloc (buflen);
  640. if (buf == NULL) {
  641.     rv = SECFailure;
  642. } else {
  643.     rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen,
  644.    data, inlen, final);
  645.     data = buf;
  646.     len = outlen;
  647. }
  648. if (rv != SECSuccess) {
  649.     if (final)
  650. goto done;
  651.     return rv;
  652. }
  653.     }
  654.     if (p7ecx->ecx != NULL) {
  655. /*
  656.  * Encode the contents bytes.
  657.  */
  658. if(len) {
  659.     rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len);
  660. }
  661.     }
  662. done:
  663.     if (p7ecx->encryptobj != NULL) {
  664. if (final)
  665.     sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
  666. if (dest != NULL) {
  667.     dest->data = buf;
  668.     dest->len = len;
  669. } else if (buf != NULL) {
  670.     PORT_Free (buf);
  671. }
  672.     }
  673.     if (final && p7ecx->digestobj != NULL) {
  674. SECItem *digest, **digests, ***digestsp;
  675. unsigned char *digdata;
  676. SECOidTag kind;
  677. kind = SEC_PKCS7ContentType (p7ecx->cinfo);
  678. switch (kind) {
  679.   default:
  680.     PORT_Assert (0);
  681.     return SECFailure;
  682.   case SEC_OID_PKCS7_DIGESTED_DATA:
  683.     digest = &(p7ecx->cinfo->content.digestedData->digest);
  684.     digestsp = NULL;
  685.     break;
  686.   case SEC_OID_PKCS7_SIGNED_DATA:
  687.     digest = NULL;
  688.     digestsp = &(p7ecx->cinfo->content.signedData->digests);
  689.     break;
  690.   case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  691.     digest = NULL;
  692.     digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
  693.     break;
  694. }
  695. digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
  696.    p7ecx->digestobj->length);
  697. if (digdata == NULL)
  698.     return SECFailure;
  699. if (digestsp != NULL) {
  700.     PORT_Assert (digest == NULL);
  701.     digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, 
  702. sizeof(SECItem));
  703.     digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
  704.        2 * sizeof(SECItem *));
  705.     if (digests == NULL || digest == NULL)
  706. return SECFailure;
  707.     digests[0] = digest;
  708.     digests[1] = NULL;
  709.     *digestsp = digests;
  710. }
  711. PORT_Assert (digest != NULL);
  712. digest->data = digdata;
  713. digest->len = p7ecx->digestobj->length;
  714. (* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data,
  715.    &(digest->len), digest->len);
  716. (* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE);
  717.     }
  718.     return rv;
  719. }
  720. SECStatus
  721. SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx,
  722. const char *data, unsigned long len)
  723. {
  724.     /* XXX Error handling needs help.  Return what?  Do "Finish" on failure? */
  725.     return sec_pkcs7_encoder_work_data (p7ecx, NULL,
  726. (const unsigned char *)data, len,
  727. PR_FALSE);
  728. }
  729. /*
  730.  * XXX I would *really* like to not have to do this, but the current
  731.  * signing interface gives me little choice.
  732.  */
  733. static SECOidTag
  734. sec_pkcs7_pick_sign_alg (SECOidTag hashalg, SECOidTag encalg)
  735. {
  736.     switch (encalg) {
  737.       case SEC_OID_PKCS1_RSA_ENCRYPTION:
  738. switch (hashalg) {
  739.   case SEC_OID_MD2:
  740.     return SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
  741.   case SEC_OID_MD5:
  742.     return SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
  743.   case SEC_OID_SHA1:
  744.     return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
  745.   default:
  746.     return SEC_OID_UNKNOWN;
  747. }
  748.       case SEC_OID_ANSIX9_DSA_SIGNATURE:
  749.       case SEC_OID_MISSI_KEA_DSS:
  750.       case SEC_OID_MISSI_DSS:
  751. switch (hashalg) {
  752.   case SEC_OID_SHA1:
  753.     return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
  754.   default:
  755.     return SEC_OID_UNKNOWN;
  756. }
  757.       default:
  758. break;
  759.     }
  760.     return encalg; /* maybe it is already the right algid */
  761. }
  762. static SECStatus
  763. sec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo,
  764.  SECKEYGetPasswordKey pwfn, void *pwfnarg)
  765. {
  766.     SECOidTag kind;
  767.     CERTCertificate **certs;
  768.     CERTCertificateList **certlists;
  769.     SECAlgorithmID **digestalgs;
  770.     SECItem **digests;
  771.     SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
  772.     SECItem **rawcerts, ***rawcertsp;
  773.     PRArenaPool *poolp;
  774.     int certcount;
  775.     int ci, cli, rci, si;
  776.     kind = SEC_PKCS7ContentType (cinfo);
  777.     switch (kind) {
  778.       default:
  779.       case SEC_OID_PKCS7_DATA:
  780.       case SEC_OID_PKCS7_DIGESTED_DATA:
  781.       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  782.       case SEC_OID_PKCS7_ENVELOPED_DATA:
  783. certs = NULL;
  784. certlists = NULL;
  785. digestalgs = NULL;
  786. digests = NULL;
  787. signerinfos = NULL;
  788. rawcertsp = NULL;
  789. break;
  790.       case SEC_OID_PKCS7_SIGNED_DATA:
  791. {
  792.     SEC_PKCS7SignedData *sdp;
  793.     sdp = cinfo->content.signedData;
  794.     certs = sdp->certs;
  795.     certlists = sdp->certLists;
  796.     digestalgs = sdp->digestAlgorithms;
  797.     digests = sdp->digests;
  798.     signerinfos = sdp->signerInfos;
  799.     rawcertsp = &(sdp->rawCerts);
  800. }
  801. break;
  802.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  803. {
  804.     SEC_PKCS7SignedAndEnvelopedData *saedp;
  805.     saedp = cinfo->content.signedAndEnvelopedData;
  806.     certs = saedp->certs;
  807.     certlists = saedp->certLists;
  808.     digestalgs = saedp->digestAlgorithms;
  809.     digests = saedp->digests;
  810.     signerinfos = saedp->signerInfos;
  811.     rawcertsp = &(saedp->rawCerts);
  812. }
  813. break;
  814.     }
  815.     if (certs == NULL && certlists == NULL && signerinfos == NULL)
  816. return SECSuccess; /* nothing for us to do! */
  817.     poolp = cinfo->poolp;
  818.     certcount = 0;
  819.     if (signerinfos != NULL) {
  820. SECOidTag digestalgtag;
  821. int di;
  822. SECStatus rv;
  823. CERTCertificate *cert;
  824. SECKEYPrivateKey *privkey;
  825. SECItem signature;
  826. SECOidTag signalgtag;
  827. PORT_Assert (digestalgs != NULL && digests != NULL);
  828. /*
  829.  * If one fails, we bail right then.  If we want to continue and
  830.  * try to do subsequent signatures, this loop, and the departures
  831.  * from it, will need to be reworked.
  832.  */
  833. for (si = 0; signerinfos[si] != NULL; si++) {
  834.     signerinfo = signerinfos[si];
  835.     /* find right digest */
  836.     digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg));
  837.     for (di = 0; digestalgs[di] != NULL; di++) {
  838. /* XXX Should I be comparing more than the tag? */
  839. if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di]))
  840.     break;
  841.     }
  842.     if (digestalgs[di] == NULL) {
  843. /* XXX oops; do what? set an error? */
  844. return SECFailure;
  845.     }
  846.     PORT_Assert (digests[di] != NULL);
  847.     cert = signerinfo->cert;
  848.     privkey = PK11_FindKeyByAnyCert (cert, pwfnarg);
  849.     if (privkey == NULL)
  850. return SECFailure;
  851.     /*
  852.      * XXX I think there should be a cert-level interface for this,
  853.      * so that I do not have to know about subjectPublicKeyInfo...
  854.      */
  855.     signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.algorithm));
  856.     /* Fortezza MISSI have weird signature formats.  Map them
  857.      * to standard DSA formats */
  858.     signalgtag = PK11_FortezzaMapSig(signalgtag);
  859.     if (signerinfo->authAttr != NULL) {
  860. SEC_PKCS7Attribute *attr;
  861. SECItem encoded_attrs;
  862. SECItem *dummy;
  863. /*
  864.  * First, find and fill in the message digest attribute.
  865.  */
  866. attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
  867.        SEC_OID_PKCS9_MESSAGE_DIGEST,
  868.        PR_TRUE);
  869. PORT_Assert (attr != NULL);
  870. if (attr == NULL) {
  871.     SECKEY_DestroyPrivateKey (privkey);
  872.     return SECFailure;
  873. }
  874. /*
  875.  * XXX The second half of the following assertion prevents
  876.  * the encoder from being called twice on the same content.
  877.  * Either just remove the second half the assertion, or
  878.  * change the code to check if the value already there is
  879.  * the same as digests[di], whichever seems more right.
  880.  */
  881. PORT_Assert (attr->values != NULL && attr->values[0] == NULL);
  882. attr->values[0] = digests[di];
  883. /*
  884.  * Before encoding, reorder the attributes so that when they
  885.  * are encoded, they will be conforming DER, which is required
  886.  * to have a specific order and that is what must be used for
  887.  * the hash/signature.  We do this here, rather than building
  888.  * it into EncodeAttributes, because we do not want to do
  889.  * such reordering on incoming messages (which also uses
  890.  * EncodeAttributes) or our old signatures (and other "broken"
  891.  * implementations) will not verify.  So, we want to guarantee
  892.  * that we send out good DER encodings of attributes, but not
  893.  * to expect to receive them.
  894.  */
  895. rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr);
  896. if (rv != SECSuccess) {
  897.     SECKEY_DestroyPrivateKey (privkey);
  898.     return SECFailure;
  899. }
  900. encoded_attrs.data = NULL;
  901. encoded_attrs.len = 0;
  902. dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
  903.    &(signerinfo->authAttr));
  904. if (dummy == NULL) {
  905.     SECKEY_DestroyPrivateKey (privkey);
  906.     return SECFailure;
  907. }
  908. rv = SEC_SignData (&signature,
  909.    encoded_attrs.data, encoded_attrs.len,
  910.    privkey,
  911.    sec_pkcs7_pick_sign_alg (digestalgtag,
  912.     signalgtag));
  913. SECITEM_FreeItem (&encoded_attrs, PR_FALSE);
  914.     } else {
  915. rv = SGN_Digest (privkey, digestalgtag, &signature,
  916.  digests[di]);
  917.     }
  918.     SECKEY_DestroyPrivateKey (privkey);
  919.     if (rv != SECSuccess)
  920. return rv;
  921.     rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature);
  922.     if (rv != SECSuccess)
  923. return rv;
  924.     SECITEM_FreeItem (&signature, PR_FALSE);
  925.     rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg),
  926. signalgtag, NULL);
  927.     if (rv != SECSuccess)
  928. return SECFailure;
  929.     /*
  930.      * Count the cert chain for this signer.
  931.      */
  932.     if (signerinfo->certList != NULL)
  933. certcount += signerinfo->certList->len;
  934. }
  935.     }
  936.     if (certs != NULL) {
  937. for (ci = 0; certs[ci] != NULL; ci++)
  938.     certcount++;
  939.     }
  940.     if (certlists != NULL) {
  941. for (cli = 0; certlists[cli] != NULL; cli++)
  942.     certcount += certlists[cli]->len;
  943.     }
  944.     if (certcount == 0)
  945. return SECSuccess; /* signing done; no certs */
  946.     /*
  947.      * Combine all of the certs and cert chains into rawcerts.
  948.      * Note: certcount is an upper bound; we may not need that many slots
  949.      * but we will allocate anyway to avoid having to do another pass.
  950.      * (The temporary space saving is not worth it.)
  951.      */
  952.     rawcerts = (SECItem**)PORT_ArenaAlloc (poolp, 
  953. (certcount + 1) * sizeof(SECItem *));
  954.     if (rawcerts == NULL)
  955. return SECFailure;
  956.     /*
  957.      * XXX Want to check for duplicates and not add *any* cert that is
  958.      * already in the set.  This will be more important when we start
  959.      * dealing with larger sets of certs, dual-key certs (signing and
  960.      * encryption), etc.  For the time being we can slide by...
  961.      */
  962.     rci = 0;
  963.     if (signerinfos != NULL) {
  964. for (si = 0; signerinfos[si] != NULL; si++) {
  965.     signerinfo = signerinfos[si];
  966.     for (ci = 0; ci < signerinfo->certList->len; ci++)
  967. rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
  968. }
  969.     }
  970.     if (certs != NULL) {
  971. for (ci = 0; certs[ci] != NULL; ci++)
  972.     rawcerts[rci++] = &(certs[ci]->derCert);
  973.     }
  974.     if (certlists != NULL) {
  975. for (cli = 0; certlists[cli] != NULL; cli++) {
  976.     for (ci = 0; ci < certlists[cli]->len; ci++)
  977. rawcerts[rci++] = &(certlists[cli]->certs[ci]);
  978. }
  979.     }
  980.     rawcerts[rci] = NULL;
  981.     *rawcertsp = rawcerts;
  982.     return SECSuccess;
  983. }
  984. SECStatus
  985. SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,
  986. SECKEYGetPasswordKey pwfn, void *pwfnarg)
  987. {
  988.     SECStatus rv;
  989.     /*
  990.      * Flush out any remaining data.
  991.      */
  992.     rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE);
  993.     /*
  994.      * Turn off streaming stuff.
  995.      */
  996.     SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx);
  997.     SEC_ASN1EncoderClearStreaming (p7ecx->ecx);
  998.     if (rv != SECSuccess)
  999. goto loser;
  1000.     rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg);
  1001.     if (rv != SECSuccess)
  1002. goto loser;
  1003.     rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
  1004. loser:
  1005.     SEC_ASN1EncoderFinish (p7ecx->ecx);
  1006.     PORT_Free (p7ecx);
  1007.     return rv;
  1008. }
  1009. /*
  1010.  * After this routine is called, the entire PKCS7 contentInfo is ready
  1011.  * to be encoded.  This is used internally, but can also be called from
  1012.  * elsewhere for those who want to be able to just have pointers to
  1013.  * the ASN1 template for pkcs7 contentInfo built into their own encodings.
  1014.  */
  1015. SECStatus
  1016. SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,
  1017.    PK11SymKey *bulkkey,
  1018.    SECKEYGetPasswordKey pwfn,
  1019.    void *pwfnarg)
  1020. {
  1021.     SEC_PKCS7EncoderContext *p7ecx;
  1022.     SECItem *content, *enc_content;
  1023.     SECStatus rv;
  1024.     p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
  1025.     if (p7ecx == NULL)
  1026. return SECFailure;
  1027.     content = SEC_PKCS7GetContent (cinfo);
  1028.     if (p7ecx->encryptobj != NULL) {
  1029. SECOidTag kind;
  1030. SEC_PKCS7EncryptedContentInfo *enccinfo;
  1031. kind = SEC_PKCS7ContentType (p7ecx->cinfo);
  1032. switch (kind) {
  1033.   default:
  1034.     PORT_Assert (0);
  1035.     rv = SECFailure;
  1036.     goto loser;
  1037.   case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1038.     enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
  1039.     break;
  1040.   case SEC_OID_PKCS7_ENVELOPED_DATA:
  1041.     enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
  1042.     break;
  1043.   case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  1044.     enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);
  1045.     break;
  1046. }
  1047. enc_content = &(enccinfo->encContent);
  1048.     } else {
  1049. enc_content = NULL;
  1050.     }
  1051.     if (content != NULL && content->data != NULL && content->len) {
  1052. rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content,
  1053.   content->data, content->len, PR_TRUE);
  1054. if (rv != SECSuccess)
  1055.     goto loser;
  1056.     }
  1057.     rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg);
  1058. loser:
  1059.     PORT_Free (p7ecx);
  1060.     return rv;
  1061. }
  1062. /*
  1063.  * Encode a PKCS7 object, in one shot.  All necessary components
  1064.  * of the object must already be specified.  Either the data has
  1065.  * already been included (via SetContent), or the data is detached,
  1066.  * or there is no data at all (certs-only).
  1067.  *
  1068.  * "cinfo" specifies the object to be encoded.
  1069.  *
  1070.  * "outputfn" is where the encoded bytes will be passed.
  1071.  *
  1072.  * "outputarg" is an opaque argument to the above callback.
  1073.  *
  1074.  * "bulkkey" specifies the bulk encryption key to use.   This argument
  1075.  * can be NULL if no encryption is being done, or if the bulk key should
  1076.  * be generated internally (usually the case for EnvelopedData but never
  1077.  * for EncryptedData, which *must* provide a bulk encryption key).
  1078.  *
  1079.  * "pwfn" is a callback for getting the password which protects the
  1080.  * private key of the signer.  This argument can be NULL if it is known
  1081.  * that no signing is going to be done.
  1082.  *
  1083.  * "pwfnarg" is an opaque argument to the above callback.
  1084.  */
  1085. SECStatus
  1086. SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,
  1087.  SEC_PKCS7EncoderOutputCallback outputfn,
  1088.  void *outputarg,
  1089.  PK11SymKey *bulkkey,
  1090.  SECKEYGetPasswordKey pwfn,
  1091.  void *pwfnarg)
  1092. {
  1093.     SECStatus rv;
  1094.     rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
  1095.     if (rv == SECSuccess) {
  1096. struct sec_pkcs7_encoder_output outputcx;
  1097. outputcx.outputfn = outputfn;
  1098. outputcx.outputarg = outputarg;
  1099. rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate,
  1100.      sec_pkcs7_encoder_out, &outputcx);
  1101.     }
  1102.     return rv;
  1103. }
  1104. /*
  1105.  * Encode a PKCS7 object, in one shot.  All necessary components
  1106.  * of the object must already be specified.  Either the data has
  1107.  * already been included (via SetContent), or the data is detached,
  1108.  * or there is no data at all (certs-only).  The output, rather than
  1109.  * being passed to an output function as is done above, is all put
  1110.  * into a SECItem.
  1111.  *
  1112.  * "pool" specifies a pool from which to allocate the result.
  1113.  * It can be NULL, in which case memory is allocated generically.
  1114.  *
  1115.  * "dest" specifies a SECItem in which to put the result data.
  1116.  * It can be NULL, in which case the entire item is allocated, too.
  1117.  *
  1118.  * "cinfo" specifies the object to be encoded.
  1119.  *
  1120.  * "bulkkey" specifies the bulk encryption key to use.   This argument
  1121.  * can be NULL if no encryption is being done, or if the bulk key should
  1122.  * be generated internally (usually the case for EnvelopedData but never
  1123.  * for EncryptedData, which *must* provide a bulk encryption key).
  1124.  *
  1125.  * "pwfn" is a callback for getting the password which protects the
  1126.  * private key of the signer.  This argument can be NULL if it is known
  1127.  * that no signing is going to be done.
  1128.  *
  1129.  * "pwfnarg" is an opaque argument to the above callback.
  1130.  */
  1131. SECItem *
  1132. SEC_PKCS7EncodeItem (PRArenaPool *pool,
  1133.      SECItem *dest,
  1134.      SEC_PKCS7ContentInfo *cinfo,
  1135.      PK11SymKey *bulkkey,
  1136.      SECKEYGetPasswordKey pwfn,
  1137.      void *pwfnarg)
  1138. {
  1139.     SECStatus rv;
  1140.     rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
  1141.     if (rv != SECSuccess)
  1142. return NULL;
  1143.     return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
  1144. }