📄 res_denv.c
字号:
/****************************************************************************
* *
* cryptlib De-enveloping Information Management *
* Copyright Peter Gutmann 1996-2008 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "envelope.h"
#include "asn1.h"
#include "asn1_ext.h"
#include "pgp.h"
#else
#include "envelope/envelope.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#include "misc/pgp.h"
#endif /* Compiler-specific includes */
/* The maximum number of content items that we can add to a content list.
We should use FAILSAFE_ITERATIONS_MED but encrypted messages sent to very
large distribution lists can have a number of per-recipient wrapped keys
that exceed this value */
#define MAX_CONTENT_ITEMS FAILSAFE_ITERATIONS_LARGE - 1
#ifdef USE_ENVELOPES
/****************************************************************************
* *
* Content List Management Functions *
* *
****************************************************************************/
/* Check whether more content items can be added to a content list */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN moreContentItemsPossible( const CONTENT_LIST *contentListPtr )
{
int contentListCount;
assert( contentListPtr == NULL || \
isReadPtr( contentListPtr, sizeof( ACTION_LIST ) ) );
for( contentListCount = 0;
contentListPtr != NULL && contentListCount < FAILSAFE_ITERATIONS_LARGE;
contentListPtr = contentListPtr->next, contentListCount++ );
ENSURES_B( contentListCount < FAILSAFE_ITERATIONS_LARGE );
return( ( contentListCount < MAX_CONTENT_ITEMS ) ? TRUE : FALSE );
}
/* Create a content list item */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int createContentListItem( OUT_PTR CONTENT_LIST **newContentListItemPtrPtr,
INOUT MEMPOOL_STATE memPoolState,
IN_ENUM( CRYPT_FORMAT ) \
const CRYPT_FORMAT_TYPE formatType,
IN_BUFFER_OPT( objectSize ) const void *object,
IN_LENGTH_Z const int objectSize,
const BOOLEAN isSigObject )
{
CONTENT_LIST *newItem;
assert( isWritePtr( newContentListItemPtrPtr, \
sizeof( CONTENT_LIST * ) ) );
assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
assert( objectSize == 0 || isReadPtr( object, objectSize ) );
REQUIRES( formatType > CRYPT_FORMAT_NONE && \
formatType < CRYPT_FORMAT_LAST );
REQUIRES( ( object == NULL && objectSize == 0 ) || \
( object != NULL && \
objectSize > 0 && objectSize < MAX_INTLENGTH ) );
if( ( newItem = getMemPool( memPoolState, \
sizeof( CONTENT_LIST ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memset( newItem, 0, sizeof( CONTENT_LIST ) );
newItem->formatType = formatType;
newItem->object = object;
newItem->objectSize = objectSize;
if( isSigObject )
{
newItem->flags = CONTENTLIST_ISSIGOBJ;
newItem->clSigInfo.iSigCheckKey = CRYPT_ERROR;
newItem->clSigInfo.iExtraData = CRYPT_ERROR;
newItem->clSigInfo.iTimestamp = CRYPT_ERROR;
}
*newContentListItemPtrPtr = newItem;
return( CRYPT_OK );
}
/* Add an item to the content list */
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void appendContentListItem( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT CONTENT_LIST *contentListItem )
{
CONTENT_LIST *contentListPtr = envelopeInfoPtr->contentList;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( contentListPtr == NULL || \
isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
/* Find the end of the list and add the new item */
if( contentListPtr != NULL )
{
int iterationCount = 0;
for( contentListPtr = envelopeInfoPtr->contentList, \
iterationCount = 0;
contentListPtr->next != NULL && \
iterationCount < FAILSAFE_ITERATIONS_LARGE;
contentListPtr = contentListPtr->next, iterationCount++ );
ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_LARGE );
}
insertDoubleListElements( &envelopeInfoPtr->contentList, contentListPtr,
contentListItem, contentListItem );
}
/* Delete a content list */
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void deleteContentList( INOUT MEMPOOL_STATE memPoolState,
INOUT_PTR CONTENT_LIST **contentListHeadPtrPtr )
{
CONTENT_LIST *contentListCursor;
int iterationCount;
assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
assert( isWritePtr( contentListHeadPtrPtr, sizeof( CONTENT_LIST * ) ) );
for( contentListCursor = *contentListHeadPtrPtr, iterationCount = 0;
contentListCursor != NULL && \
iterationCount < FAILSAFE_ITERATIONS_LARGE;
iterationCount++ )
{
CONTENT_LIST *contentListItem = contentListCursor;
contentListCursor = contentListCursor->next;
/* Destroy any attached objects if necessary */
if( contentListItem->flags & CONTENTLIST_ISSIGOBJ )
{
CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;
if( sigInfo->iSigCheckKey != CRYPT_ERROR )
krnlSendNotifier( sigInfo->iSigCheckKey, IMESSAGE_DECREFCOUNT );
if( sigInfo->iExtraData != CRYPT_ERROR )
krnlSendNotifier( sigInfo->iExtraData, IMESSAGE_DECREFCOUNT );
if( sigInfo->iTimestamp != CRYPT_ERROR )
krnlSendNotifier( sigInfo->iTimestamp, IMESSAGE_DECREFCOUNT );
}
/* Erase and free the object buffer if necessary */
deleteDoubleListElement( contentListHeadPtrPtr, contentListItem );
if( contentListItem->object != NULL )
{
/* Clear the object. We have to cheat a bit here with pointer
casting, the 'const' indicates that the object data is never
modified while it's in the content list but it has to be
modified in a manner of speaking when we delete it */
zeroise( ( void * ) contentListItem->object,
contentListItem->objectSize );
clFree( "deleteContentList", ( void * ) contentListItem->object );
}
zeroise( contentListItem, sizeof( CONTENT_LIST ) );
freeMemPool( memPoolState, contentListItem );
}
ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_LARGE );
*contentListHeadPtrPtr = NULL;
}
/****************************************************************************
* *
* Process Signature Data *
* *
****************************************************************************/
/* Process timestamps */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int processTimestamp( INOUT CONTENT_LIST *contentListPtr,
IN_BUFFER( timestampLength ) const void *timestamp,
IN_LENGTH_MIN( MIN_CRYPT_OBJECTSIZE ) \
const int timestampLength )
{
CRYPT_ENVELOPE iTimestampEnvelope;
MESSAGE_CREATEOBJECT_INFO createInfo;
MESSAGE_DATA msgData;
const int bufSize = max( timestampLength + 128, MIN_BUFFER_SIZE );
int status;
assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
assert( isReadPtr( timestamp, timestampLength ) );
REQUIRES( timestampLength >= MIN_CRYPT_OBJECTSIZE && \
timestampLength < MAX_INTLENGTH );
/* Create an envelope to contain the timestamp data. We can't use the
internal enveloping API for this because we want to retain the final
envelope and not just recover the data contents (which for a
timestamp will be empty anyway) */
setMessageCreateObjectInfo( &createInfo, CRYPT_FORMAT_AUTO );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_ENVELOPE );
if( cryptStatusError( status ) )
return( status );
iTimestampEnvelope = createInfo.cryptHandle;
/* Push in the timestamp data */
status = krnlSendMessage( iTimestampEnvelope, IMESSAGE_SETATTRIBUTE,
( void * ) &bufSize,
CRYPT_ATTRIBUTE_BUFFERSIZE );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, ( void * ) timestamp, timestampLength );
status = krnlSendMessage( iTimestampEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iTimestampEnvelope, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iTimestampEnvelope, IMESSAGE_DECREFCOUNT );
return( status );
}
/* We've got the timestamp info in a sub-envelope, remember it for
later */
contentListPtr->clSigInfo.iTimestamp = iTimestampEnvelope;
return( CRYPT_OK );
}
/* Process CMS unauthenticated attributes. We can't handle these as
standard CMS attributes since the only thing that we're likely to see
here is a countersignature, which isn't an attribute in the normal
sense */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int processUnauthAttributes( INOUT CONTENT_LIST *contentListPtr,
IN_BUFFER( unauthAttrLength ) \
const void *unauthAttr,
IN_LENGTH_MIN( MIN_CRYPT_OBJECTSIZE ) \
const int unauthAttrLength )
{
STREAM stream;
int iterationCount = 0, status;
assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
assert( isReadPtr( unauthAttr, unauthAttrLength ) );
REQUIRES( unauthAttrLength >= MIN_CRYPT_OBJECTSIZE && \
unauthAttrLength < MAX_INTLENGTH );
/* Make sure that the unauthenticated attributes are OK. Normally this
is done when we import the attributes but since we can't import
them we have to perform the check explicitly here */
if( cryptStatusError( checkObjectEncoding( unauthAttr,
unauthAttrLength ) ) )
return( CRYPT_ERROR_BADDATA );
/* Process each attribute */
sMemConnect( &stream, unauthAttr, unauthAttrLength );
status = readConstructed( &stream, NULL, 1 );
while( cryptStatusOK( status ) && \
sMemDataLeft( &stream ) >= MIN_CRYPT_OBJECTSIZE && \
iterationCount++ < FAILSAFE_ITERATIONS_LARGE )
{
BYTE oid[ MAX_OID_SIZE + 8 ];
void *dataPtr;
int oidLength, length = DUMMY_INIT;
/* See what we've got */
readSequence( &stream, NULL );
status = readEncodedOID( &stream, oid, MAX_OID_SIZE, &oidLength,
BER_OBJECT_IDENTIFIER );
if( cryptStatusOK( status ) )
status = readSet( &stream, &length );
if( cryptStatusError( status ) )
break;
/* If it's something that we don't recognise, skip it and continue */
if( oidLength != sizeofOID( OID_TSP_TSTOKEN ) || \
memcmp( oid, OID_TSP_TSTOKEN, oidLength ) )
{
status = readUniversal( &stream );
continue;
}
/* We've got a timestamp. We can't really do much with this at the
moment since although it quacks like a countersignature, in the
PKIX tradition it's subtly (and gratuitously) incompatible in
various ways so that it can't be verified as a standard
countersignature (video meliora proboque deteriora sequor).
Amusingly, the RFC actually states that this is a stupid way to
do things. Specifically, instead of using the normal MUST/SHOULD
it first states that the sensible solution to the problem is to
use a countersignature, and then goes on to mandate something
that isn't a countersignature. Since this isn't the sensible
solution, it's obviously the stupid one. QED */
if( length < MIN_CRYPT_OBJECTSIZE )
{
/* It's too short to be a valid timestamp */
status = CRYPT_ERROR_UNDERFLOW;
continue;
}
status = sMemGetDataBlock( &stream, &dataPtr, length );
if( cryptStatusOK( status ) )
status = sSkip( &stream, length );
if( cryptStatusOK( status ) )
status = processTimestamp( contentListPtr, dataPtr, length );
/* Continue in the loop with the cryptStatusOK() check */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -