📄 smread.c
字号:
/* Copyright 2003-2006, Voltage Security, all rights reserved.
*/
#include "vibe.h"
#include "environment.h"
#include "base.h"
#include "libctx.h"
#include "securemail.h"
#include "derhelp.h"
#include "errorctx.h"
/* Call DecodeUpdate, or DecodeFinal, place the result into
* readCtx->unprocessedData. If the buffer is not big enough, expand it.
* <p>The function will call Update or Final depending on the flag. If
* non-zero, do Update, if 0, do Final.
* <p>Upon return, the unprocessedData buffer contains the decoded
* material and unprocessedDataLen is the length.
*
* @param obj
* @param readCtx
* @param flag If non-zero, Update, if 0, Final.
* @param dataToDecode
* @param dataToDecodeLen
* @return an int, 0 if the function completed successfully or a
* non-zero error code.
*/
static int VOLT_CALLING_CONV DoDecodeUpdateOrFinal VOLT_PROTO_LIST ((
VoltSecureMailObject *obj,
VoltSecureMailReadCtx *readCtx,
unsigned int flag,
unsigned char *dataToDecode,
unsigned int dataToDecodeLen
));
/* There's data in the unprocessedData buffer, pass it to the Envelope
* object for a ReadUpdate.
* <p>The function will call Update or Final depending on the flag. If
* non-zero, do Update, if 0, do Final. If it calls FInal, it will call
* it with no data.
* <p>If the envelope object cannot read all the data because of
* VT_ERROR_CHOOSE_RECIPIENT, return that error and make sure the
* unprocessedData buffer contains any unread envelope data. That is,
* Memmove the unread data to the beginning of the buffer and set
* unprocessedDataLen. If this is the case, there will be no Envelope
* output.
* <p>This function will not return BUFFER_TOO_SMALL, because if
* there's any output, this routine will use any allocated space it
* already has or will allocate new space if needed.
* <p>Any error other than CHOOSE will be passed back to the caller.
* <p>If the return is 0, the function will have read all the input.
* <p>If the envelope object produces output, this function will place
* the output into the unprocessedData buffer. That is, upon successful
* completion, look in the unprocessedData buffer (length:
* unprocessedDataLen) for material that is to be passed to the
* SignedData object.
*/
static int VOLT_CALLING_CONV DoEnvelopeRead VOLT_PROTO_LIST ((
VoltSecureMailObject *obj,
VoltSecureMailReadCtx *readCtx,
unsigned int flag
));
/* Add the given data to the given byteArrayObj.
* <p>Append data. If there is already data there, place this new data
* on the end. This might require a realloc.
*
* @param obj
* @param byteArrayObj Where the new data will be placed.
* @param data The data to place.
* @param dataLen The length, in bytes of the data to place.
* @return an int, 0 if the function completed successfully or a
* non-zero error code.
*/
static int VOLT_CALLING_CONV StoreUnprocessedData VOLT_PROTO_LIST ((
VoltSecureMailObject *obj,
VoltByteArrayObj *byteArrayObj,
unsigned char *data,
unsigned int dataLen
));
/* Data was copied into the byteArrayCtx. The completeFlag indicates
* whether it was a complete content descriptor. The signRead is how
* many bytes were read out of the unprocessedData buffer of the
* readCtx.
* <p>This function will move the unprocessedData buffer by signRead
* bytes.
* <p>If the completeFlag indicates complete, the routine will check
* the contents to see if the descriptor copied is the last one. If it
* is not the last one, the function will increment the
* contentMaterialCount in the readCtx and set the contentMaterialState
* to ELEMENT. If it is the last one, the function will set the
* contentMaterialState to COMPLETE.
* <p>If the completeFlag is not complete, the function will set the
* contentMaterialState to PARTIAL.
* <p>If complete, the routine will pass the content to the P7
* SignedData object, but will not return the output to the
* application's output buffer.
*/
static int VOLT_CALLING_CONV ProcessContentDescriptor VOLT_PROTO_LIST ((
VoltSecureMailObject *obj,
VoltSecureMailReadCtx *readCtx,
VoltByteArrayObj *byteArrayObj,
unsigned int completeFlag,
unsigned int signRead
));
int VoltSecureMailReadInit (
VtSecureMailObject secureMailObj
)
{
int status;
VoltSecureMailObject *obj = (VoltSecureMailObject *)secureMailObj;
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
do
{
/* The state must be VOLT_SECURE_MAIL_STATE_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_SECURE_MAIL_STATE_READ_SET)
break;
/* Init the subordinate objects.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VtPkcs7ReadInit (obj->p7SignedData);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = VtPkcs7ReadInit (obj->p7EnvelopedData);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = VtDecodeInit (obj->base64);
if (status != 0)
break;
obj->state = VOLT_SECURE_MAIL_STATE_READ_INIT;
} while (0);
VOLT_LOG_ERROR_INFO_COMPARE (
status, 0, secureMailObj, status, 0, errorType,
(char *)0, "VoltSecureMailReadInit", fnctLine, (char *)0)
return (status);
}
#define VOLT_ZDM_MESSAGE_TYPE \
"<input type=\"hidden\" name=\"ZFRtype\" value=\"VoltageZFRDoc\">"
#define VOLT_ZDM_MESSAGE_TYPE_LEN 58
#define VOLT_ZDM_MESSAGE_START \
"<input type=\"hidden\" name=\"ZFRdata\" value=\""
#define VOLT_ZDM_MESSAGE_START_LEN 43
int VoltSecureMailReadUpdate (
VtSecureMailObject secureMailObj,
unsigned char *message,
unsigned int messageLen,
unsigned int *bytesRead,
unsigned char *outputData,
unsigned int bufferSize,
unsigned int *outputDataLen
)
{
int status;
unsigned int index, completeFlag, amountRead, currentMessageLen;
unsigned int inBlockLen, outBlockLen, leftovers, newLineLen;
unsigned int theTag, lengthLen, valueLen, preSpaceLen, flag;
#if VT_64_BIT_LENGTH == 64
VtUInt64 envelopeLen, inBlocks, outLen;
#else
unsigned int envelopeLen, inBlocks, outLen;
#endif
UInt32 lenLo, lenHi;
VoltSecureMailObject *obj = (VoltSecureMailObject *)secureMailObj;
VoltLibCtx *libCtx = (VoltLibCtx *)(obj->voltObject.libraryCtx);
VoltSecureMailReadCtx *readCtx = (VoltSecureMailReadCtx *)(obj->localCtx);
unsigned char *currentMessage;
unsigned char *beginMsg = VOLT_SECURE_MAIL_BEGIN_MESSAGE;
unsigned char *beginBlk = VOLT_SECURE_MAIL_BEGIN_BLOCK;
unsigned char *endBlk = VOLT_SECURE_MAIL_END_BLOCK;
unsigned char *endMsg = VOLT_SECURE_MAIL_END_MESSAGE;
unsigned char *zdmMessageType = VOLT_ZDM_MESSAGE_TYPE;
unsigned char *zdmMessageStart = VOLT_ZDM_MESSAGE_START;
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
*bytesRead = 0;
*outputDataLen = 0;
currentMessage = message;
currentMessageLen = messageLen;
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;
VoltSecureMailStateReadComplete:
case VOLT_SECURE_MAIL_STATE_READ_ENV_FINAL:
case VOLT_SECURE_MAIL_STATE_READ_SIGN_FINAL:
case VOLT_SECURE_MAIL_STATE_READ_P7_FINAL:
case VOLT_SECURE_MAIL_STATE_READ_COMPLETE:
/* If we're done, don't read anything. Actually, if this is ZDM,
* ignore any new data. Otherwise, the caller passed in too much
* data.
*/
status = 0;
if (currentMessageLen == 0)
break;
if ((obj->formatType & VOLT_MESSAGE_FORMAT_ZDM) != 0)
{
*bytesRead += currentMessageLen;
break;
}
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_SECURE_MAIL_MSG;
if (obj->formatType == VOLT_MESSAGE_FORMAT_SECURE_MAIL)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_SECURE_FILE_MSG;
break;
case VOLT_ZDM_STATE_READ_INIT:
/* With ZDM, the first thing to do will be to read the
* preliminary HTML info ... and ignore it.
*/
obj->formatType = VOLT_MESSAGE_FORMAT_ZDM_MAIL;
obj->state = VOLT_ZDM_STATE_READ_HEADER;
VoltZdmStateReadHeader:
case VOLT_ZDM_STATE_READ_HEADER:
/* Keep reading blocks of data until finding something we
* recognize.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltSMGetNextBlock (
obj, &(readCtx->unprocessedData), currentMessage, currentMessageLen,
9, &amountRead, &completeFlag, &newLineLen);
if (status != 0)
break;
*bytesRead += amountRead;
if (completeFlag == 0)
break;
currentMessage = message + *bytesRead;
currentMessageLen = messageLen - *bytesRead;
/* We have the next block in the unprocessedData buffer, is this
* the block that says this is a ZDM attachment?
* If not, is it the start of the data?
*/
if (readCtx->unprocessedData.len >= VOLT_ZDM_MESSAGE_TYPE_LEN)
{
if (Z2Memcmp (
readCtx->unprocessedData.data, zdmMessageType,
VOLT_ZDM_MESSAGE_TYPE_LEN) == 0)
obj->formatType = VOLT_MESSAGE_FORMAT_ZDM_ATTACHMENT;
}
if (readCtx->unprocessedData.len >= VOLT_ZDM_MESSAGE_START_LEN)
{
if (Z2Memcmp (
readCtx->unprocessedData.data, zdmMessageStart,
VOLT_ZDM_MESSAGE_START_LEN) == 0)
{
/* We've found the start, what's after the start line, a new
* line character or data. If new line, the beginning of the
* actual data is on a new line. If data, there was no
* carriage return inserted.
*/
if ( (readCtx->unprocessedData.data[VOLT_ZDM_MESSAGE_START_LEN] == 0x0d) ||
(readCtx->unprocessedData.data[VOLT_ZDM_MESSAGE_START_LEN] == 0x0a) )
{
readCtx->unprocessedData.len = 0;
}
else
{
/* If data, move the data to the beginning, we'll need to
* read it.
*/
Z2Memmove (
readCtx->unprocessedData.data,
readCtx->unprocessedData.data + VOLT_ZDM_MESSAGE_START_LEN,
readCtx->unprocessedData.len - VOLT_ZDM_MESSAGE_START_LEN);
readCtx->unprocessedData.len -= VOLT_ZDM_MESSAGE_START_LEN;
}
/* Now do we move on to reading SecureMail headers or actual
* data.
*/
if (obj->formatType == VOLT_MESSAGE_FORMAT_ZDM_MAIL)
{
/* This is MAIL, read SecureMail headers. Do we have the
* first one in the buffer already?
*/
obj->state = VOLT_SECURE_MAIL_STATE_READ_HEADER_1;
if (readCtx->unprocessedData.len == 0)
goto VoltSecureMailReadHeader1;
goto VoltSecureMailReadHeader1A;
}
/* This is a ZDM attachment, there are no headers.
* Do we have the first line of B64 in the buffer already?
*/
if (readCtx->unprocessedData.len == 0)
goto VoltSecureMailBase64;
obj->state = VOLT_SECURE_MAIL_STATE_READ_B64_LEN;
goto VoltSecureMailBase64A;
}
}
/* The line is not something expected, keep reading.
*/
readCtx->unprocessedData.len = 0;
goto VoltZdmStateReadHeader;
case VOLT_SECURE_MAIL_STATE_READ_INIT:
/* The first thing to do will be to read the first header.
*/
obj->state = VOLT_SECURE_MAIL_STATE_READ_HEADER_1;
VoltSecureMailReadHeader1:
case VOLT_SECURE_MAIL_STATE_READ_HEADER_1:
/* We're just starting to read the message. The first thing up
* should be
* -----BEGIN VOLTAGE MESSAGE BLOCK V1-----
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltSMGetNextBlock (
obj, &(readCtx->unprocessedData), currentMessage, currentMessageLen,
0, &amountRead, &completeFlag, &newLineLen);
if (status != 0)
break;
*bytesRead += amountRead;
if (completeFlag == 0)
break;
currentMessage = message + *bytesRead;
currentMessageLen = messageLen - *bytesRead;
/* We have the next block in the unprocessedData buffer, is this
* the block we expect?
* Remember, the VoltSMGetNextBlock function added a
* NULL-terminating character.
*/
VoltSecureMailReadHeader1A:
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_SECURE_MAIL_MSG;
if (readCtx->unprocessedData.len !=
VOLT_SECURE_MAIL_BEGIN_MESSAGE_LEN + newLineLen)
break;
if (Z2Memcmp (
readCtx->unprocessedData.data, beginMsg,
VOLT_SECURE_MAIL_BEGIN_MESSAGE_LEN) != 0)
break;
/* Set up the context for the next block.
*/
status = 0;
readCtx->unprocessedData.len = 0;
obj->state = VOLT_SECURE_MAIL_STATE_READ_HEADER_2;
obj->version = 1;
/* If there's no more message to read, return.
*/
if (currentMessageLen == 0)
break;
VoltSecureMailReadHeader2:
case VOLT_SECURE_MAIL_STATE_READ_HEADER_2:
/* At this point we should read an "extra" header or
* -----BEGIN VOLTAGE SECURE BLOCK V1-----
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VoltSMGetNextBlock (
obj, &(readCtx->unprocessedData), currentMessage, currentMessageLen,
9, &amountRead, &completeFlag, &newLineLen);
if (status != 0)
break;
*bytesRead += amountRead;
if (completeFlag == 0)
break;
currentMessage = message + *bytesRead;
currentMessageLen = messageLen - *bytesRead;
/* We have the next block in the unprocessedData buffer, is this
* an "extra" block or the second header?
* Note from the programmer: Notice the goto statement.
* Normally I don't like them, but in this case it really works.
*/
if (readCtx->unprocessedData.len ==
VOLT_SECURE_MAIL_BEGIN_BLOCK_LEN + newLineLen)
{
/* If this is the third header (no second header), skip to the
* next part of the read.
*/
if (Z2Memcmp (
readCtx->unprocessedData.data, beginBlk,
VOLT_SECURE_MAIL_BEGIN_BLOCK_LEN) == 0)
{
/* Set up for reading the next part.
*/
status = 0;
readCtx->unprocessedData.len = 0;
goto VoltSecureMailBase64 ;
}
}
/* This is an "extra" header, just Copy it to the extraHeader
* field in the context. Copy the NULL-terminating character as
* well.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_MEMORY;
readCtx->extraHeader.data = (unsigned char *)Z2Realloc (
readCtx->extraHeader.data, readCtx->unprocessedData.len + readCtx->extraHeader.len);
if (readCtx->extraHeader.data == (unsigned char *)0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -