cmsencode.c

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

C
741
字号
    case SEC_OID_PKCS7_SIGNED_DATA:	/* this will finish the digests and sign */	rv = NSS_CMSSignedData_Encode_AfterData(p7ecx->content.signedData);	break;    case SEC_OID_PKCS7_ENVELOPED_DATA:	rv = NSS_CMSEnvelopedData_Encode_AfterData(p7ecx->content.envelopedData);	break;    case SEC_OID_PKCS7_DIGESTED_DATA:	rv = NSS_CMSDigestedData_Encode_AfterData(p7ecx->content.digestedData);	break;    case SEC_OID_PKCS7_ENCRYPTED_DATA:	rv = NSS_CMSEncryptedData_Encode_AfterData(p7ecx->content.encryptedData);	break;    case SEC_OID_PKCS7_DATA:	/* do nothing */	break;    default:	rv = SECFailure;	break;    }    return rv;}/* * nss_cms_encoder_work_data - process incoming data * * (from the user or the next encoding layer) * Here, we need to digest and/or encrypt, then pass it on */static SECStatusnss_cms_encoder_work_data(NSSCMSEncoderContext *p7ecx, SECItem *dest,			     const unsigned char *data, unsigned long len,			     PRBool final, PRBool innermost){    unsigned char *buf = NULL;    SECStatus rv;    NSSCMSContentInfo *cinfo;    rv = SECSuccess;		/* may as well be optimistic */    /*     * We should really have data to process, or we should be trying     * to finish/flush the last block.  (This is an overly paranoid     * check since all callers are in this file and simple inspection     * proves they do it right.  But it could find a bug in future     * modifications/development, that is why it is here.)     */    PORT_Assert ((data != NULL && len) || final);    /* we got data (either from the caller, or from a lower level encoder) */    cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);    /* Update the running digest. */    if (len && cinfo->digcx != NULL)	NSS_CMSDigestContext_Update(cinfo->digcx, data, len);    /* Encrypt this chunk. */    if (cinfo->ciphcx != NULL) {	unsigned int inlen;	/* length of data being encrypted */	unsigned int outlen;	/* length of encrypted data */	unsigned int buflen;	/* length available for encrypted data */	inlen = len;	buflen = NSS_CMSCipherContext_EncryptLength(cinfo->ciphcx, inlen, final);	if (buflen == 0) {	    /*	     * No output is expected, but the input data may be buffered	     * so we still have to call Encrypt.	     */	    rv = NSS_CMSCipherContext_Encrypt(cinfo->ciphcx, NULL, NULL, 0,				   data, inlen, final);	    if (final) {		len = 0;		goto done;	    }	    return rv;	}	if (dest != NULL)	    buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cmsg->poolp, buflen);	else	    buf = (unsigned char*)PORT_Alloc(buflen);	if (buf == NULL) {	    rv = SECFailure;	} else {	    rv = NSS_CMSCipherContext_Encrypt(cinfo->ciphcx, buf, &outlen, buflen,				   data, inlen, final);	    data = buf;	    len = outlen;	}	if (rv != SECSuccess)	    /* encryption or malloc failed? */	    return rv;    }    /*     * at this point (data,len) has everything we'd like to give to the CURRENT encoder     * (which will encode it, then hand it back to the user or the parent encoder)     * We don't encode the data if we're innermost and we're told not to include the data     */    if (p7ecx->ecx != NULL && len && (!innermost || cinfo->rawContent != NULL))	rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, (const char *)data, len);done:    if (cinfo->ciphcx != NULL) {	if (dest != NULL) {	    dest->data = buf;	    dest->len = len;	} else if (buf != NULL) {	    PORT_Free (buf);	}    }    return rv;}/* * nss_cms_encoder_update - deliver encoded data to the next higher level * * no recursion here because we REALLY want to end up at the next higher encoder! */static SECStatusnss_cms_encoder_update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned long len){    /* XXX Error handling needs help.  Return what?  Do "Finish" on failure? */    return nss_cms_encoder_work_data (p7ecx, NULL, (const unsigned char *)data, len, PR_FALSE, PR_FALSE);}/* * NSS_CMSEncoder_Start - set up encoding of a CMS message * * "cmsg" - message to encode * "outputfn", "outputarg" - callback function for delivery of DER-encoded output *                           will not be called if NULL. * "dest" - if non-NULL, pointer to SECItem that will hold the DER-encoded output * "destpoolp" - pool to allocate DER-encoded output in * "pwfn", pwfn_arg" - callback function for getting token password * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData * "detached_digestalgs", "detached_digests" - digests from detached content */NSSCMSEncoderContext *NSS_CMSEncoder_Start(NSSCMSMessage *cmsg,			NSSCMSContentCallback outputfn, void *outputarg,			SECItem *dest, PLArenaPool *destpoolp,			PK11PasswordFunc pwfn, void *pwfn_arg,			NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,			SECAlgorithmID **detached_digestalgs, SECItem **detached_digests){    NSSCMSEncoderContext *p7ecx;    SECStatus rv;    NSSCMSContentInfo *cinfo;    NSS_CMSMessage_SetEncodingParams(cmsg, pwfn, pwfn_arg, decrypt_key_cb, decrypt_key_cb_arg,					detached_digestalgs, detached_digests);    p7ecx = (NSSCMSEncoderContext *)PORT_ZAlloc(sizeof(NSSCMSEncoderContext));    if (p7ecx == NULL) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return NULL;    }    p7ecx->cmsg = cmsg;    p7ecx->output.outputfn = outputfn;    p7ecx->output.outputarg = outputarg;    p7ecx->output.dest = dest;    p7ecx->output.destpoolp = destpoolp;    p7ecx->type = SEC_OID_UNKNOWN;    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);    switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {    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;    default:	rv = SECFailure;	break;    }    if (rv != SECSuccess)	return NULL;    /* Initialize the BER encoder.     * Note that this will not encode anything until the first call to SEC_ASN1EncoderUpdate */    p7ecx->ecx = SEC_ASN1EncoderStart(cmsg, NSSCMSMessageTemplate,				       nss_cms_encoder_out, &(p7ecx->output));    if (p7ecx->ecx == NULL) {	PORT_Free (p7ecx);	return NULL;    }    p7ecx->ecxupdated = PR_FALSE;    /*     * Indicate that we are streaming.  We will be streaming until we     * get past the contents bytes.     */    SEC_ASN1EncoderSetStreaming(p7ecx->ecx);    /*     * The notify function will watch for the contents field.     */    SEC_ASN1EncoderSetNotifyProc(p7ecx->ecx, nss_cms_encoder_notify, p7ecx);    /* 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     * a child encoder). */    if (SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0) != SECSuccess) {	PORT_Free (p7ecx);	return NULL;    }    return p7ecx;}/* * NSS_CMSEncoder_Update - take content data delivery from the user * * "p7ecx" - encoder context * "data" - content data * "len" - length of content data * * need to find the lowest level (and call SEC_ASN1EncoderUpdate on the way down), * then hand the data to the work_data fn */SECStatusNSS_CMSEncoder_Update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned long len){    SECStatus rv;    NSSCMSContentInfo *cinfo;    SECOidTag childtype;    if (p7ecx->error)	return SECFailure;    /* hand data to the innermost decoder */    if (p7ecx->childp7ecx) {	/* recursion here */	rv = NSS_CMSEncoder_Update(p7ecx->childp7ecx, data, len);    } else {	/* we are at innermost decoder */	/* find out about our inner content type - must be data */	cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);	childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo);	if (childtype != SEC_OID_PKCS7_DATA)	    return SECFailure;	/* and we must not have preset data */	if (cinfo->content.data != NULL)	    return SECFailure;	/*  hand it the data so it can encode it (let DER trickle up the chain) */	rv = nss_cms_encoder_work_data(p7ecx, NULL, (const unsigned char *)data, len, PR_FALSE, PR_TRUE);    }    return rv;}/* * NSS_CMSEncoder_Cancel - stop all encoding * * we need to walk down the chain of encoders and the finish them from the innermost out */SECStatusNSS_CMSEncoder_Cancel(NSSCMSEncoderContext *p7ecx){    SECStatus rv = SECFailure;    /* XXX do this right! */    /*     * Finish any inner decoders before us so that all the encoded data is flushed     * This basically finishes all the decoders from the innermost to the outermost.     * Finishing an inner decoder may result in data being updated to the outer decoder     * while we are already in NSS_CMSEncoder_Finish, but that's allright.     */    if (p7ecx->childp7ecx) {	rv = NSS_CMSEncoder_Cancel(p7ecx->childp7ecx); /* frees p7ecx->childp7ecx */	/* remember rv for now */    }    /*     * On the way back up, there will be no more data (if we had an     * inner encoder, it is done now!)     * Flush out any remaining data and/or finish digests.     */    rv = nss_cms_encoder_work_data(p7ecx, NULL, NULL, 0, PR_TRUE, (p7ecx->childp7ecx == NULL));    if (rv != SECSuccess)	goto loser;    p7ecx->childp7ecx = NULL;    /* kick the encoder back into working mode again.     * We turn off streaming stuff (which will cause the encoder to continue     * encoding happily, now that we have all the data (like digests) ready for it).     */    SEC_ASN1EncoderClearTakeFromBuf(p7ecx->ecx);    SEC_ASN1EncoderClearStreaming(p7ecx->ecx);    /* now that TakeFromBuf is off, this will kick this encoder to finish encoding */    rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0);loser:    SEC_ASN1EncoderFinish(p7ecx->ecx);    PORT_Free (p7ecx);    return rv;}/* * NSS_CMSEncoder_Finish - signal the end of data * * we need to walk down the chain of encoders and the finish them from the innermost out */SECStatusNSS_CMSEncoder_Finish(NSSCMSEncoderContext *p7ecx){    SECStatus rv = SECFailure;    NSSCMSContentInfo *cinfo;    SECOidTag childtype;    /*     * Finish any inner decoders before us so that all the encoded data is flushed     * This basically finishes all the decoders from the innermost to the outermost.     * Finishing an inner decoder may result in data being updated to the outer decoder     * while we are already in NSS_CMSEncoder_Finish, but that's allright.     */    if (p7ecx->childp7ecx) {	rv = NSS_CMSEncoder_Finish(p7ecx->childp7ecx); /* frees p7ecx->childp7ecx */	if (rv != SECSuccess)	    goto loser;    }    /*     * On the way back up, there will be no more data (if we had an     * inner encoder, it is done now!)     * Flush out any remaining data and/or finish digests.     */    rv = nss_cms_encoder_work_data(p7ecx, NULL, NULL, 0, PR_TRUE, (p7ecx->childp7ecx == NULL));    if (rv != SECSuccess)	goto loser;    p7ecx->childp7ecx = NULL;    /* find out about our inner content type - must be data */    cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);    childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo);    if (childtype == SEC_OID_PKCS7_DATA && cinfo->content.data == NULL) {	SEC_ASN1EncoderClearTakeFromBuf(p7ecx->ecx);	/* now that TakeFromBuf is off, this will kick this encoder to finish encoding */	rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0);    }    SEC_ASN1EncoderClearStreaming(p7ecx->ecx);    if (p7ecx->error)	rv = SECFailure;loser:    SEC_ASN1EncoderFinish(p7ecx->ecx);    PORT_Free (p7ecx);    return rv;}

⌨️ 快捷键说明

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