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

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.  * CMS decoding.
  35.  *
  36.  * $Id: cmsdecode.c,v 1.2 2000/06/13 21:56:28 chrisk%netscape.com Exp $
  37.  */
  38. #include "cmslocal.h"
  39. #include "cert.h"
  40. #include "key.h"
  41. #include "secasn1.h"
  42. #include "secitem.h"
  43. #include "secoid.h"
  44. #include "prtime.h"
  45. #include "secerr.h"
  46. struct NSSCMSDecoderContextStr {
  47.     SEC_ASN1DecoderContext * dcx; /* ASN.1 decoder context */
  48.     NSSCMSMessage * cmsg; /* backpointer to the root message */
  49.     SECOidTag type; /* type of message */
  50.     NSSCMSContent content; /* pointer to message */
  51.     NSSCMSDecoderContext * childp7dcx; /* inner CMS decoder context */
  52.     PRBool saw_contents;
  53.     int error;
  54.     NSSCMSContentCallback cb;
  55.     void * cb_arg;
  56. };
  57. static void nss_cms_decoder_update_filter (void *arg, const char *data, unsigned long len,
  58.                           int depth, SEC_ASN1EncodingPart data_kind);
  59. static SECStatus nss_cms_before_data(NSSCMSDecoderContext *p7dcx);
  60. static SECStatus nss_cms_after_data(NSSCMSDecoderContext *p7dcx);
  61. static SECStatus nss_cms_after_end(NSSCMSDecoderContext *p7dcx);
  62. static void nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, 
  63.      const unsigned char *data, unsigned long len, PRBool final);
  64. extern const SEC_ASN1Template NSSCMSMessageTemplate[];
  65. /* 
  66.  * nss_cms_decoder_notify -
  67.  *  this is the driver of the decoding process. It gets called by the ASN.1
  68.  *  decoder before and after an object is decoded.
  69.  *  at various points in the decoding process, we intercept to set up and do
  70.  *  further processing.
  71.  */
  72. static void
  73. nss_cms_decoder_notify(void *arg, PRBool before, void *dest, int depth)
  74. {
  75.     NSSCMSDecoderContext *p7dcx;
  76.     NSSCMSContentInfo *rootcinfo, *cinfo;
  77.     PRBool after = !before;
  78.     p7dcx = (NSSCMSDecoderContext *)arg;
  79.     rootcinfo = &(p7dcx->cmsg->contentInfo);
  80.     /* XXX error handling: need to set p7dcx->error */
  81. #ifdef CMSDEBUG 
  82.     fprintf(stderr, "%6.6s, dest = 0x%08x, depth = %dn", before ? "before" : "after", dest, depth);
  83. #endif
  84.     /* so what are we working on right now? */
  85.     switch (p7dcx->type) {
  86.     case SEC_OID_UNKNOWN:
  87. /*
  88.  * right now, we are still decoding the OUTER (root) cinfo
  89.  * As soon as we know the inner content type, set up the info,
  90.  * but NO inner decoder or filter. The root decoder handles the first
  91.  * level children by itself - only for encapsulated contents (which
  92.  * are encoded as DER inside of an OCTET STRING) we need to set up a
  93.  * child decoder...
  94.  */
  95. if (after && dest == &(rootcinfo->contentType)) {
  96.     p7dcx->type = NSS_CMSContentInfo_GetContentTypeTag(rootcinfo);
  97.     p7dcx->content = rootcinfo->content; /* is this ready already ? need to alloc? */
  98.     /* XXX yes we need to alloc -- continue here */
  99. }
  100. break;
  101.     case SEC_OID_PKCS7_DATA:
  102. /* this can only happen if the outermost cinfo has DATA in it */
  103. /* otherwise, we handle this type implicitely in the inner decoders */
  104. if (before && dest == &(rootcinfo->content)) {
  105.     /* fake it to cause the filter to put the data in the right place... */
  106.     /* we want the ASN.1 decoder to deliver the decoded bytes to us from now on */
  107.     SEC_ASN1DecoderSetFilterProc(p7dcx->dcx,
  108.   nss_cms_decoder_update_filter,
  109.   p7dcx,
  110.   (PRBool)(p7dcx->cb != NULL));
  111.     break;
  112. }
  113. if (after && dest == &(rootcinfo->content.data)) {
  114.     /* remove the filter */
  115.     SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);
  116. }
  117. break;
  118.     case SEC_OID_PKCS7_SIGNED_DATA:
  119.     case SEC_OID_PKCS7_ENVELOPED_DATA:
  120.     case SEC_OID_PKCS7_DIGESTED_DATA:
  121.     case SEC_OID_PKCS7_ENCRYPTED_DATA:
  122. if (before && dest == &(rootcinfo->content))
  123.     break; /* we're not there yet */
  124. if (p7dcx->content.pointer == NULL)
  125.     p7dcx->content = rootcinfo->content;
  126. /* get this data type's inner contentInfo */
  127. cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type);
  128. if (before && dest == &(cinfo->contentType)) {
  129.     /* at this point, set up the &%$&$ back pointer */
  130.     /* we cannot do it later, because the content itself is optional! */
  131.     /* please give me C++ */
  132.     switch (p7dcx->type) {
  133.     case SEC_OID_PKCS7_SIGNED_DATA:
  134. p7dcx->content.signedData->cmsg = p7dcx->cmsg;
  135. break;
  136.     case SEC_OID_PKCS7_DIGESTED_DATA:
  137. p7dcx->content.digestedData->cmsg = p7dcx->cmsg;
  138. break;
  139.     case SEC_OID_PKCS7_ENVELOPED_DATA:
  140. p7dcx->content.envelopedData->cmsg = p7dcx->cmsg;
  141. break;
  142.     case SEC_OID_PKCS7_ENCRYPTED_DATA:
  143. p7dcx->content.encryptedData->cmsg = p7dcx->cmsg;
  144. break;
  145.     }
  146. }
  147. if (before && dest == &(cinfo->rawContent)) {
  148.     /* we want the ASN.1 decoder to deliver the decoded bytes to us from now on */
  149.     SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, nss_cms_decoder_update_filter,
  150.   p7dcx, (PRBool)(p7dcx->cb != NULL));
  151.     /* we're right in front of the data */
  152.     if (nss_cms_before_data(p7dcx) != SECSuccess) {
  153. SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); /* stop all processing */
  154. p7dcx->error = PORT_GetError();
  155.     }
  156. }
  157. if (after && dest == &(cinfo->rawContent)) {
  158.     /* we're right after of the data */
  159.     if (nss_cms_after_data(p7dcx) != SECSuccess)
  160. p7dcx->error = PORT_GetError();
  161.     /* we don't need to see the contents anymore */
  162.     SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);
  163. }
  164. break;
  165. #if 0 /* NIH */
  166.     case SEC_OID_PKCS7_AUTHENTICATED_DATA:
  167. #endif
  168.     default:
  169. /* unsupported or unknown message type - fail (more or less) gracefully */
  170. p7dcx->error = SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE;
  171. break;
  172.     }
  173. }
  174. /*
  175.  * nss_cms_before_data - set up the current encoder to receive data
  176.  */
  177. static SECStatus
  178. nss_cms_before_data(NSSCMSDecoderContext *p7dcx)
  179. {
  180.     SECStatus rv;
  181.     SECOidTag childtype;
  182.     PLArenaPool *poolp;
  183.     NSSCMSDecoderContext *childp7dcx;
  184.     NSSCMSContentInfo *cinfo;
  185.     const SEC_ASN1Template *template;
  186.     void *mark = NULL;
  187.     size_t size;
  188.     
  189.     poolp = p7dcx->cmsg->poolp;
  190.     /* call _Decode_BeforeData handlers */
  191.     switch (p7dcx->type) {
  192.     case SEC_OID_PKCS7_SIGNED_DATA:
  193. /* we're decoding a signedData, so set up the digests */
  194. rv = NSS_CMSSignedData_Decode_BeforeData(p7dcx->content.signedData);
  195. if (rv != SECSuccess)
  196.     return SECFailure;
  197. break;
  198.     case SEC_OID_PKCS7_DIGESTED_DATA:
  199. /* we're encoding a digestedData, so set up the digest */
  200. rv = NSS_CMSDigestedData_Decode_BeforeData(p7dcx->content.digestedData);
  201. if (rv != SECSuccess)
  202.     return SECFailure;
  203. break;
  204.     case SEC_OID_PKCS7_ENVELOPED_DATA:
  205. rv = NSS_CMSEnvelopedData_Decode_BeforeData(p7dcx->content.envelopedData);
  206. if (rv != SECSuccess)
  207.     return SECFailure;
  208. break;
  209.     case SEC_OID_PKCS7_ENCRYPTED_DATA:
  210. rv = NSS_CMSEncryptedData_Decode_BeforeData(p7dcx->content.encryptedData);
  211. if (rv != SECSuccess)
  212.     return SECFailure;
  213. break;
  214.     default:
  215. return SECFailure;
  216.     }
  217.     /* ok, now we have a pointer to cinfo */
  218.     /* find out what kind of data is encapsulated */
  219.     
  220.     cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type);
  221.     childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
  222.     if (childtype == SEC_OID_PKCS7_DATA) {
  223. cinfo->content.data = SECITEM_AllocItem(poolp, NULL, 0);
  224. if (cinfo->content.data == NULL)
  225.     /* set memory error */
  226.     return SECFailure;
  227. p7dcx->childp7dcx = NULL;
  228. return SECSuccess;
  229.     }
  230.     /* set up inner decoder */
  231.     if ((template = NSS_CMSUtil_GetTemplateByTypeTag(childtype)) == NULL)
  232. return SECFailure;
  233.     childp7dcx = (NSSCMSDecoderContext *)PORT_ZAlloc(sizeof(NSSCMSDecoderContext));
  234.     if (childp7dcx == NULL)
  235. return SECFailure;
  236.     mark = PORT_ArenaMark(poolp);
  237.     /* allocate space for the stuff we're creating */
  238.     size = NSS_CMSUtil_GetSizeByTypeTag(childtype);
  239.     childp7dcx->content.pointer = (void *)PORT_ArenaZAlloc(poolp, size);
  240.     if (childp7dcx->content.pointer == NULL)
  241. goto loser;
  242.     /* start the child decoder */
  243.     childp7dcx->dcx = SEC_ASN1DecoderStart(poolp, childp7dcx->content.pointer, template);
  244.     if (childp7dcx->dcx == NULL)
  245. goto loser;
  246.     /* the new decoder needs to notify, too */
  247.     SEC_ASN1DecoderSetNotifyProc(childp7dcx->dcx, nss_cms_decoder_notify, childp7dcx);
  248.     /* tell the parent decoder that it needs to feed us the content data */
  249.     p7dcx->childp7dcx = childp7dcx;
  250.     childp7dcx->type = childtype; /* our type */
  251.     childp7dcx->cmsg = p7dcx->cmsg; /* backpointer to root message */
  252.     /* should the child decoder encounter real data, it needs to give it to the caller */
  253.     childp7dcx->cb = p7dcx->cb;
  254.     childp7dcx->cb_arg = p7dcx->cb_arg;
  255.     /* now set up the parent to hand decoded data to the next level decoder */
  256.     p7dcx->cb = (NSSCMSContentCallback)NSS_CMSDecoder_Update;
  257.     p7dcx->cb_arg = childp7dcx;
  258.     PORT_ArenaUnmark(poolp, mark);
  259.     return SECSuccess;
  260. loser:
  261.     if (mark)
  262. PORT_ArenaRelease(poolp, mark);
  263.     if (childp7dcx)
  264. PORT_Free(childp7dcx);
  265.     p7dcx->childp7dcx = NULL;
  266.     return SECFailure;
  267. }
  268. static SECStatus
  269. nss_cms_after_data(NSSCMSDecoderContext *p7dcx)
  270. {
  271.     PLArenaPool *poolp;
  272.     NSSCMSDecoderContext *childp7dcx;
  273.     SECStatus rv;
  274.     poolp = p7dcx->cmsg->poolp;
  275.     /* Handle last block. This is necessary to flush out the last bytes
  276.      * of a possibly incomplete block */
  277.     nss_cms_decoder_work_data(p7dcx, NULL, 0, PR_TRUE);
  278.     /* finish any "inner" decoders - there's no more data coming... */
  279.     if (p7dcx->childp7dcx != NULL) {
  280. childp7dcx = p7dcx->childp7dcx;
  281. if (childp7dcx->dcx != NULL) {
  282.     if (SEC_ASN1DecoderFinish(childp7dcx->dcx) != SECSuccess) {
  283. /* do what? free content? */
  284. rv = SECFailure;
  285.     } else {
  286. rv = nss_cms_after_end(childp7dcx);
  287.     }
  288.     if (rv != SECSuccess)
  289. goto done;
  290. }
  291. PORT_Free(p7dcx->childp7dcx);
  292. p7dcx->childp7dcx = NULL;
  293.     }
  294.     switch (p7dcx->type) {
  295.     case SEC_OID_PKCS7_SIGNED_DATA:
  296. /* this will finish the digests and verify */
  297. rv = NSS_CMSSignedData_Decode_AfterData(p7dcx->content.signedData);
  298. break;
  299.     case SEC_OID_PKCS7_ENVELOPED_DATA:
  300. rv = NSS_CMSEnvelopedData_Decode_AfterData(p7dcx->content.envelopedData);
  301. break;
  302.     case SEC_OID_PKCS7_DIGESTED_DATA:
  303. rv = NSS_CMSDigestedData_Decode_AfterData(p7dcx->content.digestedData);
  304. break;
  305.     case SEC_OID_PKCS7_ENCRYPTED_DATA:
  306. rv = NSS_CMSEncryptedData_Decode_AfterData(p7dcx->content.encryptedData);
  307. break;
  308.     case SEC_OID_PKCS7_DATA:
  309. /* do nothing */
  310. break;
  311.     default:
  312. rv = SECFailure;
  313. break;
  314.     }
  315. done:
  316.     return rv;
  317. }
  318. static SECStatus
  319. nss_cms_after_end(NSSCMSDecoderContext *p7dcx)
  320. {
  321.     SECStatus rv;
  322.     PLArenaPool *poolp;
  323.     poolp = p7dcx->cmsg->poolp;
  324.     switch (p7dcx->type) {
  325.     case SEC_OID_PKCS7_SIGNED_DATA:
  326. rv = NSS_CMSSignedData_Decode_AfterEnd(p7dcx->content.signedData);
  327. break;
  328.     case SEC_OID_PKCS7_ENVELOPED_DATA:
  329. rv = NSS_CMSEnvelopedData_Decode_AfterEnd(p7dcx->content.envelopedData);
  330. break;
  331.     case SEC_OID_PKCS7_DIGESTED_DATA:
  332. rv = NSS_CMSDigestedData_Decode_AfterEnd(p7dcx->content.digestedData);
  333. break;
  334.     case SEC_OID_PKCS7_ENCRYPTED_DATA:
  335. rv = NSS_CMSEncryptedData_Decode_AfterEnd(p7dcx->content.encryptedData);
  336. break;
  337.     case SEC_OID_PKCS7_DATA:
  338. rv = SECSuccess;
  339. break;
  340.     default:
  341. rv = SECFailure; /* we should not have got that far... */
  342. break;
  343.     }
  344.     return rv;
  345. }
  346. /*
  347.  * nss_cms_decoder_work_data - handle decoded data bytes.
  348.  *
  349.  * This function either decrypts the data if needed, and/or calculates digests
  350.  * on it, then either stores it or passes it on to the next level decoder.
  351.  */
  352. static void
  353. nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, 
  354.      const unsigned char *data, unsigned long len,
  355.      PRBool final)
  356. {
  357.     NSSCMSContentInfo *cinfo;
  358.     unsigned char *buf = NULL;
  359.     unsigned char *dest;
  360.     unsigned int offset;
  361.     SECStatus rv;
  362.     SECItem *storage;
  363.     /*
  364.      * We should really have data to process, or we should be trying
  365.      * to finish/flush the last block.  (This is an overly paranoid
  366.      * check since all callers are in this file and simple inspection
  367.      * proves they do it right.  But it could find a bug in future
  368.      * modifications/development, that is why it is here.)
  369.      */
  370.     PORT_Assert ((data != NULL && len) || final);
  371.     cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type);
  372.     if (cinfo->ciphcx != NULL) {
  373. /*
  374.  * we are decrypting.
  375.  * 
  376.  * XXX If we get an error, we do not want to do the digest or callback,
  377.  * but we want to keep decoding.  Or maybe we want to stop decoding
  378.  * altogether if there is a callback, because obviously we are not
  379.  * sending the data back and they want to know that.
  380.  */
  381. unsigned int outlen = 0; /* length of decrypted data */
  382. unsigned int buflen; /* length available for decrypted data */
  383. /* find out about the length of decrypted data */
  384. buflen = NSS_CMSCipherContext_DecryptLength(cinfo->ciphcx, len, final);
  385. /*
  386.  * it might happen that we did not provide enough data for a full
  387.  * block (decryption unit), and that there is no output available
  388.  */
  389. /* no output available, AND no input? */
  390. if (buflen == 0 && len == 0)
  391.     goto loser; /* bail out */
  392. /*
  393.  * have inner decoder: pass the data on (means inner content type is NOT data)
  394.  * no inner decoder: we have DATA in here: either call callback or store
  395.  */
  396. if (buflen != 0) {
  397.     /* there will be some output - need to make room for it */
  398.     /* allocate buffer from the heap */
  399.     buf = (unsigned char *)PORT_Alloc(buflen);
  400.     if (buf == NULL) {
  401. p7dcx->error = SEC_ERROR_NO_MEMORY;
  402. goto loser;
  403.     }
  404. }
  405. /*
  406.  * decrypt incoming data
  407.  * buf can still be NULL here (and buflen == 0) here if we don't expect
  408.  * any output (see above), but we still need to call NSS_CMSCipherContext_Decrypt to
  409.  * keep track of incoming data
  410.  */
  411. rv = NSS_CMSCipherContext_Decrypt(cinfo->ciphcx, buf, &outlen, buflen,
  412.        data, len, final);
  413. if (rv != SECSuccess) {
  414.     p7dcx->error = PORT_GetError();
  415.     goto loser;
  416. }
  417. PORT_Assert (final || outlen == buflen);
  418. /* swap decrypted data in */
  419. data = buf;
  420. len = outlen;
  421.     }
  422.     if (len == 0)
  423. return; /* nothing more to do */
  424.     /*
  425.      * Update the running digests with plaintext bytes (if we need to).
  426.      */
  427.     if (cinfo->digcx)
  428. NSS_CMSDigestContext_Update(cinfo->digcx, data, len);
  429.     /* at this point, we have the plain decoded & decrypted data */
  430.     /* which is either more encoded DER which we need to hand to the child decoder */
  431.     /*              or data we need to hand back to our caller */
  432.     /* pass the content back to our caller or */
  433.     /* feed our freshly decrypted and decoded data into child decoder */
  434.     if (p7dcx->cb != NULL) {
  435. (*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len);
  436.     }
  437. #if 1
  438.     else
  439. #endif
  440.     if (NSS_CMSContentInfo_GetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA) {
  441. /* store it in "inner" data item as well */
  442. /* find the DATA item in the encapsulated cinfo and store it there */
  443. storage = cinfo->content.data;
  444. offset = storage->len;
  445. if (storage->len == 0) {
  446.     dest = (unsigned char *)PORT_ArenaAlloc(p7dcx->cmsg->poolp, len);
  447. } else {
  448.     dest = (unsigned char *)PORT_ArenaGrow(p7dcx->cmsg->poolp, 
  449.   storage->data,
  450.   storage->len,
  451.   storage->len + len);
  452. }
  453. if (dest == NULL) {
  454.     p7dcx->error = SEC_ERROR_NO_MEMORY;
  455.     goto loser;
  456. }
  457. storage->data = dest;
  458. storage->len += len;
  459. /* copy it in */
  460. PORT_Memcpy(storage->data + offset, data, len);
  461.     }
  462. loser:
  463.     if (buf)
  464. PORT_Free (buf);
  465. }
  466. /*
  467.  * nss_cms_decoder_update_filter - process ASN.1 data
  468.  *
  469.  * once we have set up a filter in nss_cms_decoder_notify(),
  470.  * all data processed by the ASN.1 decoder is also passed through here.
  471.  * we pass the content bytes (as opposed to length and tag bytes) on to
  472.  * nss_cms_decoder_work_data().
  473.  */
  474. static void
  475. nss_cms_decoder_update_filter (void *arg, const char *data, unsigned long len,
  476.   int depth, SEC_ASN1EncodingPart data_kind)
  477. {
  478.     NSSCMSDecoderContext *p7dcx;
  479.     PORT_Assert (len); /* paranoia */
  480.     if (len == 0)
  481. return;
  482.     p7dcx = (NSSCMSDecoderContext*)arg;
  483.     p7dcx->saw_contents = PR_TRUE;
  484.     /* pass on the content bytes only */
  485.     if (data_kind == SEC_ASN1_Contents)
  486. nss_cms_decoder_work_data(p7dcx, (const unsigned char *) data, len, PR_FALSE);
  487. }
  488. /*
  489.  * NSS_CMSDecoder_Start - set up decoding of a DER-encoded CMS message
  490.  *
  491.  * "poolp" - pointer to arena for message, or NULL if new pool should be created
  492.  * "cb", "cb_arg" - callback function and argument for delivery of inner content
  493.  * "pwfn", pwfn_arg" - callback function for getting token password
  494.  * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
  495.  */
  496. NSSCMSDecoderContext *
  497. NSS_CMSDecoder_Start(PRArenaPool *poolp,
  498.       NSSCMSContentCallback cb, void *cb_arg,
  499.       PK11PasswordFunc pwfn, void *pwfn_arg,
  500.       NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg)
  501. {
  502.     NSSCMSDecoderContext *p7dcx;
  503.     NSSCMSMessage *cmsg;
  504.     cmsg = NSS_CMSMessage_Create(poolp);
  505.     if (cmsg == NULL)
  506. return NULL;
  507.     NSS_CMSMessage_SetEncodingParams(cmsg, pwfn, pwfn_arg, decrypt_key_cb, decrypt_key_cb_arg,
  508. NULL, NULL);
  509.     p7dcx = (NSSCMSDecoderContext*)PORT_ZAlloc(sizeof(NSSCMSDecoderContext));
  510.     if (p7dcx == NULL) {
  511. NSS_CMSMessage_Destroy(cmsg);
  512. return NULL;
  513.     }
  514.     p7dcx->dcx = SEC_ASN1DecoderStart(cmsg->poolp, cmsg, NSSCMSMessageTemplate);
  515.     if (p7dcx->dcx == NULL) {
  516. PORT_Free (p7dcx);
  517. NSS_CMSMessage_Destroy(cmsg);
  518. return NULL;
  519.     }
  520.     SEC_ASN1DecoderSetNotifyProc (p7dcx->dcx, nss_cms_decoder_notify, p7dcx);
  521.     p7dcx->cmsg = cmsg;
  522.     p7dcx->type = SEC_OID_UNKNOWN;
  523.     p7dcx->cb = cb;
  524.     p7dcx->cb_arg = cb_arg;
  525.     return p7dcx;
  526. }
  527. /*
  528.  * NSS_CMSDecoder_Update - feed DER-encoded data to decoder
  529.  */
  530. SECStatus
  531. NSS_CMSDecoder_Update(NSSCMSDecoderContext *p7dcx, const char *buf, unsigned long len)
  532. {
  533.     if (p7dcx->dcx != NULL && p7dcx->error == 0) { /* if error is set already, don't bother */
  534. if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) {
  535.     p7dcx->error = PORT_GetError();
  536.     PORT_Assert (p7dcx->error);
  537.     if (p7dcx->error == 0)
  538. p7dcx->error = -1;
  539. }
  540.     }
  541.     if (p7dcx->error == 0)
  542. return SECSuccess;
  543.     /* there has been a problem, let's finish the decoder */
  544.     if (p7dcx->dcx != NULL) {
  545. (void) SEC_ASN1DecoderFinish (p7dcx->dcx);
  546. p7dcx->dcx = NULL;
  547.     }
  548.     PORT_SetError (p7dcx->error);
  549.     return SECFailure;
  550. }
  551. /*
  552.  * NSS_CMSDecoder_Cancel - stop decoding in case of error
  553.  */
  554. void
  555. NSS_CMSDecoder_Cancel(NSSCMSDecoderContext *p7dcx)
  556. {
  557.     /* XXXX what about inner decoders? running digests? decryption? */
  558.     /* XXXX there's a leak here! */
  559.     NSS_CMSMessage_Destroy(p7dcx->cmsg);
  560.     (void)SEC_ASN1DecoderFinish(p7dcx->dcx);
  561.     PORT_Free(p7dcx);
  562. }
  563. /*
  564.  * NSS_CMSDecoder_Finish - mark the end of inner content and finish decoding
  565.  */
  566. NSSCMSMessage *
  567. NSS_CMSDecoder_Finish(NSSCMSDecoderContext *p7dcx)
  568. {
  569.     NSSCMSMessage *cmsg;
  570.     cmsg = p7dcx->cmsg;
  571.     if (p7dcx->dcx == NULL || SEC_ASN1DecoderFinish(p7dcx->dcx) != SECSuccess ||
  572. nss_cms_after_end(p7dcx) != SECSuccess)
  573.     {
  574. NSS_CMSMessage_Destroy(cmsg); /* needs to get rid of pool if it's ours */
  575. cmsg = NULL;
  576.     }
  577.     PORT_Free(p7dcx);
  578.     return cmsg;
  579. }
  580. NSSCMSMessage *
  581. NSS_CMSMessage_CreateFromDER(SECItem *DERmessage,
  582.     NSSCMSContentCallback cb, void *cb_arg,
  583.     PK11PasswordFunc pwfn, void *pwfn_arg,
  584.     NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg)
  585. {
  586.     NSSCMSDecoderContext *p7dcx;
  587.     /* first arg(poolp) == NULL => create our own pool */
  588.     p7dcx = NSS_CMSDecoder_Start(NULL, cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb, decrypt_key_cb_arg);
  589.     (void) NSS_CMSDecoder_Update(p7dcx, (char *)DERmessage->data, DERmessage->len);
  590.     return NSS_CMSDecoder_Finish(p7dcx);
  591. }