cmsencode.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 741 行 · 第 1/2 页
C
741 行
/* * 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 encoding. * * $Id: cmsencode.c,v 1.2 2000/06/13 21:56:29 chrisk%netscape.com Exp $ */#include "cmslocal.h"#include "cert.h"#include "key.h"#include "secasn1.h"#include "secoid.h"#include "secrng.h"#include "secitem.h"#include "pk11func.h"#include "secerr.h"struct nss_cms_encoder_output { NSSCMSContentCallback outputfn; void *outputarg; PLArenaPool *destpoolp; SECItem *dest;};struct NSSCMSEncoderContextStr { SEC_ASN1EncoderContext * ecx; /* ASN.1 encoder context */ PRBool ecxupdated; /* true if data was handed in */ NSSCMSMessage * cmsg; /* pointer to the root message */ SECOidTag type; /* type tag of the current content */ NSSCMSContent content; /* pointer to current content */ struct nss_cms_encoder_output output; /* output function */ int error; /* error code */ NSSCMSEncoderContext * childp7ecx; /* link to child encoder context */};static SECStatus nss_cms_before_data(NSSCMSEncoderContext *p7ecx);static SECStatus nss_cms_after_data(NSSCMSEncoderContext *p7ecx);static SECStatus nss_cms_encoder_update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned long len);static SECStatus nss_cms_encoder_work_data(NSSCMSEncoderContext *p7ecx, SECItem *dest, const unsigned char *data, unsigned long len, PRBool final, PRBool innermost);extern const SEC_ASN1Template NSSCMSMessageTemplate[];/* * The little output function that the ASN.1 encoder calls to hand * us bytes which we in turn hand back to our caller (via the callback * they gave us). */static voidnss_cms_encoder_out(void *arg, const char *buf, unsigned long len, int depth, SEC_ASN1EncodingPart data_kind){ struct nss_cms_encoder_output *output = (struct nss_cms_encoder_output *)arg; unsigned char *dest; unsigned long offset;#ifdef CMSDEBUG int i; fprintf(stderr, "kind = %d, depth = %d, len = %d\n", data_kind, depth, len); for (i=0; i < len; i++) { fprintf(stderr, " %02x%s", (unsigned int)buf[i] & 0xff, ((i % 16) == 15) ? "\n" : ""); } if ((i % 16) != 0) fprintf(stderr, "\n");#endif if (output->outputfn != NULL) /* call output callback with DER data */ output->outputfn(output->outputarg, buf, len); if (output->dest != NULL) { /* store DER data in SECItem */ offset = output->dest->len; if (offset == 0) { dest = (unsigned char *)PORT_ArenaAlloc(output->destpoolp, len); } else { dest = (unsigned char *)PORT_ArenaGrow(output->destpoolp, output->dest->data, output->dest->len, output->dest->len + len); } if (dest == NULL) /* oops */ return; output->dest->data = dest; output->dest->len += len; /* copy it in */ PORT_Memcpy(output->dest->data + offset, buf, len); }}/* * nss_cms_encoder_notify - ASN.1 encoder callback * * this function is called by the ASN.1 encoder before and after the encoding of * every object. here, it is used to keep track of data structures, set up * encryption and/or digesting and possibly set up child encoders. */static voidnss_cms_encoder_notify(void *arg, PRBool before, void *dest, int depth){ NSSCMSEncoderContext *p7ecx; NSSCMSContentInfo *rootcinfo, *cinfo; PRBool after = !before; PLArenaPool *poolp; SECOidTag childtype; SECItem *item; p7ecx = (NSSCMSEncoderContext *)arg; PORT_Assert(p7ecx != NULL); rootcinfo = &(p7ecx->cmsg->contentInfo); poolp = p7ecx->cmsg->poolp;#ifdef CMSDEBUG fprintf(stderr, "%6.6s, dest = 0x%08x, depth = %d\n", before ? "before" : "after", dest, depth);#endif /* * Watch for the content field, at which point we want to instruct * the ASN.1 encoder to start taking bytes from the buffer. */ switch (p7ecx->type) { default: case SEC_OID_UNKNOWN: /* we're still in the root message */ if (after && dest == &(rootcinfo->contentType)) { /* got the content type OID now - so find out the type tag */ p7ecx->type = NSS_CMSContentInfo_GetContentTypeTag(rootcinfo); /* set up a pointer to our current content */ p7ecx->content = rootcinfo->content; } break; case SEC_OID_PKCS7_DATA: if (before && dest == &(rootcinfo->rawContent)) { /* just set up encoder to grab from user - no encryption or digesting */ if ((item = rootcinfo->content.data) != NULL) (void)nss_cms_encoder_work_data(p7ecx, NULL, item->data, item->len, PR_TRUE, PR_TRUE); else SEC_ASN1EncoderSetTakeFromBuf(p7ecx->ecx); SEC_ASN1EncoderClearNotifyProc(p7ecx->ecx); /* no need to get notified anymore */ } 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: /* when we know what the content is, we encode happily until we reach the inner content */ cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type); childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo); if (after && dest == &(cinfo->contentType)) { /* we're right before encoding the data (if we have some or not) */ /* (for encrypted data, we're right before the contentEncAlg which may change */ /* in nss_cms_before_data because of IV calculation when setting up encryption) */ if (nss_cms_before_data(p7ecx) != SECSuccess) p7ecx->error = PORT_GetError(); } if (before && dest == &(cinfo->rawContent)) { if (childtype == SEC_OID_PKCS7_DATA && (item = cinfo->content.data) != NULL) /* we have data - feed it in */ (void)nss_cms_encoder_work_data(p7ecx, NULL, item->data, item->len, PR_TRUE, PR_TRUE); else /* else try to get it from user */ SEC_ASN1EncoderSetTakeFromBuf(p7ecx->ecx); } if (after && dest == &(cinfo->rawContent)) { if (nss_cms_after_data(p7ecx) != SECSuccess) p7ecx->error = PORT_GetError(); SEC_ASN1EncoderClearNotifyProc(p7ecx->ecx); /* no need to get notified anymore */ } break; }}/* * nss_cms_before_data - setup the current encoder to receive data */static SECStatusnss_cms_before_data(NSSCMSEncoderContext *p7ecx){ SECStatus rv; SECOidTag childtype; NSSCMSContentInfo *cinfo; PLArenaPool *poolp; NSSCMSEncoderContext *childp7ecx; const SEC_ASN1Template *template; poolp = p7ecx->cmsg->poolp; /* call _Encode_BeforeData handlers */ switch (p7ecx->type) { case SEC_OID_PKCS7_SIGNED_DATA: /* we're encoding a signedData, so set up the digests */ rv = NSS_CMSSignedData_Encode_BeforeData(p7ecx->content.signedData); break; case SEC_OID_PKCS7_DIGESTED_DATA: /* we're encoding a digestedData, so set up the digest */ rv = NSS_CMSDigestedData_Encode_BeforeData(p7ecx->content.digestedData); break; case SEC_OID_PKCS7_ENVELOPED_DATA: rv = NSS_CMSEnvelopedData_Encode_BeforeData(p7ecx->content.envelopedData); break; case SEC_OID_PKCS7_ENCRYPTED_DATA: rv = NSS_CMSEncryptedData_Encode_BeforeData(p7ecx->content.encryptedData); break; default: rv = SECFailure; } if (rv != SECSuccess) return SECFailure; /* ok, now we have a pointer to cinfo */ /* find out what kind of data is encapsulated */ cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type); childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo); switch (childtype) { case SEC_OID_PKCS7_SIGNED_DATA: case SEC_OID_PKCS7_ENVELOPED_DATA: case SEC_OID_PKCS7_ENCRYPTED_DATA: case SEC_OID_PKCS7_DIGESTED_DATA:#if 0 case SEC_OID_PKCS7_DATA: /* XXX here also??? maybe yes! */#endif /* in these cases, we need to set up a child encoder! */ /* create new encoder context */ childp7ecx = PORT_ZAlloc(sizeof(NSSCMSEncoderContext)); if (childp7ecx == NULL) return SECFailure; /* the CHILD encoder needs to hand its encoded data to the CURRENT encoder * (which will encrypt and/or digest it) * this needs to route back into our update function * which finds the lowest encoding context & encrypts and computes digests */ childp7ecx->type = childtype; childp7ecx->content = cinfo->content; /* use the non-recursive update function here, of course */ childp7ecx->output.outputfn = (NSSCMSContentCallback)nss_cms_encoder_update; childp7ecx->output.outputarg = p7ecx; childp7ecx->output.destpoolp = NULL; childp7ecx->output.dest = NULL; childp7ecx->cmsg = p7ecx->cmsg; template = NSS_CMSUtil_GetTemplateByTypeTag(childtype); if (template == NULL) goto loser; /* cannot happen */ /* now initialize the data for encoding the first third */ switch (childp7ecx->type) { case SEC_OID_PKCS7_SIGNED_DATA: rv = NSS_CMSSignedData_Encode_BeforeStart(cinfo->content.signedData); break; case SEC_OID_PKCS7_ENVELOPED_DATA: rv = NSS_CMSEnvelopedData_Encode_BeforeStart(cinfo->content.envelopedData); break; case SEC_OID_PKCS7_DIGESTED_DATA: rv = NSS_CMSDigestedData_Encode_BeforeStart(cinfo->content.digestedData); break; case SEC_OID_PKCS7_ENCRYPTED_DATA: rv = NSS_CMSEncryptedData_Encode_BeforeStart(cinfo->content.encryptedData); break; case SEC_OID_PKCS7_DATA: rv = SECSuccess; break; } if (rv != SECSuccess) goto loser; /* * Initialize the BER encoder. */ childp7ecx->ecx = SEC_ASN1EncoderStart(cinfo->content.pointer, template, nss_cms_encoder_out, &(childp7ecx->output)); if (childp7ecx->ecx == NULL) goto loser; childp7ecx->ecxupdated = PR_FALSE; /* * Indicate that we are streaming. We will be streaming until we * get past the contents bytes. */ SEC_ASN1EncoderSetStreaming(childp7ecx->ecx); /* * The notify function will watch for the contents field. */ SEC_ASN1EncoderSetNotifyProc(childp7ecx->ecx, nss_cms_encoder_notify, childp7ecx); /* please note that we are NOT calling SEC_ASN1EncoderUpdate here to kick off the */ /* encoding process - we'll do that from the update function instead */ /* otherwise we'd be encoding data from a call of the notify function of the */ /* parent encoder (which would not work) */ /* this will kick off the encoding process & encode everything up to the content bytes, * at which point the notify function sets streaming mode (and possibly creates * another child encoder). */ if (SEC_ASN1EncoderUpdate(childp7ecx->ecx, NULL, 0) != SECSuccess) goto loser; p7ecx->childp7ecx = childp7ecx; break; case SEC_OID_PKCS7_DATA: p7ecx->childp7ecx = NULL; break; default: /* we do not know this type */ p7ecx->error = SEC_ERROR_BAD_DER; break; } return SECSuccess;loser: if (childp7ecx) { if (childp7ecx->ecx) SEC_ASN1EncoderFinish(childp7ecx->ecx); PORT_Free(childp7ecx); } return SECFailure;}static SECStatusnss_cms_after_data(NSSCMSEncoderContext *p7ecx){ SECStatus rv; switch (p7ecx->type) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?