📄 res_env.c
字号:
/****************************************************************************
* *
* cryptlib 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 */
#ifdef USE_ENVELOPES
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
#ifdef USE_PGP
/* Check that an object being added is suitable for use with PGP data */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkPgpUsage( INOUT ENVELOPE_INFO *envelopeInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE envInfo )
{
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( envInfo > CRYPT_ENVINFO_FIRST && envInfo < CRYPT_ENVINFO_LAST );
/* The attribute being added isn't context-related, there's nothing
PGP-specific to check */
if( envInfo != CRYPT_ENVINFO_PUBLICKEY && \
envInfo != CRYPT_ENVINFO_PRIVATEKEY && \
envInfo != CRYPT_ENVINFO_KEY && \
envInfo != CRYPT_ENVINFO_SESSIONKEY && \
envInfo != CRYPT_ENVINFO_HASH && \
envInfo != CRYPT_ENVINFO_SIGNATURE )
return( CRYPT_OK );
/* PGP doesn't support both PKC and conventional key exchange actions in
the same envelope since the session key is encrypted for the PKC
action but derived from the password for the conventional action */
if( findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE ) != NULL )
return( CRYPT_ERROR_INITED );
/* PGP handles multiple signers by nesting signed data rather than
attaching multiple signatures so we can only apply a single
signature per envelope */
if( envInfo == CRYPT_ENVINFO_SIGNATURE && \
envelopeInfoPtr->postActionList != NULL )
return( CRYPT_ERROR_INITED );
/* PGP doesn't allow multiple hash algorithms to be used when signing
data, a follow-on from the way that nested sigs are handled */
if( envInfo == CRYPT_ENVINFO_HASH && \
envelopeInfoPtr->actionList != NULL )
return( CRYPT_ERROR_INITED );
return( CRYPT_OK );
}
#endif /* USE_PGP */
#ifdef USE_FORTEZZA
/* Check that an object being added is suitable for use with Fortezza data */
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
static int checkFortezzaUsage( IN_HANDLE const CRYPT_HANDLE cryptHandle,
const ENVELOPE_INFO *envelopeInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE envInfo )
{
CRYPT_ALGO_TYPE cryptAlgo;
int device1, device2 = DUMMY_INIT, status;
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( isHandleRangeValid( cryptHandle ) );
REQUIRES( envInfo == CRYPT_ENVINFO_ORIGINATOR || \
envInfo == CRYPT_ENVINFO_SESSIONKEY );
/* Make sure that the new session key being added (if there's existing
originator info) or the existing one (if it's originator info being
added) is a Skipjack context */
status = krnlSendMessage( ( envInfo == CRYPT_ENVINFO_ORIGINATOR ) ? \
envelopeInfoPtr->iCryptContext : cryptHandle,
IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) || cryptAlgo != CRYPT_ALGO_SKIPJACK )
return( CRYPT_ARGERROR_NUM1 );
/* Make sure that both objects are present in the same device */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT, &device1,
OBJECT_TYPE_DEVICE );
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
IMESSAGE_GETDEPENDENT, &device2,
OBJECT_TYPE_DEVICE );
}
if( cryptStatusOK( status ) && ( device1 != device2 ) )
status = CRYPT_ARGERROR_NUM1;
return( status );
}
#endif /* USE_FORTEZZA */
/****************************************************************************
* *
* Misc.Enveloping Info Management Functions *
* *
****************************************************************************/
/* Set up the encryption for an envelope */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int initEnvelopeEncryption( INOUT ENVELOPE_INFO *envelopeInfoPtr,
IN_HANDLE const CRYPT_CONTEXT cryptContext,
IN_ALGO_OPT const CRYPT_ALGO_TYPE algorithm,
IN_MODE_OPT const CRYPT_MODE_TYPE mode,
IN_BUFFER_OPT( ivLength ) const BYTE *iv,
IN_LENGTH_IV_Z const int ivLength,
const BOOLEAN copyContext )
{
CRYPT_CONTEXT iCryptContext = cryptContext;
CRYPT_ALGO_TYPE cryptAlgo = DUMMY_INIT;
CRYPT_MODE_TYPE cryptMode = DUMMY_INIT;
int blockSize = DUMMY_INIT, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( ( iv == NULL && ivLength == 0 ) || \
isReadPtr( iv, ivLength ) );
REQUIRES( isHandleRangeValid( cryptContext ) );
REQUIRES( ( algorithm == CRYPT_ALGO_NONE && mode == CRYPT_MODE_NONE ) || \
( algorithm >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
algorithm <= CRYPT_ALGO_LAST_CONVENTIONAL ) );
REQUIRES( ( algorithm == CRYPT_ALGO_NONE && mode == CRYPT_MODE_NONE ) || \
( mode > CRYPT_MODE_NONE && mode < CRYPT_MODE_LAST ) );
REQUIRES( ( iv == NULL && ivLength == 0 ) || \
( iv != NULL && \
ivLength >= 8 && ivLength <= CRYPT_MAX_IVSIZE ) );
/* Extract the information that we need to process data */
status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
&cryptMode, CRYPT_CTXINFO_MODE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
&blockSize, CRYPT_CTXINFO_BLOCKSIZE );
if( cryptStatusError( status ) )
return( status );
/* Make sure that the context is what's required */
if( algorithm != CRYPT_ALGO_NONE && \
( cryptAlgo != algorithm || cryptMode != mode ) )
{
/* This can only happen on de-enveloping 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( ivLength != 0 && ivLength != blockSize )
return( CRYPT_ERROR_BADDATA );
/* If it's a user-supplied context take a copy for our own use. This is
only done for non-idempotent user-supplied contexts, 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 )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
setMessageCreateObjectInfo( &createInfo, cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( iCryptContext, IMESSAGE_CLONE, NULL,
createInfo.cryptHandle );
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
iCryptContext = createInfo.cryptHandle;
}
/* Load the IV into the context and set up the encryption information for
the envelope */
if( !isStreamCipher( cryptAlgo ) )
{
if( iv != NULL )
{
MESSAGE_DATA msgData;
setMessageData( &msgData, ( void * ) iv, ivLength );
status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_IV );
}
else
{
/* There's no IV specified, generate a new one */
status = krnlSendNotifier( iCryptContext, IMESSAGE_CTX_GENIV );
}
if( cryptStatusError( status ) )
{
if( copyContext )
{
/* Destroy the copy that we created earlier */
krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
}
return( status );
}
}
envelopeInfoPtr->iCryptContext = iCryptContext;
envelopeInfoPtr->blockSize = blockSize;
envelopeInfoPtr->blockSizeMask = ~( blockSize - 1 );
return( CRYPT_OK );
}
/* Check the consistency of enveloping resources before we begin enveloping,
returning the ID of any missing attributes */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkSignatureActionFunction( const ACTION_LIST *actionListPtr,
IN_INT_Z const int signingKeyPresent )
{
assert( isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
/* If there are no signature-related auxiliary options present, there's
nothing to check */
if( actionListPtr->iExtraData != CRYPT_ERROR || \
actionListPtr->iTspSession != CRYPT_ERROR )
return( CRYPT_OK );
/* There must be a signing key present to handle the signature options */
if( !signingKeyPresent || actionListPtr->iCryptHandle == CRYPT_ERROR )
return( CRYPT_ERROR_NOTINITED );
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkMissingInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
BOOLEAN signingKeyPresent = FALSE;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
/* Make sure that we have the minimum requirements for each usage type
present */
switch( envelopeInfoPtr->usage )
{
case ACTION_COMPRESS:
REQUIRES( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED );
break;
case ACTION_HASH:
assert( DEBUG_WARN );
break;
case ACTION_MAC:
/* If it's a MAC envelope there must be at least one key exchange
action present. A few obscure operation sequences may
however set the usage without setting a key exchange action.
For example making the envelope a MAC envelope simply
indicates that any future key exchange actions should be used
for MACing rather than encryption but this is indicative of a
logic error in the calling application so we report an error
even if, strictly speaking, we could ignore it and continue */
if( findAction( envelopeInfoPtr->preActionList, \
ACTION_KEYEXCHANGE_PKC ) == NULL && \
findAction( envelopeInfoPtr->preActionList, \
ACTION_KEYEXCHANGE ) == NULL )
{
/* We return the most generic CRYPT_ENVINFO_KEY error code
since there are several possible missing attribute types
that could be required */
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEY,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
break;
case ACTION_CRYPT:
/* If it's an encryption envelope there must be a key present at
some level. This situation doesn't normally occur since the
higher-level code will only set the usage to encryption once
a key exchange action has been added, but we check anyway
just to be safe */
if( findAction( envelopeInfoPtr->preActionList, \
ACTION_KEYEXCHANGE_PKC ) == NULL && \
findAction( envelopeInfoPtr->preActionList, \
ACTION_KEYEXCHANGE ) == NULL && \
findAction( envelopeInfoPtr->actionList, ACTION_CRYPT ) == NULL )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEY,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
#ifdef USE_FORTEZZA
/* If there's an originator present there must be a matching
public-key action present */
if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR && \
findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC ) == NULL )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_PUBLICKEY,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
#endif /* USE_FORTEZZA */
break;
case ACTION_SIGN:
/* If it's a signing envelope there must be a signature key
present */
if( findAction( envelopeInfoPtr->postActionList, \
ACTION_SIGN ) == NULL )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
signingKeyPresent = TRUE;
}
REQUIRES( signingKeyPresent || \
!( ( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) || \
findAction( envelopeInfoPtr->actionList, ACTION_HASH ) ) );
/* If there are signature-related options present (signature envelope,
detached-signature flag set, hash context present, or CMS attributes
or a TSA session present) there must be a signing key also present */
if( envelopeInfoPtr->postActionList != NULL )
{
int status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -