📄 resource.c
字号:
actionListCurrent->needsController )
deleteAction( &envelopeInfoPtr->actionList, actionListCurrent );
}
}
/* Check that the actions in an envelope are consistent. This is a complex
function which is called from an assert() macro, so we only need to define
it when we're building a debug version */
#ifndef NDEBUG
BOOLEAN actionsOK( ENVELOPE_INFO *envelopeInfoPtr )
{
ACTION_LIST *actionListPtr = envelopeInfoPtr->actionList;
/* The permitted action combinations are key exchange + crypt/MAC,
sign + hash, crypt, or none, make sure this is the case */
if( envelopeInfoPtr->preActionList != NULL )
{
/* Key exchange must be followed by crypt or MAC action */
if( actionListPtr == NULL )
return( FALSE );
while( actionListPtr != NULL )
{
if( actionListPtr->action != ACTION_CRYPT && \
actionListPtr->action != ACTION_MAC )
return( FALSE );
actionListPtr = actionListPtr->next;
}
if( envelopeInfoPtr->postActionList != NULL )
return( FALSE );
}
else
if( envelopeInfoPtr->postActionList != NULL )
{
/* Signature must be preceded by hash action */
if( actionListPtr == NULL )
return( FALSE );
while( actionListPtr != NULL )
{
if( actionListPtr->action != ACTION_HASH )
return( FALSE );
actionListPtr = actionListPtr->next;
}
if( envelopeInfoPtr->preActionList != NULL )
return( FALSE );
}
else
if( actionListPtr != NULL )
/* A standalone action can only be (session-key based)
encryption except for de-enveloping a signed envelope,
where we can have standalone hash actions before we get
to the signature data and add post-actions */
if( !( ( actionListPtr->action == ACTION_CRYPT ) || \
( ( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
actionListPtr->action == ACTION_HASH ) ) )
return( FALSE );
/* Pre-actions can only be key exchange actions, and have to be sorted
by action group */
if( envelopeInfoPtr->preActionList != NULL )
{
actionListPtr = envelopeInfoPtr->preActionList;
while( actionListPtr != NULL && \
actionListPtr->action == ACTION_KEYEXCHANGE )
actionListPtr = actionListPtr->next;
while( actionListPtr != NULL && \
actionListPtr->action == ACTION_KEYEXCHANGE_PKC )
actionListPtr = actionListPtr->next;
return( ( actionListPtr == NULL ) ? TRUE : FALSE );
}
/* Post-actions can only be signature actions */
if( envelopeInfoPtr->postActionList != NULL )
{
for( actionListPtr = envelopeInfoPtr->postActionList;
actionListPtr != NULL; actionListPtr = actionListPtr->next )
if( actionListPtr->action != ACTION_SIGN )
return( FALSE );
return( TRUE );
}
/* A standalone action can be either a single crypt, one or more hashes,
or nothing */
if( envelopeInfoPtr->actionList == NULL )
return( TRUE );
if( envelopeInfoPtr->actionList->action == ACTION_CRYPT )
return( envelopeInfoPtr->actionList->next == NULL ? TRUE : FALSE );
for( actionListPtr = envelopeInfoPtr->preActionList;
actionListPtr != NULL; actionListPtr = actionListPtr->next )
if( actionListPtr->action != ACTION_HASH )
return( FALSE );
return( TRUE );
}
#endif /* !NDEBUG */
/****************************************************************************
* *
* Misc.Enveloping Info Management Functions *
* *
****************************************************************************/
/* Set up the encryption for an envelope */
int initEnvelopeEncryption( ENVELOPE_INFO *envelopeInfoPtr,
const CRYPT_CONTEXT cryptContext,
const CRYPT_ALGO algorithm, const CRYPT_MODE mode,
const BYTE *iv, const int ivLength,
const BOOLEAN copyContext )
{
CRYPT_CONTEXT iCryptContext = cryptContext;
CRYPT_ALGO cryptAlgo;
CRYPT_MODE cryptMode;
RESOURCE_DATA msgData;
int blockSize, status;
/* Extract the information we need to process data */
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptMode, CRYPT_CTXINFO_MODE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&blockSize, CRYPT_CTXINFO_BLOCKSIZE );
if( cryptStatusError( status ) )
return( status );
/* Make sure the context is what's required */
if( algorithm != CRYPT_UNUSED && \
( cryptAlgo != algorithm || cryptMode != mode ) )
/* This can only happen on deenveloping if the data is corrupted or
if the user is asked for a KEK and tries to supply a session key
instead */
return( CRYPT_ERROR_WRONGKEY );
/* If it's a user-supplied context, take a copy for our own use. This is
only done for user-supplied raw session keys, for everything else we
either use cryptlib's object management to handle things for us or the
context is a internal one created specifically for our own use */
if( copyContext )
{
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_CLONE,
&iCryptContext, 0 );
if( cryptStatusError( status ) )
return( status );
}
/* Load the IV into the context and set up the encryption information for
the envelope */
if( !isStreamCipher( cryptAlgo ) )
{
if( iv != NULL )
{
int ivSize;
status = krnlSendMessage( cryptContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&ivSize, CRYPT_CTXINFO_IVSIZE );
setResourceData( &msgData, ( void * ) iv, min( ivLength, ivSize ) );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_IV );
}
else
/* There's no IV specified, generate a new one */
status = krnlSendNotifier( iCryptContext, RESOURCE_IMESSAGE_CTX_GENIV );
if( cryptStatusError( status ) )
{
if( copyContext )
/* Destroy the copy we created earlier */
krnlSendNotifier( iCryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
}
envelopeInfoPtr->iCryptContext = iCryptContext;
envelopeInfoPtr->blockSize = blockSize;
envelopeInfoPtr->blockSizeMask = ~( blockSize - 1 );
return( CRYPT_OK );
}
/* Add keyset information */
static int addKeyset( ENVELOPE_INFO *envelopeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE keysetFunction,
const CRYPT_KEYSET keyset )
{
CRYPT_KEYSET *iKeysetPtr;
/* Figure out which keyset we want to set */
switch( keysetFunction )
{
case CRYPT_ENVINFO_KEYSET_ENCRYPT:
iKeysetPtr = &envelopeInfoPtr->iEncryptionKeyset;
break;
case CRYPT_ENVINFO_KEYSET_DECRYPT:
iKeysetPtr = &envelopeInfoPtr->iDecryptionKeyset;
break;
case CRYPT_ENVINFO_KEYSET_SIGCHECK:
iKeysetPtr = &envelopeInfoPtr->iSigCheckKeyset;
break;
default:
assert( NOTREACHED );
}
/* Make sure the keyset hasn't already been set */
if( *iKeysetPtr != CRYPT_ERROR )
return( CRYPT_ERROR_INITED );
/* Remember the new keyset and increment its reference count */
*iKeysetPtr = keyset;
return( krnlSendNotifier( keyset, RESOURCE_IMESSAGE_INCREFCOUNT ) );
}
/****************************************************************************
* *
* Deenveloping Information Management Functions *
* *
****************************************************************************/
/* 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 )
{
MECHANISM_WRAP_INFO mechanismInfo;
BYTE *payloadPtr = contentListPtr->payload;
int payloadLength = contentListPtr->payloadSize;
/* If it's an RSA key, skip the MPI header around the RSA data. DLP
keys are handled natively so no extra processing is required */
if( contentListPtr->cryptAlgo == CRYPT_ALGO_RSA )
{
payloadPtr += 2;
payloadLength -= 2;
}
/* Decrypt the encrypted key and load it into the context */
setMechanismWrapInfo( &mechanismInfo, payloadPtr, payloadLength, NULL,
0, CRYPT_UNUSED, iImportContext, CRYPT_UNUSED );
status = krnlSendMessage( iImportContext, RESOURCE_IMESSAGE_DEV_IMPORT,
&mechanismInfo, MECHANISM_PKCS1_PGP );
if( cryptStatusOK( status ) )
*iSessionKeyContext = mechanismInfo.keyContext;
clearMechanismInfo( &mechanismInfo );
return( status );
}
/* 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->cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_SETATTRIBUTE,
&sessionKeyInfoPtr->cryptMode,
CRYPT_CTXINFO_MODE );
if( cryptStatusOK( status ) )
status = iCryptImportKeyEx( contentListPtr->object,
contentListPtr->objectSize,
iImportContext, createInfo.cryptHandle );
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle,
RESOURCE_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;
int status;
/* 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 = createAction( ACTION_HASH, cryptHandle );
if( actionListItem == NULL )
return( CRYPT_ERROR_MEMORY );
envelopeInfoPtr->actionList = actionListItem;
return( krnlSendNotifier( cryptHandle,
RESOURCE_IMESSAGE_INCREFCOUNT ) );
}
/* Since we can add one of a multitude of necessary information types, we
need to check to make sure 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 */
for( contentListPtr = envelopeInfoPtr->contentList;
contentListPtr != NULL && contentListPtr->envInfo != envInfo;
contentListPtr = contentListPtr->next );
if( contentListPtr == NULL )
return( CRYPT_ARGERROR_VALUE );
}
/* Make sure the information we're adding matches the currently required
information object. The one exception to this is that we can be
passed password information when we require a private key if the
private key is encrypted */
if( contentListPtr->envInfo != envInfo && \
!( contentListPtr->envInfo == CRYPT_ENVINFO_PRIVATEKEY && \
envInfo == CRYPT_ENVINFO_PASSWORD ) )
return( CRYPT_ARGERROR_VALUE );
/* If it's a signature object, check the signature and exit. Anything
left after this point is a keying object */
if( envInfo == CRYPT_ENVINFO_SIGNATURE )
{
/* If we've already processed this entry, return the saved processing
result */
if( contentListPtr->processed )
return( contentListPtr->processingResult );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -