cmsdecode.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 689 行 · 第 1/2 页

C
689
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * CMS decoding. * * $Id: cmsdecode.c,v 1.2 2000/06/13 21:56:28 chrisk%netscape.com Exp $ */#include "cmslocal.h"#include "cert.h"#include "key.h"#include "secasn1.h"#include "secitem.h"#include "secoid.h"#include "prtime.h"#include "secerr.h"struct NSSCMSDecoderContextStr {    SEC_ASN1DecoderContext *		dcx;		/* ASN.1 decoder context */    NSSCMSMessage *			cmsg;		/* backpointer to the root message */    SECOidTag				type;		/* type of message */    NSSCMSContent			content;	/* pointer to message */    NSSCMSDecoderContext *		childp7dcx;	/* inner CMS decoder context */    PRBool				saw_contents;    int					error;    NSSCMSContentCallback		cb;    void *				cb_arg;};static void nss_cms_decoder_update_filter (void *arg, const char *data, unsigned long len,                          int depth, SEC_ASN1EncodingPart data_kind);static SECStatus nss_cms_before_data(NSSCMSDecoderContext *p7dcx);static SECStatus nss_cms_after_data(NSSCMSDecoderContext *p7dcx);static SECStatus nss_cms_after_end(NSSCMSDecoderContext *p7dcx);static void nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, 			     const unsigned char *data, unsigned long len, PRBool final);extern const SEC_ASN1Template NSSCMSMessageTemplate[];/*  * nss_cms_decoder_notify - *  this is the driver of the decoding process. It gets called by the ASN.1 *  decoder before and after an object is decoded. *  at various points in the decoding process, we intercept to set up and do *  further processing. */static voidnss_cms_decoder_notify(void *arg, PRBool before, void *dest, int depth){    NSSCMSDecoderContext *p7dcx;    NSSCMSContentInfo *rootcinfo, *cinfo;    PRBool after = !before;    p7dcx = (NSSCMSDecoderContext *)arg;    rootcinfo = &(p7dcx->cmsg->contentInfo);    /* XXX error handling: need to set p7dcx->error */#ifdef CMSDEBUG     fprintf(stderr, "%6.6s, dest = 0x%08x, depth = %d\n", before ? "before" : "after", dest, depth);#endif    /* so what are we working on right now? */    switch (p7dcx->type) {    case SEC_OID_UNKNOWN:	/*	 * right now, we are still decoding the OUTER (root) cinfo	 * As soon as we know the inner content type, set up the info,	 * but NO inner decoder or filter. The root decoder handles the first	 * level children by itself - only for encapsulated contents (which	 * are encoded as DER inside of an OCTET STRING) we need to set up a	 * child decoder...	 */	if (after && dest == &(rootcinfo->contentType)) {	    p7dcx->type = NSS_CMSContentInfo_GetContentTypeTag(rootcinfo);	    p7dcx->content = rootcinfo->content;	/* is this ready already ? need to alloc? */	    /* XXX yes we need to alloc -- continue here */	}	break;    case SEC_OID_PKCS7_DATA:	/* this can only happen if the outermost cinfo has DATA in it */	/* otherwise, we handle this type implicitely in the inner decoders */	if (before && dest == &(rootcinfo->content)) {	    /* fake it to cause the filter to put the data in the right place... */	    /* we want the ASN.1 decoder to deliver the decoded bytes to us from now on */	    SEC_ASN1DecoderSetFilterProc(p7dcx->dcx,					  nss_cms_decoder_update_filter,					  p7dcx,					  (PRBool)(p7dcx->cb != NULL));	    break;	}	if (after && dest == &(rootcinfo->content.data)) {	    /* remove the filter */	    SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);	}	break;    case SEC_OID_PKCS7_SIGNED_DATA:    case SEC_OID_PKCS7_ENVELOPED_DATA:    case SEC_OID_PKCS7_DIGESTED_DATA:    case SEC_OID_PKCS7_ENCRYPTED_DATA:	if (before && dest == &(rootcinfo->content))	    break;					/* we're not there yet */	if (p7dcx->content.pointer == NULL)	    p7dcx->content = rootcinfo->content;	/* get this data type's inner contentInfo */	cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type);	if (before && dest == &(cinfo->contentType)) {	    /* at this point, set up the &%$&$ back pointer */	    /* we cannot do it later, because the content itself is optional! */	    /* please give me C++ */	    switch (p7dcx->type) {	    case SEC_OID_PKCS7_SIGNED_DATA:		p7dcx->content.signedData->cmsg = p7dcx->cmsg;		break;	    case SEC_OID_PKCS7_DIGESTED_DATA:		p7dcx->content.digestedData->cmsg = p7dcx->cmsg;		break;	    case SEC_OID_PKCS7_ENVELOPED_DATA:		p7dcx->content.envelopedData->cmsg = p7dcx->cmsg;		break;	    case SEC_OID_PKCS7_ENCRYPTED_DATA:		p7dcx->content.encryptedData->cmsg = p7dcx->cmsg;		break;	    }	}	if (before && dest == &(cinfo->rawContent)) {	    /* we want the ASN.1 decoder to deliver the decoded bytes to us from now on */	    SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, nss_cms_decoder_update_filter,					  p7dcx, (PRBool)(p7dcx->cb != NULL));	    /* we're right in front of the data */	    if (nss_cms_before_data(p7dcx) != SECSuccess) {		SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);	/* stop all processing */		p7dcx->error = PORT_GetError();	    }	}	if (after && dest == &(cinfo->rawContent)) {	    /* we're right after of the data */	    if (nss_cms_after_data(p7dcx) != SECSuccess)		p7dcx->error = PORT_GetError();	    /* we don't need to see the contents anymore */	    SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);	}	break;#if 0 /* NIH */    case SEC_OID_PKCS7_AUTHENTICATED_DATA:#endif    default:	/* unsupported or unknown message type - fail (more or less) gracefully */	p7dcx->error = SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE;	break;    }}/* * nss_cms_before_data - set up the current encoder to receive data */static SECStatusnss_cms_before_data(NSSCMSDecoderContext *p7dcx){    SECStatus rv;    SECOidTag childtype;    PLArenaPool *poolp;    NSSCMSDecoderContext *childp7dcx;    NSSCMSContentInfo *cinfo;    const SEC_ASN1Template *template;    void *mark = NULL;    size_t size;        poolp = p7dcx->cmsg->poolp;    /* call _Decode_BeforeData handlers */    switch (p7dcx->type) {    case SEC_OID_PKCS7_SIGNED_DATA:	/* we're decoding a signedData, so set up the digests */	rv = NSS_CMSSignedData_Decode_BeforeData(p7dcx->content.signedData);	if (rv != SECSuccess)	    return SECFailure;	break;    case SEC_OID_PKCS7_DIGESTED_DATA:	/* we're encoding a digestedData, so set up the digest */	rv = NSS_CMSDigestedData_Decode_BeforeData(p7dcx->content.digestedData);	if (rv != SECSuccess)	    return SECFailure;	break;    case SEC_OID_PKCS7_ENVELOPED_DATA:	rv = NSS_CMSEnvelopedData_Decode_BeforeData(p7dcx->content.envelopedData);	if (rv != SECSuccess)	    return SECFailure;	break;    case SEC_OID_PKCS7_ENCRYPTED_DATA:	rv = NSS_CMSEncryptedData_Decode_BeforeData(p7dcx->content.encryptedData);	if (rv != SECSuccess)	    return SECFailure;	break;    default:	return SECFailure;    }    /* ok, now we have a pointer to cinfo */    /* find out what kind of data is encapsulated */        cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type);    childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo);    if (childtype == SEC_OID_PKCS7_DATA) {	cinfo->content.data = SECITEM_AllocItem(poolp, NULL, 0);	if (cinfo->content.data == NULL)	    /* set memory error */	    return SECFailure;	p7dcx->childp7dcx = NULL;	return SECSuccess;    }    /* set up inner decoder */    if ((template = NSS_CMSUtil_GetTemplateByTypeTag(childtype)) == NULL)	return SECFailure;    childp7dcx = (NSSCMSDecoderContext *)PORT_ZAlloc(sizeof(NSSCMSDecoderContext));    if (childp7dcx == NULL)	return SECFailure;    mark = PORT_ArenaMark(poolp);    /* allocate space for the stuff we're creating */    size = NSS_CMSUtil_GetSizeByTypeTag(childtype);    childp7dcx->content.pointer = (void *)PORT_ArenaZAlloc(poolp, size);    if (childp7dcx->content.pointer == NULL)	goto loser;    /* start the child decoder */    childp7dcx->dcx = SEC_ASN1DecoderStart(poolp, childp7dcx->content.pointer, template);    if (childp7dcx->dcx == NULL)	goto loser;    /* the new decoder needs to notify, too */    SEC_ASN1DecoderSetNotifyProc(childp7dcx->dcx, nss_cms_decoder_notify, childp7dcx);    /* tell the parent decoder that it needs to feed us the content data */    p7dcx->childp7dcx = childp7dcx;    childp7dcx->type = childtype;	/* our type */    childp7dcx->cmsg = p7dcx->cmsg;	/* backpointer to root message */    /* should the child decoder encounter real data, it needs to give it to the caller */    childp7dcx->cb = p7dcx->cb;    childp7dcx->cb_arg = p7dcx->cb_arg;    /* now set up the parent to hand decoded data to the next level decoder */    p7dcx->cb = (NSSCMSContentCallback)NSS_CMSDecoder_Update;    p7dcx->cb_arg = childp7dcx;    PORT_ArenaUnmark(poolp, mark);    return SECSuccess;loser:    if (mark)	PORT_ArenaRelease(poolp, mark);    if (childp7dcx)	PORT_Free(childp7dcx);    p7dcx->childp7dcx = NULL;    return SECFailure;}static SECStatusnss_cms_after_data(NSSCMSDecoderContext *p7dcx){    PLArenaPool *poolp;    NSSCMSDecoderContext *childp7dcx;    SECStatus rv;    poolp = p7dcx->cmsg->poolp;    /* Handle last block. This is necessary to flush out the last bytes     * of a possibly incomplete block */    nss_cms_decoder_work_data(p7dcx, NULL, 0, PR_TRUE);    /* finish any "inner" decoders - there's no more data coming... */    if (p7dcx->childp7dcx != NULL) {	childp7dcx = p7dcx->childp7dcx;	if (childp7dcx->dcx != NULL) {	    if (SEC_ASN1DecoderFinish(childp7dcx->dcx) != SECSuccess) {		/* do what? free content? */		rv = SECFailure;	    } else {		rv = nss_cms_after_end(childp7dcx);	    }	    if (rv != SECSuccess)		goto done;	}	PORT_Free(p7dcx->childp7dcx);	p7dcx->childp7dcx = NULL;    }    switch (p7dcx->type) {    case SEC_OID_PKCS7_SIGNED_DATA:	/* this will finish the digests and verify */	rv = NSS_CMSSignedData_Decode_AfterData(p7dcx->content.signedData);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?