📄 readsign.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 "certobj.h"
#include "vcert.h"
#include "certvfyctx.h"
#include "distobj.h"
#include "vtime.h"
#include "digest.h"
/* Decode each of the attributes in the authAttributes field of the
* given signerInfo. This function will build an array of
* Asn1P9Attribute pointers, as many pointers as are authenticate
* attributes. It will then create (Asn1P9Attribute_new) the objects
* and decode (d2i_Asn1P9Attribute) each of the attributes. It will
* return the array and the count.
* <p>The caller must destroy each of the objects (Asn1P9Attribute_free)
* and free the memory that is the array.
*
* @param libCtx The libCtx to use.
* @param signerInfo The specific signerInfo from which the
* authenticated attributes are to be extracted.
* @param attributes The address where this function will deposit the
* created array.
* @param attributeCount The address where this function will deposit
* the number of Asn1P9Attribute objects it created.
* @return an int, 0 if the function completed successfully or a
* non-zero error code.
*/
static int VOLT_CALLING_CONV DecodeAuthAttributesAlloc VOLT_PROTO_LIST ((
VoltLibCtx *libCtx,
Asn1SignerInfo *signerInfo,
Asn1P9Attribute ***attributes,
unsigned int *attributeCount
));
/* This function finds the attribute in the array that matches the
* given flag, then compares the value in the attribute object with the
* given baseValue. If there is no attribute to match or if the value
* does not compare equally to the baseValue, the routine returns
* VT_ERROR_INVALID_ENCODING.
* <p>This function also expects that the attribute has only one value
* (a P9 attribute is actually a SET OF values) and that the value is
* an "atomic" ASN.1 type (an OID or OCTET STRING, for example).
* <p>The flag indicates what to look for. Currently, the following are
* supported.
*
* VOLT_P9_ATTRIBUTE_CONTENT_TYPE
* VOLT_P9_ATTRIBUTE_DIGEST
*
* @param libCtx The libCtx to use.
* @param flag What attribute to search for.
* @param attributes The array to search.
* @param attributeCount The number of attributes in the array.
* @param baseValue The value to match.
* @param baseValueLen The length, in bytes, of the baseValue.
* @return an int, 0 if the function completed successfully or a
* non-zero error code.
*/
static int VOLT_CALLING_CONV VerifyAuthAttribute VOLT_PROTO_LIST ((
VoltLibCtx *libCtx,
unsigned int flag,
Asn1P9Attribute **attributes,
unsigned int attributeCount,
unsigned char *baseValue,
unsigned int baseValueLen
));
#define VOLT_P9_ATTRIBUTE_CONTENT_TYPE 3
#define VOLT_P9_ATTRIBUTE_DIGEST 4
/* This function looks through the array of attributes until finding
* the one with the given OID. If it can't find an attribute with that
* OID, it returns the INVALID_ENCODING_ERROR.
* <p>The function sets the unsigned int at the address index to the
* index in the array of the attribute with the matching OID.
* <p>This function does no arg checking, it assumes a valid array and
* valid OID to check.
*
* @param libCtx The libCtx to use.
* @param oid The OID to match.
* @param oidLen The length, in bytes, of the OID.
* @param attributes The array to search.
* @param attributeCount The number of attributes in the array.
* @param index The address where the routine will deposit the index
* into the array of the attribute with the matching OID.
* @return an int, 0 if the function completed successfully or a
* non-zero error code.
*/
static int VOLT_CALLING_CONV FindAuthAttribute VOLT_PROTO_LIST ((
VoltLibCtx *libCtx,
unsigned char *oid,
unsigned int oidLen,
Asn1P9Attribute **attributes,
unsigned int attributeCount,
unsigned int *index
));
/* Build a cert object from the encoding, then add it to the list of
* msgCerts in the readCtx. This function will grow the array of
* msgCerts, if necessary.
*/
static int VOLT_CALLING_CONV AddCertToList VOLT_PROTO_LIST ((
VoltLibCtx *libCtx,
VoltPkcs7ReadSignCtx *readCtx,
unsigned char *certDer,
unsigned int certDerLen
));
/* Build a SignerInfo object from the encoding, then add it to the
* list of signerInfos in the readCtx. This function will grow the
* array of signerInfos, if necessary.
*/
static int VOLT_CALLING_CONV AddSignerInfoToList VOLT_PROTO_LIST ((
VoltLibCtx *libCtx,
VoltPkcs7ReadSignCtx *readCtx,
unsigned char *encoding,
unsigned int encodingLen
));
int VoltP7ReadSignedInit (
VtPkcs7Object pkcs7Obj
)
{
int status;
VoltPkcs7Object *obj = (VoltPkcs7Object *)pkcs7Obj;
do
{
/* The state must be VOLT_P7_STATE_SIGN_READ_SET, if not, we're
* not allowed to call ReadInit.
*/
status = VT_ERROR_INVALID_CALL_ORDER;
if (obj->state != VOLT_P7_STATE_SIGN_READ_SET)
break;
/* Set the state to INIT.
*/
obj->state = VOLT_P7_STATE_SIGN_READ_INIT;
status = 0;
} while (0);
return (status);
}
int VoltP7ReadSignedUpdate (
VtPkcs7Object pkcs7Obj,
unsigned char *message,
unsigned int messageLen,
unsigned int *bytesRead,
unsigned char *outputData,
unsigned int bufferSize,
unsigned int *outputDataLen
)
{
int status;
unsigned int offset, messageRead, length;
VoltPkcs7Object *obj = (VoltPkcs7Object *)pkcs7Obj;
VoltPkcs7ReadSignCtx *readCtx = (VoltPkcs7ReadSignCtx *)(obj->localCtx);
VoltLibCtx *libCtx = (VoltLibCtx *)(obj->voltObject.libraryCtx);
VoltDerElement *derElement = &(readCtx->currentElement);
unsigned char p7Oid[VoltP7SignDataOidBytesLen] = { VoltP7SignDataOidBytes };
VtSetAlgIdInfo algIdInfo;
*bytesRead = 0;
*outputDataLen = 0;
switch (obj->state)
{
default:
status = VT_ERROR_INVALID_CALL_ORDER;
break;
case VOLT_P7_STATE_SIGN_READ_COMPLETE:
/* If we're done, don't read anything.
*/
status = 0;
break;
case VOLT_P7_STATE_SIGN_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.
*/
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 != VoltP7SignDataOidBytesLen)
break;
if (Z2Memcmp (
p7Oid, derElement->element + offset, VoltP7SignDataOidBytesLen) != 0)
break;
obj->state = VOLT_P7_STATE_SIGN_READ_SD_OID;
/* Move on to the next element.
*/
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_SIGN_READ_SD_OID:
/* We now have the SignedData. 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;
obj->state = VOLT_P7_STATE_SIGN_READ_EXP_1;
/* Move on to the next element.
*/
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_SIGN_READ_EXP_1:
/* 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] != 1)
break;
obj->state = VOLT_P7_STATE_SIGN_READ_VERSION;
/* Move on to the next element.
*/
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_SIGN_READ_VERSION:
/* Next up is the SET OF digest algorithm ID's. This
* implementation can operate with only one digest algorithm.
* "Cheat" a little bit, pass the SET OF tag as the explicitTag,
* and the SEQUENCE as the tag. We'll get the SET OF as the
* explicit and the contents of the first (presumably only)
* digest algID in the element buffer.
*/
status = VoltGetNextDerElement (
libCtx, message, messageLen, VOLT_SET_TAG, VOLT_SEQUENCE_TAG, 1,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* Make sure there's only one digest alg. If more than one, error.
*/
status = VT_ERROR_UNSUPPORTED;
if (derElement->explicitLen != derElement->elementLen)
break;
/* Build a digest object from this
*/
algIdInfo.derCoders = readCtx->DerCoders;
algIdInfo.derCoderCount = readCtx->derCoderCount;
algIdInfo.berEncoding = derElement->element;
algIdInfo.maxEncodingLen = derElement->elementLen;
status = VtCreateAlgorithmObject (
(VtLibCtx)libCtx, VtAlgorithmImplAlgId, (Pointer)&algIdInfo,
&(readCtx->digestObj));
if (status != 0)
break;
obj->state = VOLT_P7_STATE_SIGN_READ_DIGEST;
/* Move on to the next element.
*/
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_SIGN_READ_DIGEST:
/* Now read the contentInfo, the data to verify. Start with the
* SEQUENCE and OID. Do this by "cheating", setting the
* explicitTag to the SEQUENCE, thereby capturing both the
* SEQUENCE tag and the first element, the 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 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 != VoltP7SignDataOidBytesLen)
break;
if (Z2Memcmp (
p7Oid, derElement->element + offset, VoltP7SignDataOidBytesLen) != 0)
break;
/* Copy this OID into the readCtx.
*/
status = VT_ERROR_MEMORY;
readCtx->contentOid = (unsigned char *)Z2Realloc (
readCtx->contentOid, VoltP7SignDataOidBytesLen);
if (readCtx->contentOid == (unsigned char *)0)
break;
Z2Memcpy (readCtx->contentOid, p7Oid, VoltP7SignDataOidBytesLen);
readCtx->contentOidLen = VoltP7SignDataOidBytesLen;
obj->state = VOLT_P7_STATE_SIGN_READ_DATA_OID;
/* Move on to the next element.
*/
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_SIGN_READ_DATA_OID:
/* We expect to see an EXPLICIT then OCTET STRING.
*/
status = VoltGetNextDerElement (
libCtx, message, messageLen, 0xA0, VOLT_OCTET_STRING_TAG, 0,
derElement, &messageRead);
if (status != 0)
break;
*bytesRead += messageRead;
if (derElement->complete == 0)
break;
/* We'll now start reading data. How much data is there to read?
*/
readCtx->currentLen = derElement->tlvLen;
obj->state = VOLT_P7_STATE_SIGN_READ_DATA_S;
status = VtDigestInit (readCtx->digestObj);
if (status != 0)
break;
/* Move on to the next element.
*/
message += messageRead;
messageLen -= messageRead;
VoltResetDerElement (derElement);
if (messageLen == 0)
break;
case VOLT_P7_STATE_SIGN_READ_DATA_S:
/* How many of the bytes are to be output?
*/
length = readCtx->currentLen;
if (messageLen < readCtx->currentLen)
length = messageLen;
status = VT_ERROR_BUFFER_TOO_SMALL;
*outputDataLen = length;
if (bufferSize < length)
break;
/* Digest the data.
*/
status = VtDigestUpdate (
readCtx->digestObj, message, length);
if (status != 0)
break;
Z2Memcpy (outputData, message, length);
*bytesRead += length;
message += length;
messageLen -= length;
readCtx->currentLen -= length;
/* If we're expecting more data, we're done with Update. If not,
* finish this call so the caller can call Update again.
*/
if (readCtx->currentLen != 0)
break;
/* We've processed all the data to verify. Complete the digest.
*/
obj->state = VOLT_P7_STATE_SIGN_READ_DATA_F;
status = VtDigestFinal (
readCtx->digestObj, (unsigned char *)0, 0,
(unsigned char *)0, 0, &(readCtx->digestLen));
if (status == 0)
status = VT_ERROR_GENERAL;
if (status != VT_ERROR_BUFFER_TOO_SMALL)
break;
status = VT_ERROR_MEMORY;
readCtx->digest = (unsigned char *)Z2Realloc (
readCtx->digest, readCtx->digestLen);
if (readCtx->digest == (unsigned char *)0)
break;
status = VtDigestFinal (
readCtx->digestObj, (unsigned char *)0, 0,
readCtx->digest, readCtx->digestLen, &(readCtx->digestLen));
if (status != 0)
break;
obj->state = VOLT_P7_STATE_SIGN_READ_DATA_S;
if (messageLen == 0)
break;
case VOLT_P7_STATE_SIGN_READ_DATA_F:
/* Next come the certs. Actually, they're OPTIONAL, so they may
* not be there.
*/
if (message[0] != 0xA0)
{
/* If no certs, check to see if there are any CRL's. If there
* are CRL's, consider the state to be the state it would be if
* we had just finished reading all the certs and confirmed
* that there are CRL's. If there are no CRL's, consider the
* state to be the state it would be if we had just finished
* reading all the CRL's.
* Note from the programmer: Notice the goto statement.
* Normally I don't like them, but in this case it really works.
*/
if (message[0] == 0xA1)
{
obj->state = VOLT_P7_STATE_SIGN_READ_CRL_L;
goto VoltP7StateSignReadCrlLen;
}
obj->state = VOLT_P7_STATE_SIGN_READ_CRLS;
goto VoltP7StateSignReadCrls;
}
obj->state = VOLT_P7_STATE_SIGN_READ_CERT_L;
case VOLT_P7_STATE_SIGN_READ_CERT_L:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -