📄 readenv.c
字号:
/* Copyright 2003-2006, Voltage Security, all rights reserved.
*/
#include "vibe.h"
#include "environment.h"
#include "base.h"
#include "libctx.h"
#include "p7obj.h"
#include "reciplist.h"
#include "idobj.h"
#include "errorctx.h"
/* Build an Asn1RecipientInfo object from the encoding, then add it to
* the list of recipInfos in the readCtx. This function will grow the
* array of recipInfos, if necessary.
* <p>This function will also add the identity represented by the
* recipientInfo to the identity list in the readCtx.
*/
static int VOLT_CALLING_CONV AddRecipientInfoToList VOLT_PROTO_LIST ((
VoltLibCtx *libCtx,
VoltPkcs7ReadEnvCtx *readCtx,
unsigned char *recipInfoDer,
unsigned int recipInfoDerLen
));
/* The readCtx contains a private key with which to decrypt the session
* key. It also contains the index of the chosen recipient. Go into the
* RecipientInfo of that index to find the algorithm to use (algID) and
* the encrypted key data. Decrypt the data and store it in the
* symKeyData field of the readCtx.
*/
static int VOLT_CALLING_CONV DecryptSessionKeyData VOLT_PROTO_LIST ((
VoltLibCtx *libCtx,
VoltPkcs7Object *obj,
VoltPkcs7ReadEnvCtx *readCtx
));
int VoltP7ReadEnvelopedInit (
VtPkcs7Object pkcs7Obj
)
{
int status;
VoltPkcs7Object *obj = (VoltPkcs7Object *)pkcs7Obj;
VoltPkcs7ReadEnvCtx *readCtx = (VoltPkcs7ReadEnvCtx *)(obj->localCtx);
VtBase64Info base64Info;
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
do
{
/* The state must be VOLT_P7_STATE_ENV_READ_SET, if not, we're
* not allowed to call ReadInit.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_CALL_ORDER;
if (obj->state != VOLT_P7_STATE_ENV_READ_SET)
break;
/* Build a Base64 object, we'll need it later and we might as build
* one, rather than building a new one again and again.
*/
base64Info.base64BlockSize = 76;
base64Info.newLineCharacter = VT_BASE64_NO_NEW_LINE;
base64Info.errorCheck = VT_BASE64_NO_ERROR_CHECK;
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VtCreateAlgorithmObject (
obj->voltObject.libraryCtx, VtAlgorithmImplBase64, (Pointer)&base64Info,
&(readCtx->base64));
if (status != 0)
break;
/* Create an empty identityList, we'll need it later.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = VtCreateIdentityList (
obj->voltObject.libraryCtx, VtIdentityListImplMpCtx,
(Pointer)(readCtx->mpCtx), &(readCtx->recipList));
if (status != 0)
break;
/* Set the state to INIT.
*/
obj->state = VOLT_P7_STATE_ENV_READ_INIT;
} while (0);
VOLT_LOG_ERROR_INFO_COMPARE (
status, 0, pkcs7Obj, status, 0, errorType,
(char *)0, "VoltP7ReadEnvelopedInit", fnctLine, (char *)0)
return (status);
}
int VoltP7ReadEnvelopedUpdate (
VtPkcs7Object pkcs7Obj,
unsigned char *message,
unsigned int messageLen,
unsigned int *bytesRead,
unsigned char *outputData,
unsigned int bufferSize,
unsigned int *outputDataLen
)
{
int status;
unsigned int index, offset, theTag, lengthLen, valueLen;
unsigned int messageRead, algorithm;
UInt32 lenLo, lenHi;
VoltPkcs7Object *obj = (VoltPkcs7Object *)pkcs7Obj;
VoltPkcs7ReadEnvCtx *readCtx = (VoltPkcs7ReadEnvCtx *)(obj->localCtx);
VoltLibCtx *libCtx = (VoltLibCtx *)(obj->voltObject.libraryCtx);
VtKeyObject symKey = (VtKeyObject)0;
VoltDerElement *derElement = &(readCtx->currentElement);
VtSetAlgIdInfo algIdInfo;
VtDerCoderInfo coderInfo;
unsigned char p7Oid[VoltP7EnvDataOidBytesLen] = { VoltP7EnvDataOidBytes };
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
*bytesRead = 0;
*outputDataLen = 0;
switch (obj->state)
{
default:
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_CALL_ORDER;
break;
case VOLT_P7_STATE_ENV_READ_COMPLETE:
/* If we're done, don't read anything.
*/
status = 0;
break;
case VOLT_P7_STATE_ENV_READ_INIT:
/* The first thing to do is read the ContentInfo SEQUENCE.
* "Cheat" a little bit and set the explicitTag to the outer
* SEQUENCE, then we can capture the SEQUENCE and the OID at the
* same time.
*/
obj->state = VOLT_P7_STATE_ENV_READ_ED_OID;
case VOLT_P7_STATE_ENV_READ_ED_OID:
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltGetNextDerElement (
libCtx, message, messageLen, VOLT_SEQUENCE_TAG, VOLT_OID_TAG, 1,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* Is this the EnvelopedData OID?
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_ENCODING;
offset = (unsigned int)(derElement->elementLen - derElement->valueLen);
if (derElement->valueLen != VoltP7EnvDataOidBytesLen)
break;
if (Z2Memcmp (
p7Oid, derElement->element + offset, VoltP7EnvDataOidBytesLen) != 0)
break;
/* Move on to the next element.
*/
status = 0;
obj->state = VOLT_P7_STATE_ENV_READ_EXP;
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_ENV_READ_EXP:
/* We now have the EnvelopedData. It starts with the EXPLICIT.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltGetNextDerElement (
libCtx, message, messageLen, 0xA0, VOLT_SEQUENCE_TAG, 0,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* Move on to the next element.
*/
obj->state = VOLT_P7_STATE_ENV_READ_VERSION;
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_ENV_READ_VERSION:
/* Now it's the version.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltGetNextDerElement (
libCtx, message, messageLen, 0, VOLT_INTEGER_TAG, 1,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* Is this the expected version?
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_UNSUPPORTED;
if (derElement->valueLen != 1)
break;
VOLT_SET_FNCT_LINE (fnctLine)
if (derElement->element[2] != 0)
break;
/* Move on to the next element.
*/
status = 0;
obj->state = VOLT_P7_STATE_ENV_READ_RI_LEN;
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_ENV_READ_RI_LEN:
/* The next element is the SET OF RecipientInfos. Get the SET OF
* length.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltGetNextDerElement (
libCtx, message, messageLen, 0, VOLT_SET_TAG, 0,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* Keep the length around so we know when we have no more
* RecipientInfos.
*/
readCtx->currentLen = (unsigned int)(derElement->valueLen);
/* Move on to the next element.
*/
obj->state = VOLT_P7_STATE_ENV_READ_RI_DATA;
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
VoltP7StateEnvelopeReadRiData:
case VOLT_P7_STATE_ENV_READ_RI_DATA:
/* Read in the next RecipientInfo.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltGetNextDerElement (
libCtx, message, messageLen, 0, VOLT_SEQUENCE_TAG, 1,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* We kept the total length of all the RecipientInfos, now that
* we've read one, subtract its length from the total.
*/
readCtx->currentLen -= derElement->elementLen;
/* Add this RecipientInfo to the list of RecipientInfos.
* If this subroutine can't decode the identity, just ignore it.
* So if the error is INVALID_ENCODING or UNKNOWN_SCHEMA, don't
* bail, just move on. Return other errors, but if there's an
* unknown identity, it's probably not one the app is interest in.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = AddRecipientInfoToList (
libCtx, readCtx, derElement->element, derElement->elementLen);
if ( (status == VT_ERROR_INVALID_ENCODING) ||
(status == VT_ERROR_UNKNOWN_SCHEMA) )
status = 0;
if (status != 0)
break;
/* Move on to the next element.
*/
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
/* There may be more RecipientInfos, check readCtx->currentLen to
* see. If there are no more, move on to PREPARE_ENC, whether or
* not there is more message to read. If there are more
* recipientInfos, make sure there's still more message, then go
* back to the start of this state.
* Note from the programmer: Notice the goto statement.
* Normally I don't like them, but in this case it really works.
*/
if (readCtx->currentLen != 0)
{
if (messageLen == 0)
break;
goto VoltP7StateEnvelopeReadRiData;
}
/* If that was the last RecipientInfo, make sure we were actually
* able to read at least one, then set the state to indicate
* we're moving on to the next element.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_NO_ID_IN_P7_MESSAGE;
if (readCtx->recipInfoCount == 0)
break;
obj->state = VOLT_P7_STATE_ENV_READ_PREPARE_ENC;
case VOLT_P7_STATE_ENV_READ_PREPARE_ENC:
/* In order to read the encrypted content, we need the decryption
* object and decryption key. In order to get the decryption key
* we need to decrypt the encrypted key from one of the
* recipientInfos. If we have one chosen, decrypt. If not, we may
* be able to choose one if we have the private key to use
* already.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -