📄 cms_denv.c
字号:
/****************************************************************************
* *
* cryptlib De-enveloping Routines *
* Copyright Peter Gutmann 1996-2008 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "envelope.h"
#include "asn1.h"
#include "asn1_ext.h"
#else
#include "envelope/envelope.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
#ifdef USE_ENVELOPES
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* OID information used to read enveloped data */
static const CMS_CONTENT_INFO FAR_BSS oidInfoSignedData = { 0, 3 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoEnvelopedData = { 0, 2 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoDigestedData = { 0, 2 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoEncryptedData = { 0, 2 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoCompressedData = { 0, 0 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoAuthData = { 0, 0 };
static const CMS_CONTENT_INFO FAR_BSS oidInfoAuthEnvData = { 0, 0 };
static const OID_INFO FAR_BSS envelopeOIDinfo[] = {
{ OID_CMS_DATA, ACTION_NONE },
{ OID_CMS_SIGNEDDATA, ACTION_SIGN, &oidInfoSignedData },
{ OID_CMS_ENVELOPEDDATA, ACTION_KEYEXCHANGE, &oidInfoEnvelopedData },
{ OID_CMS_DIGESTEDDATA, ACTION_HASH, &oidInfoDigestedData },
{ OID_CMS_ENCRYPTEDDATA, ACTION_CRYPT, &oidInfoEncryptedData },
{ OID_CMS_COMPRESSEDDATA, ACTION_COMPRESS, &oidInfoCompressedData },
{ OID_CMS_AUTHDATA, ACTION_MAC, &oidInfoAuthData },
{ OID_CMS_AUTHENVDATA, ACTION_MAC, &oidInfoAuthEnvData },
{ OID_CMS_TSTOKEN, ACTION_NONE },
{ OID_MS_SPCINDIRECTDATACONTEXT, ACTION_NONE },
{ OID_CRYPTLIB_RTCSREQ, ACTION_NONE },
{ OID_CRYPTLIB_RTCSRESP, ACTION_NONE },
{ OID_CRYPTLIB_RTCSRESP_EXT, ACTION_NONE },
{ NULL, 0 }, { NULL, 0 }
};
static const OID_INFO FAR_BSS nestedContentOIDinfo[] = {
{ OID_CMS_DATA, CRYPT_CONTENT_DATA },
{ OID_CMS_SIGNEDDATA, CRYPT_CONTENT_SIGNEDDATA },
{ OID_CMS_ENVELOPEDDATA, CRYPT_CONTENT_ENVELOPEDDATA },
{ OID_CMS_ENCRYPTEDDATA, CRYPT_CONTENT_ENCRYPTEDDATA },
{ OID_CMS_COMPRESSEDDATA, CRYPT_CONTENT_COMPRESSEDDATA },
{ OID_CMS_AUTHDATA, CRYPT_CONTENT_AUTHDATA },
{ OID_CMS_AUTHENVDATA, CRYPT_CONTENT_AUTHENVDATA },
{ OID_CMS_TSTOKEN, CRYPT_CONTENT_TSTINFO },
{ OID_MS_SPCINDIRECTDATACONTEXT, CRYPT_CONTENT_SPCINDIRECTDATACONTEXT },
{ OID_CRYPTLIB_RTCSREQ, CRYPT_CONTENT_RTCSREQUEST },
{ OID_CRYPTLIB_RTCSRESP, CRYPT_CONTENT_RTCSRESPONSE },
{ OID_CRYPTLIB_RTCSRESP_EXT, CRYPT_CONTENT_RTCSRESPONSE_EXT },
{ NULL, 0 }, { NULL, 0 }
};
/* Sanity-check the envelope state */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN sanityCheck( const ENVELOPE_INFO *envelopeInfoPtr )
{
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
/* Make sure that general envelope state is in order */
if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
return( FALSE );
if( envelopeInfoPtr->deenvState < DEENVSTATE_NONE || \
envelopeInfoPtr->deenvState >= DEENVSTATE_LAST )
return( FALSE );
/* Make sure that the buffer position is within bounds */
if( envelopeInfoPtr->buffer == NULL || \
envelopeInfoPtr->bufPos < 0 || \
envelopeInfoPtr->bufPos > envelopeInfoPtr->bufSize || \
envelopeInfoPtr->bufSize < MIN_BUFFER_SIZE || \
envelopeInfoPtr->bufSize >= MAX_INTLENGTH )
return( FALSE );
return( TRUE );
}
/* Add information about an object to an envelope's content information list.
The content information can be supplied in one of two ways, either
implicitly via the data in the stream or explicitly via a QUERY_INFO
structure */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
static int addContentListItem( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT_OPT STREAM *stream,
OUT_OPT QUERY_INFO *externalQueryInfoPtr,
OUT_LENGTH_SHORT_Z int *itemSize )
{
QUERY_INFO queryInfo, *queryInfoPtr = ( externalQueryInfoPtr == NULL ) ? \
&queryInfo : externalQueryInfoPtr;
CONTENT_LIST *contentListItem;
BYTE *contentListObjectPtr = NULL;
int objectSize = 0, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( ( stream == NULL && \
isWritePtr( externalQueryInfoPtr, sizeof( QUERY_INFO ) ) ) || \
( isWritePtr( stream, sizeof( STREAM ) ) && \
externalQueryInfoPtr == NULL ) );
assert( isWritePtr( itemSize, sizeof( int ) ) );
REQUIRES( ( stream == NULL && externalQueryInfoPtr != NULL ) || \
( stream != NULL && externalQueryInfoPtr == NULL ) );
/* Clear return value */
*itemSize = 0;
/* Make sure that there's room to add another list item */
if( !moreContentItemsPossible( envelopeInfoPtr->contentList ) )
return( CRYPT_ERROR_OVERFLOW );
/* Find the size of the object, allocate a buffer for it, and copy it
across */
if( externalQueryInfoPtr == NULL )
{
/* See what we've got. This call verifies that all of the object
data is present in the stream so in theory we don't have to check
the following reads, but we check them anyway just to be sure */
status = queryAsn1Object( stream, queryInfoPtr );
if( cryptStatusError( status ) )
return( status );
objectSize = ( int ) queryInfoPtr->size;
/* If it's a valid but unrecognised object type (a new RecipientInfo
type that was added after this version of cryptlib was released),
skip it and continue (if there are no recognised RecipientInfo
types, the code will automatically fall back to asking the user
for a raw session key). Alternatively, we could just add it to
the content list as an unrecognised object type, but this would
lead to confusion for the caller when non-object-types appear
when they query the current component */
if( queryInfoPtr->type == CRYPT_OBJECT_NONE )
{
status = sSkip( stream, objectSize );
if( cryptStatusError( status ) )
return( status );
*itemSize = objectSize;
return( CRYPT_OK );
}
/* Read the object data into memory */
if( ( contentListObjectPtr = clAlloc( "addContentListItem", \
objectSize ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
status = sread( stream, contentListObjectPtr, objectSize );
if( cryptStatusError( status ) )
{
clFree( "addContentListItem", contentListObjectPtr );
return( status );
}
}
ENSURES( ( externalQueryInfoPtr != NULL ) || \
( queryInfoPtr->size > 0 && \
queryInfoPtr->size < MAX_INTLENGTH ) );
/* If the query info is supplied externally it's a template that
doesn't correspond to any actual data */
/* Allocate memory for the new content list item and copy information on
the item across */
status = createContentListItem( &contentListItem,
envelopeInfoPtr->memPoolState, queryInfoPtr->formatType,
contentListObjectPtr, objectSize,
( queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE ) ? \
TRUE : FALSE );
if( cryptStatusError( status ) )
{
if( contentListObjectPtr == NULL )
clFree( "addContentListItem", contentListObjectPtr );
return( status );
}
if( externalQueryInfoPtr != NULL )
{
CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;
/* It's externally-supplied crypto algorithm details from an
encrypted data header */
contentListItem->envInfo = CRYPT_ENVINFO_SESSIONKEY;
encrInfo->cryptAlgo = queryInfoPtr->cryptAlgo;
encrInfo->cryptMode = queryInfoPtr->cryptMode;
if( queryInfoPtr->ivLength > 0 )
{
REQUIRES( queryInfoPtr->ivLength > 0 && \
queryInfoPtr->ivLength <= CRYPT_MAX_IVSIZE );
memcpy( encrInfo->saltOrIV, queryInfoPtr->iv,
queryInfoPtr->ivLength );
encrInfo->saltOrIVsize = queryInfoPtr->ivLength;
}
}
if( queryInfoPtr->type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE )
{
/* Remember the details of the enveloping info that we require to
continue */
if( queryInfoPtr->type == CRYPT_OBJECT_PKCENCRYPTED_KEY )
contentListItem->envInfo = CRYPT_ENVINFO_PRIVATEKEY;
else
{
contentListItem->envInfo = CRYPT_ENVINFO_SIGNATURE;
contentListItem->clSigInfo.hashAlgo = queryInfoPtr->hashAlgo;
}
if( queryInfoPtr->formatType == CRYPT_FORMAT_CMS )
{
REQUIRES( rangeCheck( queryInfoPtr->iAndSStart,
queryInfoPtr->iAndSLength, objectSize ) );
contentListItem->issuerAndSerialNumber = contentListObjectPtr + \
queryInfoPtr->iAndSStart;
contentListItem->issuerAndSerialNumberSize = queryInfoPtr->iAndSLength;
}
else
{
REQUIRES( queryInfoPtr->keyIDlength > 0 && \
queryInfoPtr->keyIDlength <= CRYPT_MAX_HASHSIZE );
memcpy( contentListItem->keyID, queryInfoPtr->keyID,
queryInfoPtr->keyIDlength );
contentListItem->keyIDsize = queryInfoPtr->keyIDlength;
}
REQUIRES( rangeCheck( queryInfoPtr->dataStart,
queryInfoPtr->dataLength, objectSize ) );
contentListItem->payload = contentListObjectPtr + \
queryInfoPtr->dataStart;
contentListItem->payloadSize = queryInfoPtr->dataLength;
if( queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE && \
queryInfoPtr->formatType == CRYPT_FORMAT_CMS && \
queryInfoPtr->unauthAttributeStart > 0 )
{
CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;
REQUIRES( rangeCheck( queryInfoPtr->unauthAttributeStart,
queryInfoPtr->unauthAttributeLength,
objectSize ) );
sigInfo->extraData2 = contentListObjectPtr + \
queryInfoPtr->unauthAttributeStart;
sigInfo->extraData2Length = queryInfoPtr->unauthAttributeLength;
}
}
if( queryInfoPtr->type == CRYPT_OBJECT_ENCRYPTED_KEY )
{
CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;
/* Remember the details of the enveloping info that we require to
continue */
if( queryInfoPtr->keySetupAlgo != CRYPT_ALGO_NONE )
{
contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
encrInfo->keySetupAlgo = queryInfoPtr->keySetupAlgo;
encrInfo->keySetupIterations = queryInfoPtr->keySetupIterations;
if( queryInfoPtr->saltLength > 0 )
{
REQUIRES( queryInfoPtr->saltLength > 0 && \
queryInfoPtr->saltLength <= CRYPT_MAX_HASHSIZE );
memcpy( encrInfo->saltOrIV, queryInfoPtr->salt,
queryInfoPtr->saltLength );
encrInfo->saltOrIVsize = queryInfoPtr->saltLength;
}
}
else
contentListItem->envInfo = CRYPT_ENVINFO_KEY;
encrInfo->cryptAlgo = queryInfoPtr->cryptAlgo;
encrInfo->cryptMode = queryInfoPtr->cryptMode;
REQUIRES( rangeCheck( queryInfoPtr->dataStart,
queryInfoPtr->dataLength, objectSize ) );
contentListItem->payload = contentListObjectPtr + \
queryInfoPtr->dataStart;
contentListItem->payloadSize = queryInfoPtr->dataLength;
}
appendContentListItem( envelopeInfoPtr, contentListItem );
*itemSize = ( int ) queryInfoPtr->size;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Header Processing Routines *
* *
****************************************************************************/
/* Process the outer CMS envelope header */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int processEnvelopeHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT STREAM *stream,
OUT_ENUM_OPT( DEENV_STATE ) DEENV_STATE *state )
{
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( state, sizeof( DEENV_STATE ) ) );
/* Clear return value */
*state = DEENVSTATE_NONE;
/* Read the outer CMS header */
status = readCMSheader( stream, envelopeOIDinfo,
FAILSAFE_ARRAYSIZE( envelopeOIDinfo, OID_INFO ),
&envelopeInfoPtr->payloadSize, FALSE );
if( cryptStatusError( status ) )
return( status );
/* Determine the next state to continue processing */
switch( status )
{
case ACTION_KEYEXCHANGE:
#ifdef USE_KEA
status = peekTag( stream );
if( cryptStatusError( status ) )
return( status );
if( status != BER_SET )
{
/* There may be key agreement data present, try and read the
start of the [0] IMPLICIT SEQUENCE { [0] SET OF Certificate } */
readConstructed( stream, NULL, 0 );
status = readConstructed( stream, NULL, 0 );
if( cryptStatusError( status ) )
return( status );
}
#endif /* USE_KEA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -