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 + -
显示快捷键?