📄 readenv.c
字号:
/* Copyright 2003-2005, Voltage Security, all rights reserved.
*/
#include "vibe.h"
#include "environment.h"
#include "base.h"
#include "libctx.h"
#include "p7obj.h"
#include "reciplist.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;
do
{
/* The state must be VOLT_P7_STATE_ENV_READ_SET, if not, we're
* not allowed to call ReadInit.
*/
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;
status = VtCreateAlgorithmObject (
obj->voltObject.libraryCtx, VtAlgorithmImplBase64, (Pointer)&base64Info,
&(readCtx->base64));
if (status != 0)
break;
/* Create an empty identityList, we'll need it later.
*/
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;
status = 0;
} while (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, lengthLen, valueLen, messageRead, algorithm;
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 };
*bytesRead = 0;
*outputDataLen = 0;
switch (obj->state)
{
default:
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:
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 SignedData OID?
*/
status = VT_ERROR_INVALID_ENCODING;
offset = derElement->elementLen - derElement->tlvLen;
if (derElement->tlvLen != 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.
*/
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.
*/
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?
*/
status = VT_ERROR_UNSUPPORTED;
if (derElement->tlvLen != 1)
break;
offset = derElement->elementLen - derElement->tlvLen;
if (derElement->element[offset] != 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.
*/
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 = derElement->tlvLen;
/* 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;
VoltP7StateSignReadRiData:
case VOLT_P7_STATE_ENV_READ_RI_DATA:
/* Read in the next RecipientInfo.
*/
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.
*/
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 VoltP7StateSignReadRiData;
}
/* 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.
*/
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.
*/
status = VT_ERROR_CHOOSE_RECIPIENT;
if (readCtx->chosenRecipient < 0)
{
if (readCtx->priKeyRef == (VtKeyObject)0)
break;
/* We have a private key. Which identity belongs to that
* private key? We have to go through the recipInfos to find
* the ID matching the one passed in with the private key.
*/
status = VoltFindIdInList (
libCtx, readCtx->specifiedIdentity, readCtx->recipList, &index);
if (status != 0)
break;
/* Set the chosen recipient.
*/
readCtx->chosenRecipient = (int)index;
}
/* Build the symmetric decryption alg object and the symmetric
* key. This call will need to decrypt the session key in the
* RecipientInfo of the chosen recipient.
*/
status = DecryptSessionKeyData (libCtx, obj, readCtx);
if (status != 0)
break;
/* We have the session key data, set the state so we'll read
* encrypted content. Then check to see if there's any message to
* read.
*/
obj->state = VOLT_P7_STATE_ENV_READ_ENC_CONTENT;
if (messageLen == 0)
break;
case VOLT_P7_STATE_ENV_READ_ENC_CONTENT:
/* The first part of encrypted content is the SEQUENCE then an
* OID. "Cheat" by reading the SEQUENCE as the explicitTag.
*/
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 Data OID?
* First, set the buffer containing the OID to hold the Data OID.
*/
status = VT_ERROR_UNSUPPORTED;
p7Oid[VoltP7SignDataOidBytesLen - 1] = VOLT_P7_OID_BYTE_DATA;
offset = derElement->elementLen - derElement->tlvLen;
if (derElement->tlvLen != 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_SYM_ALG_ID;
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_ENV_READ_SYM_ALG_ID:
/* Read the symmetric algID.
*/
status = VoltGetNextDerElement (
libCtx, message, messageLen, 0, VOLT_SEQUENCE_TAG, 1,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* Build an algorithm object using the algId in the RecipientInfo.
*/
algIdInfo.derCoders = readCtx->DerCoders;
algIdInfo.derCoderCount = readCtx->derCoderCount;
algIdInfo.berEncoding = derElement->element;
algIdInfo.maxEncodingLen = derElement->elementLen;
status = VtCreateAlgorithmObject (
(VtLibCtx)libCtx, VtAlgorithmImplAlgId, (Pointer)&algIdInfo,
&(readCtx->decryptor));
if (status != 0)
break;
/* Get the KeyParam to use when building a key object. Do this by
* calling the DerCoder's asking for the algorithm.
*/
offset = derElement->elementLen - derElement->tlvLen;
status = VoltDecodeDerLength (
derElement->element + offset, derElement->elementLen - offset,
&lengthLen, &valueLen);
coderInfo.info.getAlgData.libCtx = libCtx;
coderInfo.info.getAlgData.oid =
derElement->element + offset + lengthLen + 1;
coderInfo.info.getAlgData.oidLen = valueLen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -