📄 res_denv.c
字号:
/****************************************************************************
* *
* cryptlib De-enveloping Information Management *
* Copyright Peter Gutmann 1996-2004 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "envelope.h"
#include "pgp.h"
#include "asn1.h"
#include "asn1_ext.h"
#elif defined( INC_CHILD )
#include "envelope.h"
#include "pgp.h"
#include "../misc/asn1.h"
#include "../misc/asn1_ext.h"
#else
#include "envelope/envelope.h"
#include "envelope/pgp.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Content List Management Functions *
* *
****************************************************************************/
/* Create a content list item */
CONTENT_LIST *createContentListItem( MEMPOOL_STATE memPoolState,
const CRYPT_FORMAT_TYPE formatType,
const void *object, const int objectSize,
const BOOLEAN isSigObject )
{
CONTENT_LIST *contentListItem;
if( ( contentListItem = getMemPool( memPoolState,
sizeof( CONTENT_LIST ) ) ) == NULL )
return( NULL );
memset( contentListItem, 0, sizeof( CONTENT_LIST ) );
contentListItem->formatType = formatType;
contentListItem->object = ( void * ) object;
contentListItem->objectSize = objectSize;
if( isSigObject )
{
contentListItem->flags = CONTENTLIST_ISSIGOBJ;
contentListItem->clSigInfo.iSigCheckKey = CRYPT_ERROR;
contentListItem->clSigInfo.iExtraData = CRYPT_ERROR;
contentListItem->clSigInfo.iTimestamp = CRYPT_ERROR;
}
return( contentListItem );
}
/* Add an item to the content list */
void appendContentListItem( ENVELOPE_INFO *envelopeInfoPtr,
CONTENT_LIST *contentListItem )
{
CONTENT_LIST *contentListPtr = envelopeInfoPtr->contentList;
/* Find the end of the list and add the new item */
if( contentListPtr != NULL )
while( contentListPtr->next != NULL )
contentListPtr = contentListPtr->next;
insertDoubleListElements( &envelopeInfoPtr->contentList, contentListPtr,
contentListItem, contentListItem );
}
/* Delete a content list */
void deleteContentList( MEMPOOL_STATE memPoolState,
CONTENT_LIST **contentListHeadPtr )
{
CONTENT_LIST *contentListCursor = *contentListHeadPtr;
while( contentListCursor != NULL )
{
CONTENT_LIST *contentListItem = contentListCursor;
/* 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 */
contentListCursor = contentListCursor->next;
deleteDoubleListElement( contentListHeadPtr, contentListItem );
if( contentListItem->object != NULL )
{
zeroise( contentListItem->object, contentListItem->objectSize );
clFree( "deleteContentList", contentListItem->object );
}
zeroise( contentListItem, sizeof( CONTENT_LIST ) );
freeMemPool( memPoolState, contentListItem );
}
}
/****************************************************************************
* *
* De-enveloping Information Management Functions *
* *
****************************************************************************/
/* Process timestamps */
static int processTimestamp( STREAM *stream,
CONTENT_LIST *contentListPtr )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
int dataSize, bufSize, status;
/* Find out how much data we've got */
dataSize = getStreamObjectLength( stream );
if( cryptStatusError( dataSize ) )
return( dataSize );
if( dataSize < MIN_CRYPT_OBJECTSIZE )
return( CRYPT_ERROR_UNDERFLOW );
if( dataSize > sMemDataLeft( stream ) )
return( CRYPT_ERROR_OVERFLOW );
bufSize = max( dataSize + 128, MIN_BUFFER_SIZE );
/* Create an envelope to contain the timestamp data */
setMessageCreateObjectInfo( &createInfo, CRYPT_FORMAT_AUTO );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_ENVELOPE );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
( void * ) &bufSize, CRYPT_ATTRIBUTE_BUFFERSIZE );
/* Push in the timestamp data */
setMessageData( &msgData, sMemBufPtr( stream ), dataSize );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_ENV_PUSHDATA,
&msgData, 0 );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
/* We've got the timestamp info in a sub-envelope, remember it for
later */
contentListPtr->clSigInfo.iTimestamp = createInfo.cryptHandle;
return( sSkip( stream, dataSize ) );
}
/* Process CMS unauthenticated attributes. We can't handle these as
standard CMS attributes since the only thing we're likely to see here is
a countersignature, which isn't an attribute in the normal sense */
static int processUnauthAttributes( CONTENT_LIST *contentListPtr,
const void *unauthAttr,
const int unauthAttrLength )
{
STREAM stream;
int status;
UNUSED( contentListPtr );
/* 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 */
status = checkObjectEncoding( unauthAttr, unauthAttrLength );
if( cryptStatusError( status ) )
return( status );
/* Process each attribute */
sMemConnect( &stream, unauthAttr, unauthAttrLength );
status = readConstructed( &stream, NULL, 1 );
while( cryptStatusOK( status ) && \
sMemDataLeft( &stream ) > MIN_CRYPT_OBJECTSIZE )
{
BYTE oid[ MAX_OID_SIZE ];
int oidLength;
/* See what we've got */
readSequence( &stream, NULL );
status = readRawObject( &stream, oid, &oidLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusOK( status ) )
status = readSet( &stream, NULL );
if( cryptStatusError( status ) )
break;
if( oidLength == sizeofOID( OID_TSP_TSTOKEN ) && \
!memcmp( oid, OID_TSP_TSTOKEN, oidLength ) )
{
/* 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. 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 */
status = processTimestamp( &stream, contentListPtr );
continue;
}
/* It's something that we don't recognise, skip it and continue */
status = readUniversal( &stream );
continue;
}
sMemDisconnect( &stream );
return( status );
}
/* Import a wrapped session key */
static int importSessionKey( ENVELOPE_INFO *envelopeInfoPtr,
const CONTENT_LIST *contentListPtr,
const CRYPT_CONTEXT iImportContext,
CRYPT_CONTEXT *iSessionKeyContext )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
CONTENT_LIST *sessionKeyInfoPtr;
int status;
/* Clear the return value */
*iSessionKeyContext = CRYPT_ERROR;
/* PGP doesn't provide separate session key information with the
encrypted data but wraps it up alongside the encrypted key, so we
can't import the wrapped key into a context via the standard key
import functions but instead have to create the context as part of
the unwrap process */
if( contentListPtr->formatType == CRYPT_FORMAT_PGP )
return( iCryptImportKeyEx( contentListPtr->object,
contentListPtr->objectSize,
CRYPT_FORMAT_PGP, iImportContext,
CRYPT_UNUSED, iSessionKeyContext ) );
/* Look for the information required to recreate the session key context */
for( sessionKeyInfoPtr = envelopeInfoPtr->contentList;
sessionKeyInfoPtr != NULL && \
sessionKeyInfoPtr->envInfo != CRYPT_ENVINFO_SESSIONKEY;
sessionKeyInfoPtr = sessionKeyInfoPtr->next );
if( sessionKeyInfoPtr == NULL )
/* We need to read more data before we can recreate the session key */
return( CRYPT_ERROR_UNDERFLOW );
/* Create the session key context and import the encrypted session key */
setMessageCreateObjectInfo( &createInfo,
sessionKeyInfoPtr->clEncrInfo.cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&sessionKeyInfoPtr->clEncrInfo.cryptMode,
CRYPT_CTXINFO_MODE );
if( cryptStatusOK( status ) )
status = iCryptImportKeyEx( contentListPtr->object,
contentListPtr->objectSize,
contentListPtr->formatType,
iImportContext, createInfo.cryptHandle,
NULL );
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
*iSessionKeyContext = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* Add de-enveloping information to an envelope */
static int addDeenvelopeInfo( ENVELOPE_INFO *envelopeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE envInfo,
const void *value, const int valueLength )
{
CONTENT_LIST *contentListPtr = envelopeInfoPtr->contentListCurrent;
CRYPT_HANDLE cryptHandle = *( ( CRYPT_HANDLE * ) value ), iNewContext;
ACTION_LIST *actionListPtr;
ACTION_RESULT actionResult;
int status = CRYPT_OK;
/* If it's meta-information, remember the value */
if( envInfo == CRYPT_IATTRIBUTE_ATTRONLY )
{
/* This is off by default so we should only be turning it on */
assert( ( *( int * ) value ) == TRUE );
envelopeInfoPtr->flags |= ENVELOPE_ATTRONLY;
return( CRYPT_OK );
}
/* If it's keyset information, just keep a record of it for later use */
if( envInfo == CRYPT_ENVINFO_KEYSET_SIGCHECK || \
envInfo == CRYPT_ENVINFO_KEYSET_ENCRYPT || \
envInfo == CRYPT_ENVINFO_KEYSET_DECRYPT )
return( addKeyset( envelopeInfoPtr, envInfo, cryptHandle ) );
/* If it's a hash action, the user is checking a detached sig, remember
the hash for later. In theory we should check the state of the hash
context, however PGP requires that it not be completed (since it
needs to hash further data) and everything else requires that it be
completed, but we don't know at this point whether we're processing
PGP or non-PGP data, so we can't perform any checking here */
if( envInfo == CRYPT_ENVINFO_HASH )
{
ACTION_LIST *actionListItem;
/* If there's already an action present, we can't add anything
further */
if( envelopeInfoPtr->actionList != NULL )
return( CRYPT_ERROR_INITED );
/* Add the hash as an action list item */
actionListItem = addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->memPoolState,
ACTION_HASH, cryptHandle );
if( actionListItem == NULL )
return( CRYPT_ERROR_MEMORY );
return( krnlSendNotifier( cryptHandle, IMESSAGE_INCREFCOUNT ) );
}
/* Since we can add one of a multitude of necessary information types, we
need to check to make sure that what we're adding is appropriate. If
the caller hasn't tried to read the required resource information yet,
we try to match what's being added to the first information object of
the correct type */
if( contentListPtr == NULL )
{
/* Look for the first information object matching the supplied
information */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -