cmsdecode.c

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

C
689
字号
	break;    case SEC_OID_PKCS7_ENVELOPED_DATA:	rv = NSS_CMSEnvelopedData_Decode_AfterData(p7dcx->content.envelopedData);	break;    case SEC_OID_PKCS7_DIGESTED_DATA:	rv = NSS_CMSDigestedData_Decode_AfterData(p7dcx->content.digestedData);	break;    case SEC_OID_PKCS7_ENCRYPTED_DATA:	rv = NSS_CMSEncryptedData_Decode_AfterData(p7dcx->content.encryptedData);	break;    case SEC_OID_PKCS7_DATA:	/* do nothing */	break;    default:	rv = SECFailure;	break;    }done:    return rv;}static SECStatusnss_cms_after_end(NSSCMSDecoderContext *p7dcx){    SECStatus rv;    PLArenaPool *poolp;    poolp = p7dcx->cmsg->poolp;    switch (p7dcx->type) {    case SEC_OID_PKCS7_SIGNED_DATA:	rv = NSS_CMSSignedData_Decode_AfterEnd(p7dcx->content.signedData);	break;    case SEC_OID_PKCS7_ENVELOPED_DATA:	rv = NSS_CMSEnvelopedData_Decode_AfterEnd(p7dcx->content.envelopedData);	break;    case SEC_OID_PKCS7_DIGESTED_DATA:	rv = NSS_CMSDigestedData_Decode_AfterEnd(p7dcx->content.digestedData);	break;    case SEC_OID_PKCS7_ENCRYPTED_DATA:	rv = NSS_CMSEncryptedData_Decode_AfterEnd(p7dcx->content.encryptedData);	break;    case SEC_OID_PKCS7_DATA:	rv = SECSuccess;	break;    default:	rv = SECFailure;	/* we should not have got that far... */	break;    }    return rv;}/* * nss_cms_decoder_work_data - handle decoded data bytes. * * This function either decrypts the data if needed, and/or calculates digests * on it, then either stores it or passes it on to the next level decoder. */static voidnss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, 			     const unsigned char *data, unsigned long len,			     PRBool final){    NSSCMSContentInfo *cinfo;    unsigned char *buf = NULL;    unsigned char *dest;    unsigned int offset;    SECStatus rv;    SECItem *storage;    /*     * 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);    cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type);    if (cinfo->ciphcx != NULL) {	/*	 * we are decrypting.	 * 	 * XXX If we get an error, we do not want to do the digest or callback,	 * but we want to keep decoding.  Or maybe we want to stop decoding	 * altogether if there is a callback, because obviously we are not	 * sending the data back and they want to know that.	 */	unsigned int outlen = 0;	/* length of decrypted data */	unsigned int buflen;		/* length available for decrypted data */	/* find out about the length of decrypted data */	buflen = NSS_CMSCipherContext_DecryptLength(cinfo->ciphcx, len, final);	/*	 * it might happen that we did not provide enough data for a full	 * block (decryption unit), and that there is no output available	 */	/* no output available, AND no input? */	if (buflen == 0 && len == 0)	    goto loser;	/* bail out */	/*	 * have inner decoder: pass the data on (means inner content type is NOT data)	 * no inner decoder: we have DATA in here: either call callback or store	 */	if (buflen != 0) {	    /* there will be some output - need to make room for it */	    /* allocate buffer from the heap */	    buf = (unsigned char *)PORT_Alloc(buflen);	    if (buf == NULL) {		p7dcx->error = SEC_ERROR_NO_MEMORY;		goto loser;	    }	}	/*	 * decrypt incoming data	 * buf can still be NULL here (and buflen == 0) here if we don't expect	 * any output (see above), but we still need to call NSS_CMSCipherContext_Decrypt to	 * keep track of incoming data	 */	rv = NSS_CMSCipherContext_Decrypt(cinfo->ciphcx, buf, &outlen, buflen,			       data, len, final);	if (rv != SECSuccess) {	    p7dcx->error = PORT_GetError();	    goto loser;	}	PORT_Assert (final || outlen == buflen);		/* swap decrypted data in */	data = buf;	len = outlen;    }    if (len == 0)	return;		/* nothing more to do */    /*     * Update the running digests with plaintext bytes (if we need to).     */    if (cinfo->digcx)	NSS_CMSDigestContext_Update(cinfo->digcx, data, len);    /* at this point, we have the plain decoded & decrypted data */    /* which is either more encoded DER which we need to hand to the child decoder */    /*              or data we need to hand back to our caller */    /* pass the content back to our caller or */    /* feed our freshly decrypted and decoded data into child decoder */    if (p7dcx->cb != NULL) {	(*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len);    }#if 1    else#endif    if (NSS_CMSContentInfo_GetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA) {	/* store it in "inner" data item as well */	/* find the DATA item in the encapsulated cinfo and store it there */	storage = cinfo->content.data;	offset = storage->len;	if (storage->len == 0) {	    dest = (unsigned char *)PORT_ArenaAlloc(p7dcx->cmsg->poolp, len);	} else {	    dest = (unsigned char *)PORT_ArenaGrow(p7dcx->cmsg->poolp, 				  storage->data,				  storage->len,				  storage->len + len);	}	if (dest == NULL) {	    p7dcx->error = SEC_ERROR_NO_MEMORY;	    goto loser;	}	storage->data = dest;	storage->len += len;	/* copy it in */	PORT_Memcpy(storage->data + offset, data, len);    }loser:    if (buf)	PORT_Free (buf);}/* * nss_cms_decoder_update_filter - process ASN.1 data * * once we have set up a filter in nss_cms_decoder_notify(), * all data processed by the ASN.1 decoder is also passed through here. * we pass the content bytes (as opposed to length and tag bytes) on to * nss_cms_decoder_work_data(). */static voidnss_cms_decoder_update_filter (void *arg, const char *data, unsigned long len,			  int depth, SEC_ASN1EncodingPart data_kind){    NSSCMSDecoderContext *p7dcx;    PORT_Assert (len);	/* paranoia */    if (len == 0)	return;    p7dcx = (NSSCMSDecoderContext*)arg;    p7dcx->saw_contents = PR_TRUE;    /* pass on the content bytes only */    if (data_kind == SEC_ASN1_Contents)	nss_cms_decoder_work_data(p7dcx, (const unsigned char *) data, len, PR_FALSE);}/* * NSS_CMSDecoder_Start - set up decoding of a DER-encoded CMS message * * "poolp" - pointer to arena for message, or NULL if new pool should be created * "cb", "cb_arg" - callback function and argument for delivery of inner content * "pwfn", pwfn_arg" - callback function for getting token password * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData */NSSCMSDecoderContext *NSS_CMSDecoder_Start(PRArenaPool *poolp,		      NSSCMSContentCallback cb, void *cb_arg,		      PK11PasswordFunc pwfn, void *pwfn_arg,		      NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg){    NSSCMSDecoderContext *p7dcx;    NSSCMSMessage *cmsg;    cmsg = NSS_CMSMessage_Create(poolp);    if (cmsg == NULL)	return NULL;    NSS_CMSMessage_SetEncodingParams(cmsg, pwfn, pwfn_arg, decrypt_key_cb, decrypt_key_cb_arg,					NULL, NULL);    p7dcx = (NSSCMSDecoderContext*)PORT_ZAlloc(sizeof(NSSCMSDecoderContext));    if (p7dcx == NULL) {	NSS_CMSMessage_Destroy(cmsg);	return NULL;    }    p7dcx->dcx = SEC_ASN1DecoderStart(cmsg->poolp, cmsg, NSSCMSMessageTemplate);    if (p7dcx->dcx == NULL) {	PORT_Free (p7dcx);	NSS_CMSMessage_Destroy(cmsg);	return NULL;    }    SEC_ASN1DecoderSetNotifyProc (p7dcx->dcx, nss_cms_decoder_notify, p7dcx);    p7dcx->cmsg = cmsg;    p7dcx->type = SEC_OID_UNKNOWN;    p7dcx->cb = cb;    p7dcx->cb_arg = cb_arg;    return p7dcx;}/* * NSS_CMSDecoder_Update - feed DER-encoded data to decoder */SECStatusNSS_CMSDecoder_Update(NSSCMSDecoderContext *p7dcx, const char *buf, unsigned long len){    if (p7dcx->dcx != NULL && p7dcx->error == 0) {	/* if error is set already, don't bother */	if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) {	    p7dcx->error = PORT_GetError();	    PORT_Assert (p7dcx->error);	    if (p7dcx->error == 0)		p7dcx->error = -1;	}    }    if (p7dcx->error == 0)	return SECSuccess;    /* there has been a problem, let's finish the decoder */    if (p7dcx->dcx != NULL) {	(void) SEC_ASN1DecoderFinish (p7dcx->dcx);	p7dcx->dcx = NULL;    }    PORT_SetError (p7dcx->error);    return SECFailure;}/* * NSS_CMSDecoder_Cancel - stop decoding in case of error */voidNSS_CMSDecoder_Cancel(NSSCMSDecoderContext *p7dcx){    /* XXXX what about inner decoders? running digests? decryption? */    /* XXXX there's a leak here! */    NSS_CMSMessage_Destroy(p7dcx->cmsg);    (void)SEC_ASN1DecoderFinish(p7dcx->dcx);    PORT_Free(p7dcx);}/* * NSS_CMSDecoder_Finish - mark the end of inner content and finish decoding */NSSCMSMessage *NSS_CMSDecoder_Finish(NSSCMSDecoderContext *p7dcx){    NSSCMSMessage *cmsg;    cmsg = p7dcx->cmsg;    if (p7dcx->dcx == NULL || SEC_ASN1DecoderFinish(p7dcx->dcx) != SECSuccess ||	nss_cms_after_end(p7dcx) != SECSuccess)    {	NSS_CMSMessage_Destroy(cmsg);	/* needs to get rid of pool if it's ours */	cmsg = NULL;    }    PORT_Free(p7dcx);    return cmsg;}NSSCMSMessage *NSS_CMSMessage_CreateFromDER(SECItem *DERmessage,		    NSSCMSContentCallback cb, void *cb_arg,		    PK11PasswordFunc pwfn, void *pwfn_arg,		    NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg){    NSSCMSDecoderContext *p7dcx;    /* first arg(poolp) == NULL => create our own pool */    p7dcx = NSS_CMSDecoder_Start(NULL, cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb, decrypt_key_cb_arg);    (void) NSS_CMSDecoder_Update(p7dcx, (char *)DERmessage->data, DERmessage->len);    return NSS_CMSDecoder_Finish(p7dcx);}

⌨️ 快捷键说明

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