📄 cryptctx.c
字号:
MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL );
static const int actionFlagsDH = ACTION_PERM_NONE_EXTERNAL_ALL;
static const int actionFlagsPGP = \
MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_ALL ) | \
MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_ALL );
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
STREAM stream;
int status;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( contextInfoPtr->type == CONTEXT_PKC );
assert( needsKey( contextInfoPtr ) || \
( contextInfoPtr->flags & CONTEXT_DUMMY ) );
assert( keyType == CRYPT_IATTRIBUTE_KEY_SPKI || \
keyType == CRYPT_IATTRIBUTE_KEY_PGP || \
keyType == CRYPT_IATTRIBUTE_KEY_SSH1 || \
keyType == CRYPT_IATTRIBUTE_KEY_SSH2 || \
keyType == CRYPT_IATTRIBUTE_KEY_SSL || \
keyType == CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL || \
keyType == CRYPT_IATTRIBUTE_KEY_PGP_PARTIAL );
assert( isReadPtr( keyData, keyDataLen ) );
/* If the keys are held externally (e.g. in a crypto device), copy the
encoded public key data in and set up any other information that we
may need from it. This information is used when loading a context
from a key contained in a device, where the actual key components
aren't directly available in the context but may be needed in the
future for things like cert requests and certs */
if( contextInfoPtr->flags & CONTEXT_DUMMY )
{
assert( keyType == CRYPT_IATTRIBUTE_KEY_SPKI || \
keyType == CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL );
if( ( contextInfoPtr->ctxPKC->publicKeyInfo = \
clAlloc( "processSetAttributeS", keyDataLen ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memcpy( contextInfoPtr->ctxPKC->publicKeyInfo, keyData, keyDataLen );
contextInfoPtr->ctxPKC->publicKeyInfoSize = keyDataLen;
return( calculateKeyID( contextInfoPtr ) );
}
/* Read the appropriately-formatted key data into the context, applying
a lowest-common-denominator set of usage flags to the loaded key
(more specific usage restrictions will be set by higher-level code) */
sMemConnect( &stream, keyData, keyDataLen );
status = contextInfoPtr->ctxPKC->readPublicKeyFunction( &stream,
contextInfoPtr,
attributeToFormatType( keyType ) );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* If it's a partial load of the initial public portions of a private
key with further key component operations to follow, there's nothing
more to do at this point and we're done */
if( keyType == CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL || \
keyType == CRYPT_IATTRIBUTE_KEY_PGP_PARTIAL )
return( calculateKeyID( contextInfoPtr ) );
/* Perform an internal load that uses the key component values that
we've just read into the context */
contextInfoPtr->flags |= CONTEXT_ISPUBLICKEY;
status = contextInfoPtr->loadKeyFunction( contextInfoPtr, NULL, 0 );
if( cryptStatusError( status ) )
/* Map the status to a more appropriate code if necessary */
return( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status );
contextInfoPtr->flags |= CONTEXT_KEY_SET;
/* Restrict the key usage to public-key-only actions if necessary. For
PGP key loads (which, apart from the restrictions specified with the
stored key data aren't constrained by the presence of ACLs in the
form of certs) we allow external usage, for DH (whose keys can be
both public and private keys even though technically it's a public
key) we allow both encryption and decryption usage, and for public
keys read from certs we allow internal usage only */
status = krnlSendMessage( contextInfoPtr->objectHandle,
IMESSAGE_SETATTRIBUTE,
( keyType == CRYPT_IATTRIBUTE_KEY_PGP ) ? \
( void * ) &actionFlagsPGP : \
( capabilityInfoPtr->cryptAlgo == CRYPT_ALGO_DH ) ? \
( void * ) &actionFlagsDH : \
( void * ) &actionFlags,
CRYPT_IATTRIBUTE_ACTIONPERMS );
if( cryptStatusError( status ) )
return( status );
contextInfoPtr->flags |= CONTEXT_KEY_SET;
return( calculateKeyID( contextInfoPtr ) );
}
/* Load a composite key into a context */
static int setKeyComponents( CONTEXT_INFO *contextInfoPtr,
const void *keyData, const int keyDataLen )
{
static const int actionFlags = \
MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_ALL ) | \
MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_ALL );
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
int status;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( contextInfoPtr->type == CONTEXT_PKC );
assert( needsKey( contextInfoPtr ) );
assert( isReadPtr( keyData, keyDataLen ) );
assert( keyDataLen == sizeof( CRYPT_PKCINFO_RSA ) || \
keyDataLen == sizeof( CRYPT_PKCINFO_DLP ) );
/* We need to have a key label set before we can continue */
if( contextInfoPtr->labelSize <= 0 )
return( exitErrorNotInited( contextInfoPtr, CRYPT_CTXINFO_LABEL ) );
/* Load the key components into the context */
status = contextInfoPtr->loadKeyFunction( contextInfoPtr, keyData,
keyDataLen );
if( cryptStatusError( status ) )
return( status );
contextInfoPtr->flags |= CONTEXT_KEY_SET | CONTEXT_EPHEMERAL | CONTEXT_PBO;
/* Restrict the key usage to public-key-only actions if it's a public
key. DH keys act as both public and private keys so we don't
restrict their usage */
if( ( contextInfoPtr->flags & CONTEXT_ISPUBLICKEY ) && \
( capabilityInfoPtr->cryptAlgo != CRYPT_ALGO_DH ) )
status = krnlSendMessage( contextInfoPtr->objectHandle,
IMESSAGE_SETATTRIBUTE,
( void * ) &actionFlags,
CRYPT_IATTRIBUTE_ACTIONPERMS );
return( status );
}
/* Encrypt a block of data */
static int encryptData( CONTEXT_INFO *contextInfoPtr, void *data,
const int dataLength )
{
BYTE savedData[ ENCRYPT_CHECKSIZE ];
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
const int savedDataLength = min( dataLength, ENCRYPT_CHECKSIZE );
int status;
assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
assert( contextInfoPtr->type == CONTEXT_CONV || \
contextInfoPtr->type == CONTEXT_PKC );
assert( contextInfoPtr->encryptFunction != NULL );
assert( isWritePtr( data, dataLength ) );
if( contextInfoPtr->type == CONTEXT_PKC )
{
const BOOLEAN isDLP = isDlpAlgo( capabilityInfoPtr->cryptAlgo );
/* Key agreement algorithms are treated as a special case since they
don't actually encrypt the data */
if( isKeyxAlgo( capabilityInfoPtr->cryptAlgo ) )
{
assert( dataLength == sizeof( KEYAGREE_PARAMS ) );
status = contextInfoPtr->encryptFunction( contextInfoPtr, data,
dataLength );
clearTempBignums( contextInfoPtr->ctxPKC );
return( status );
}
assert( !isDLP || dataLength == sizeof( DLP_PARAMS ) );
memcpy( savedData, isDLP ? ( ( DLP_PARAMS * ) data )->inParam1 : \
data, ENCRYPT_CHECKSIZE );
status = contextInfoPtr->encryptFunction( contextInfoPtr, data,
dataLength );
if( cryptStatusError( status ) )
{
zeroise( savedData, ENCRYPT_CHECKSIZE );
clearTempBignums( contextInfoPtr->ctxPKC );
return( status );
}
/* Check for a catastrophic failure of the encryption */
if( isDLP )
{
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) data;
if( !memcmp( savedData, dlpParams->outParam, ENCRYPT_CHECKSIZE ) )
{
zeroise( dlpParams->outParam, dlpParams->outLen );
status = CRYPT_ERROR_FAILED;
}
}
else
if( !memcmp( savedData, data, ENCRYPT_CHECKSIZE ) )
{
zeroise( data, dataLength );
status = CRYPT_ERROR_FAILED;
}
zeroise( savedData, ENCRYPT_CHECKSIZE );
return( status );
}
assert( isStreamCipher( capabilityInfoPtr->cryptAlgo ) || \
!needsIV( contextInfoPtr->ctxConv->mode ) ||
( contextInfoPtr->flags & CONTEXT_IV_SET ) );
assert( contextInfoPtr->ctxConv->key == \
contextInfoPtr->storage + sizeof( CONV_INFO ) );
memcpy( savedData, data, savedDataLength );
status = contextInfoPtr->encryptFunction( contextInfoPtr, data,
dataLength );
if( cryptStatusError( status ) || savedDataLength <= 6 )
{
zeroise( savedData, ENCRYPT_CHECKSIZE );
return( status );
}
/* Check for a catastrophic failure of the encryption. A check of
a single block unfortunately isn't completely foolproof for 64-bit
blocksize ciphers in CBC mode because of the way the IV is applied to
the input. For the CBC encryption operation:
out = enc( in ^ IV )
if out == IV the operation turns into a no-op. Consider the simple
case where IV == in, so IV ^ in == 0. Then out = enc( 0 ) == IV,
with the input appearing again at the output. In fact this can occur
during normal operation once every 2^32 blocks (for a 64-bit block
cipher). Although the chances of this happening are fairly low (the
collision would have to occur on the first encrypted block in a
message, since that's the one we check), if possible we check the
first two blocks if we're using a 64-bit block cipher in CBC mode in
order to reduce false positives */
if( !memcmp( savedData, data, savedDataLength ) )
{
zeroise( data, dataLength );
status = CRYPT_ERROR_FAILED;
}
zeroise( savedData, ENCRYPT_CHECKSIZE );
return( status );
}
/****************************************************************************
* *
* Context Attribute Handling Functions *
* *
****************************************************************************/
/* Handle data sent to or read from a context */
static int processGetAttribute( CONTEXT_INFO *contextInfoPtr,
void *messageDataPtr, const int messageValue )
{
const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
const CONTEXT_TYPE contextType = contextInfoPtr->type;
int *valuePtr = ( int * ) messageDataPtr, value;
switch( messageValue )
{
case CRYPT_ATTRIBUTE_ERRORTYPE:
*valuePtr = contextInfoPtr->errorType;
return( CRYPT_OK );
case CRYPT_ATTRIBUTE_ERRORLOCUS:
*valuePtr = contextInfoPtr->errorLocus;
return( CRYPT_OK );
case CRYPT_OPTION_MISC_SIDECHANNELPROTECTION:
*valuePtr = ( contextInfoPtr->flags & \
CONTEXT_SIDECHANNELPROTECTION ) ? TRUE : FALSE;
return( CRYPT_OK );
case CRYPT_CTXINFO_ALGO:
*valuePtr = capabilityInfoPtr->cryptAlgo;
return( CRYPT_OK );
case CRYPT_CTXINFO_MODE:
assert( contextType == CONTEXT_CONV );
*valuePtr = contextInfoPtr->ctxConv->mode;
return( CRYPT_OK );
case CRYPT_CTXINFO_KEYSIZE:
switch( contextType )
{
case CONTEXT_CONV:
value = contextInfoPtr->ctxConv->userKeyLength;
break;
case CONTEXT_PKC:
value = bitsToBytes( contextInfoPtr->ctxPKC->keySizeBits );
break;
case CONTEXT_MAC:
value = contextInfoPtr->ctxMAC->userKeyLength;
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR );
}
if( value <= 0 )
/* If a key hasn't been loaded yet, we return the default
key size */
value = capabilityInfoPtr->keySize;
*valuePtr = value;
return( CRYPT_OK );
case CRYPT_CTXINFO_BLOCKSIZE:
if( contextType == CONTEXT_CONV && \
( contextInfoPtr->ctxConv->mode == CRYPT_MODE_CFB || \
contextInfoPtr->ctxConv->mode == CRYPT_MODE_OFB ) )
*valuePtr = 1; /* Block cipher in stream mode */
else
*valuePtr = capabilityInfoPtr->blockSize;
return( CRYPT_OK );
case CRYPT_CTXINFO_IVSIZE:
assert( contextType == CONTEXT_CONV );
if( !needsIV( contextInfoPtr->ctxConv->mode ) || \
isStreamCipher( capabilityInfoPtr->cryptAlgo ) )
return( CRYPT_ERROR_NOTAVAIL );
*valuePtr = capabilityInfoPtr->blockSize;
return( CRYPT_OK );
case CRYPT_CTXINFO_KEYING_ALGO:
case CRYPT_OPTION_KEYING_ALGO:
switch( contextType )
{
case CONTEXT_CONV:
value = contextInfoPtr->ctxConv->keySetupAlgorithm;
break;
case CONTEXT_MAC:
value = contextInfoPtr->ctxMAC->keySetupAlgorithm;
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR );
}
if( value <= 0 )
return( exitErrorNotInited( contextInfoPtr,
CRYPT_CTXINFO_KEYING_ALGO ) );
*valuePtr = value;
return( CRYPT_OK );
case CRYPT_CTXINFO_KEYING_ITERATIONS:
case CRYPT_OPTION_KEYING_ITERATIONS:
switch( contextType )
{
case CONTEXT_CONV:
value = contextInfoPtr->ctxConv->keySetupIterations;
break;
case CONTEXT_MAC:
value = contextInfoPtr->ctxMAC->keySetupIterations;
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR );
}
if( value <= 0 )
return( exitErrorNotInited( contextInfoPtr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -