📄 denv_cms.c
字号:
/****************************************************************************
* *
* cryptlib De-enveloping Routines *
* Copyright Peter Gutmann 1996-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "envelope.h"
#include "asn1_rw.h"
#include "asn1s_rw.h"
#include "objinfo.h"
#elif defined( INC_CHILD )
#include "envelope.h"
#include "../misc/asn1_rw.h"
#include "../misc/asn1s_rw.h"
#include "../misc/objinfo.h"
#else
#include "envelope/envelope.h"
#include "misc/asn1_rw.h"
#include "misc/asn1s_rw.h"
#include "misc/objinfo.h"
#endif /* Compiler-specific includes */
#ifdef USE_ENVELOPES
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* OID information used to read enveloped data */
static const FAR_BSS OID_SELECTION envelopeOIDselection[] = {
{ OID_CMS_DATA, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
{ OID_CMS_SIGNEDDATA, 0, 3, ACTION_SIGN },
{ OID_CMS_ENVELOPEDDATA, 0, 2, ACTION_KEYEXCHANGE },
{ OID_CMS_DIGESTEDDATA, 0, 2, ACTION_HASH },
{ OID_CMS_ENCRYPTEDDATA, 0, 2, ACTION_CRYPT },
{ OID_CMS_COMPRESSEDDATA, 0, 0, ACTION_COMPRESS },
{ OID_CMS_TSTOKEN, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
{ OID_MS_SPCINDIRECTDATACONTEXT, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
{ OID_CRYPTLIB_RTCSREQ, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
{ OID_CRYPTLIB_RTCSRESP, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
{ OID_CRYPTLIB_RTCSRESP_EXT, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_NONE },
{ NULL, 0, 0, 0 }
};
static const FAR_BSS OID_SELECTION nestedContentOIDselection[] = {
{ OID_CMS_DATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_DATA },
{ OID_CMS_SIGNEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_SIGNEDDATA },
{ OID_CMS_ENVELOPEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_ENVELOPEDDATA },
{ OID_CMS_ENCRYPTEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_ENCRYPTEDDATA },
{ OID_CMS_TSTOKEN, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_TSTINFO },
{ OID_CMS_COMPRESSEDDATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_COMPRESSEDDATA },
{ OID_MS_SPCINDIRECTDATACONTEXT, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_SPCINDIRECTDATACONTEXT },
{ OID_CRYPTLIB_RTCSREQ, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_RTCSREQUEST },
{ OID_CRYPTLIB_RTCSRESP, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_RTCSRESPONSE },
{ OID_CRYPTLIB_RTCSRESP_EXT, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_CONTENT_RTCSRESPONSE_EXT },
{ NULL, 0, 0, 0 }
};
/* Add information about an object to an envelope's content information list */
static int addContentListItem( STREAM *stream, ENVELOPE_INFO *envelopeInfoPtr,
QUERY_INFO *externalQueryInfoPtr )
{
QUERY_INFO queryInfo, *queryInfoPtr = ( externalQueryInfoPtr == NULL ) ? \
&queryInfo : externalQueryInfoPtr;
CONTENT_LIST *contentListItem;
void *object = NULL, *originalObjectPtr = sMemBufPtr( stream );
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
/* Find the size of the object, allocate a buffer for it, and copy it
across */
if( externalQueryInfoPtr == NULL )
{
status = queryAsn1Object( stream, queryInfoPtr );
if( cryptStatusError( status ) )
return( status );
if( queryInfoPtr->type == CRYPT_OBJECT_NONE )
{
/* It's a valid but unrecognised object type (a new
RecipientInfo type which 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 */
sSkip( stream, queryInfoPtr->size );
return( ( int ) queryInfoPtr->size );
}
if( ( object = clAlloc( "addContentListItem", \
( size_t ) queryInfoPtr->size ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
sread( stream, object, ( int ) queryInfoPtr->size );
}
/* Allocate memory for the new content list item and copy information on
the item across */
contentListItem = createContentListItem( envelopeInfoPtr->memPoolState,
queryInfoPtr->formatType, object,
( int ) queryInfoPtr->size,
queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE );
if( contentListItem == NULL )
{
if( externalQueryInfoPtr == NULL )
clFree( "addContentListItem", object );
return( CRYPT_ERROR_MEMORY );
}
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;
memcpy( encrInfo->saltOrIV, queryInfoPtr->iv, queryInfoPtr->ivLength );
encrInfo->saltOrIVsize = queryInfoPtr->ivLength;
}
if( queryInfoPtr->type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE )
{
/* Remember details of the enveloping info 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 )
{
contentListItem->issuerAndSerialNumber = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfoPtr->iAndSStart - \
( BYTE * ) originalObjectPtr );
contentListItem->issuerAndSerialNumberSize = queryInfoPtr->iAndSLength;
}
else
{
memcpy( contentListItem->keyID, queryInfoPtr->keyID,
queryInfoPtr->keyIDlength );
contentListItem->keyIDsize = queryInfoPtr->keyIDlength;
}
contentListItem->payload = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfoPtr->dataStart - \
( BYTE * ) originalObjectPtr );
contentListItem->payloadSize = queryInfoPtr->dataLength;
if( queryInfoPtr->type == CRYPT_OBJECT_SIGNATURE && \
queryInfoPtr->formatType == CRYPT_FORMAT_CMS && \
queryInfoPtr->unauthAttributeStart != NULL )
{
CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;
sigInfo->extraData2 = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfoPtr->unauthAttributeStart - \
( BYTE * ) originalObjectPtr );
sigInfo->extraData2Length = queryInfoPtr->unauthAttributeLength;
}
}
if( queryInfoPtr->type == CRYPT_OBJECT_ENCRYPTED_KEY )
{
CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;
/* Remember details of the enveloping info we require to continue */
if( queryInfoPtr->keySetupAlgo != CRYPT_ALGO_NONE )
{
contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
encrInfo->keySetupAlgo = queryInfoPtr->keySetupAlgo;
encrInfo->keySetupIterations = queryInfoPtr->keySetupIterations;
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;
contentListItem->payload = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfoPtr->dataStart - ( BYTE * ) originalObjectPtr );
contentListItem->payloadSize = queryInfoPtr->dataLength;
}
appendContentListItem( envelopeInfoPtr, contentListItem );
return( ( int ) queryInfoPtr->size );
}
/****************************************************************************
* *
* Process Envelope Preamble/Postamble *
* *
****************************************************************************/
/* Process the non-data portions of an envelope. This is a complex event-
driven state machine, but instead of reading along a (hypothetical
Turing-machine) tape, someone has taken the tape and cut it into bits and
keeps feeding them to us and saying "See what you can do with this" (and
occasionally "Where's the bloody spoons?"). The following code implements
this state machine.
Encr. with key exchange: SET_ENCR -> ENCR -> ENCRCONTENT -> DATA
Encr. with key agreement: "
Encr.: ENCRCONTENT -> DATA
Signed: SET_HASH -> HASH -> CONTENT -> DATA */
static int processPreamble( ENVELOPE_INFO *envelopeInfoPtr )
{
DEENV_STATE state = envelopeInfoPtr->deenvState;
STREAM stream;
int length, streamPos = 0, status = CRYPT_OK;
sMemConnect( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufPos );
/* If we haven't started doing anything yet, try and read the outer
header fields */
if( state == DEENVSTATE_NONE )
{
BYTE algoIDbuffer[ MAX_OID_SIZE ];
int algoIDlength;
/* Read the outer CMS header */
status = readCMSheader( &stream, envelopeOIDselection,
&envelopeInfoPtr->payloadSize, FALSE );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
/* Determine the next state to continue processing */
switch( status )
{
case ACTION_KEYEXCHANGE:
envelopeInfoPtr->usage = ACTION_CRYPT;
if( peekTag( &stream ) != 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 ) )
{
sMemDisconnect( &stream );
return( status );
}
}
state = DEENVSTATE_SET_ENCR;
break;
case ACTION_CRYPT:
envelopeInfoPtr->usage = ACTION_CRYPT;
state = DEENVSTATE_ENCRCONTENT;
break;
case ACTION_SIGN:
envelopeInfoPtr->usage = ACTION_SIGN;
state = DEENVSTATE_SET_HASH;
break;
case ACTION_COMPRESS:
/* With compressed data all we need to do is check that the
fixed AlgorithmIdentifier is present and set up the
decompression stream, after which we go straight to the
content */
envelopeInfoPtr->usage = ACTION_COMPRESS;
status = readRawObject( &stream, algoIDbuffer, &algoIDlength,
MAX_OID_SIZE, BER_SEQUENCE );
if( !cryptStatusError( status ) && \
( algoIDlength != sizeofOID( ALGOID_CMS_ZLIB ) || \
memcmp( algoIDbuffer, ALGOID_CMS_ZLIB, algoIDlength ) ) )
status = CRYPT_ERROR_BADDATA;
else
#ifdef USE_COMPRESSION
if( inflateInit( &envelopeInfoPtr->zStream ) == Z_OK )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -