📄 system.c
字号:
CHECK_RETVAL \
static int initCapabilities( void ); /* Fwd.dec for fn.*/
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int initFunction( INOUT DEVICE_INFO *deviceInfo,
STDC_UNUSED const char *name,
STDC_UNUSED const int nameLength )
{
int status;
assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
REQUIRES( name == NULL && nameLength == 0 );
/* Set up the capability information for this device */
status = initCapabilities();
if( cryptStatusError( status ) )
return( status );
/* Set up the randomness info */
status = initRandomInfo( &deviceInfo->randomInfo );
if( cryptStatusError( status ) )
return( status );
/* Complete the initialisation and mark the device as active */
deviceInfo->label = "cryptlib system device";
deviceInfo->labelLen = strlen( deviceInfo->label );
deviceInfo->flags = DEVICE_ACTIVE | DEVICE_LOGGEDIN | DEVICE_TIME;
return( CRYPT_OK );
}
STDC_NONNULL_ARG( ( 1 ) ) \
static void shutdownFunction( INOUT DEVICE_INFO *deviceInfo )
{
assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
endRandomInfo( &deviceInfo->randomInfo );
}
/* Perform a self-test */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int selftestFunction( INOUT DEVICE_INFO *deviceInfo,
INOUT MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
{
CAPABILITY_INFO_LIST **capabilityInfoListPtrPtr = \
( CAPABILITY_INFO_LIST ** ) &deviceInfo->capabilityInfoList;
BYTE buffer[ 8 + 8 ];
int refCount, status;
assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
assert( isWritePtr( messageExtInfo, \
sizeof( MESSAGE_FUNCTION_EXTINFO ) ) );
/* The self-tests need randomness for some of their operations, in order
to pre-empt a lack of this from causing a failure somewhere deep down
in the crypto code we perform a dummy read of first the randomness
source and then the nonce source to force a full initialisation of
the randomness subsystem */
status = deviceInfo->getRandomFunction( deviceInfo, buffer, 8, NULL );
if( cryptStatusError( status ) )
return( status );
zeroise( buffer, 8 );
status = getNonce( deviceInfo->deviceSystem, buffer, 8 );
if( cryptStatusError( status ) )
return( status );
zeroise( buffer, 8 );
/* Perform an algorithm self-test */
status = algorithmSelfTest( capabilityInfoListPtrPtr );
if( cryptStatusError( status ) )
return( status );
/* Perform the mechanism self-test. Since this can be quite lengthy and
requires recursive handling of messages by the system object (without
actually requiring access to system object state) we unlock it to
avoid it becoming a bottleneck */
status = krnlSuspendObject( deviceInfo->objectHandle, &refCount );
if( cryptStatusError( status ) )
return( status );
setMessageObjectUnlocked( messageExtInfo );
return( mechanismSelfTest() );
}
/* Get random data. We have to unlock the device around the randomness
fetch because background polling threads need to be able to send entropy
data to it:
System Randomness
------ ----------
getRand ------>| |
[Suspend] |
|--------------->|
| |
|<===============| Entropy
|<===============| Entropy
|<===============| Entropy Quality
| |
|<---------------|
[Resume] |
If the caller has specified that it's unlockable and the reference count
is one or less (meaning that we've been sent the message directly), we
leave it unlocked. Otherwise we re-lock it afterwards.
Note that there's a tiny chance of a race condition if the system object
is destroyed between the unlock and the acquisition of the randomness
mutex (which means that the randomInfo could be freed while we're getting
the random data), however there's no easy way around this short of using
a complex multiple-mutex interlock, and in any case there's only so much
that we can do to help a user who pulls data structures out from under
active threads */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int getRandomFunction( INOUT DEVICE_INFO *deviceInfo,
OUT_BUFFER_FIXED( length ) void *buffer,
IN_LENGTH_SHORT const int length,
INOUT_OPT MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
{
int refCount, status;
assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
assert( isWritePtr( buffer, length ) );
REQUIRES( length > 0 && length < MAX_INTLENGTH_SHORT );
/* Clear the return value and make sure that we fail the FIPS 140 tests
on the output if there's a problem */
zeroise( buffer, length );
/* If the system device is already unlocked (which can happen if this
function is called in a loop, for example if multiple chunks of
randomness are read) just return the randomness directly */
if( messageExtInfo != NULL && isMessageObjectUnlocked( messageExtInfo ) )
return( getRandomData( deviceInfo->randomInfo, buffer, length ) );
/* Unlock the system device, get the data, and re-lock it if necessary */
status = krnlSuspendObject( deviceInfo->objectHandle, &refCount );
if( cryptStatusError( status ) )
return( status );
status = getRandomData( deviceInfo->randomInfo, buffer, length );
if( messageExtInfo == NULL || refCount > 1 )
{
/* The object isn't unlockable or it's been locked recursively,
re-lock it */
status = krnlResumeObject( SYSTEM_OBJECT_HANDLE, refCount );
if( cryptStatusError( status ) )
{
/* We couldn't re-lock the system object, let the caller know.
Since this is a shouldn't-occur condition we also warn the
user in the debug version */
assert( DEBUG_WARN );
if( messageExtInfo != NULL )
setMessageObjectUnlocked( messageExtInfo );
}
}
else
{
/* Tell the caller that we've left the object unlocked so they don't
have to do anything further with it */
setMessageObjectUnlocked( messageExtInfo );
}
return( status );
}
/* Handle device control functions */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int controlFunction( INOUT DEVICE_INFO *deviceInfo,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type,
IN_BUFFER_OPT( dataLength ) void *data,
IN_LENGTH_SHORT_Z const int dataLength,
INOUT_OPT MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
{
int refCount, status;
assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
assert( data == NULL || isReadPtr( data, dataLength ) );
REQUIRES( type == CRYPT_IATTRIBUTE_ENTROPY || \
type == CRYPT_IATTRIBUTE_ENTROPY_QUALITY || \
type == CRYPT_IATTRIBUTE_RANDOM_POLL || \
type == CRYPT_IATTRIBUTE_RANDOM_NONCE || \
type == CRYPT_IATTRIBUTE_TIME );
/* Handle entropy addition. Since this can take awhile, we do it with
the system object unlocked. See the comment in getRandomFunction()
about the possibility of a race condition */
if( type == CRYPT_IATTRIBUTE_ENTROPY )
{
status = krnlSuspendObject( deviceInfo->objectHandle, &refCount );
if( cryptStatusError( status ) )
return( status );
setMessageObjectUnlocked( messageExtInfo );
return( addEntropyData( deviceInfo->randomInfo, data, dataLength ) );
}
if( type == CRYPT_IATTRIBUTE_ENTROPY_QUALITY )
{
status = krnlSuspendObject( deviceInfo->objectHandle, &refCount );
if( cryptStatusError( status ) )
return( status );
setMessageObjectUnlocked( messageExtInfo );
return( addEntropyQuality( deviceInfo->randomInfo, dataLength ) );
}
if( type == CRYPT_IATTRIBUTE_RANDOM_POLL )
{
status = krnlSuspendObject( deviceInfo->objectHandle, &refCount );
if( cryptStatusError( status ) )
return( status );
setMessageObjectUnlocked( messageExtInfo );
/* Perform a slow or fast poll as required */
if( dataLength == TRUE )
slowPoll();
else
fastPoll();
return( CRYPT_OK );
}
/* Handle nonces */
if( type == CRYPT_IATTRIBUTE_RANDOM_NONCE )
return( getNonce( deviceInfo->deviceSystem, data, dataLength ) );
/* Handle high-reliability time */
if( type == CRYPT_IATTRIBUTE_TIME )
{
time_t *timePtr = ( time_t * ) data;
*timePtr = getTime();
return( CRYPT_OK );
}
retIntError();
}
/****************************************************************************
* *
* Device Capability Routines *
* *
****************************************************************************/
/* The cryptlib intrinsic capability list */
#define MAX_NO_CAPABILITIES 32
static const GETCAPABILITY_FUNCTION FAR_BSS getCapabilityTable[] = {
get3DESCapability,
#ifdef USE_AES
getAESCapability,
#endif /* USE_AES */
#ifdef USE_BLOWFISH
getBlowfishCapability,
#endif /* USE_BLOWFISH */
#ifdef USE_CAST
getCASTCapability,
#endif /* USE_CAST */
getDESCapability,
#ifdef USE_IDEA
getIDEACapability,
#endif /* USE_IDEA */
#ifdef USE_RC2
getRC2Capability,
#endif /* USE_RC2 */
#ifdef USE_RC4
getRC4Capability,
#endif /* USE_RC4 */
#ifdef USE_RC5
getRC5Capability,
#endif /* USE_RC5 */
#ifdef USE_SKIPJACK
getSkipjackCapability,
#endif /* USE_SKIPJACK */
#ifdef USE_MD2
getMD2Capability,
#endif /* USE_MD2 */
#ifdef USE_MD4
getMD4Capability,
#endif /* USE_MD4 */
#ifdef USE_MD5
getMD5Capability,
#endif /* USE_MD5 */
#ifdef USE_RIPEMD160
getRipemd160Capability,
#endif /* USE_RIPEMD160 */
getSHA1Capability,
#ifdef USE_SHA2
getSHA2Capability,
#endif /* USE_SHA2 */
#ifdef USE_HMAC_MD5
getHmacMD5Capability,
#endif /* USE_HMAC_MD5 */
#ifdef USE_HMAC_RIPEMD160
getHmacRipemd160Capability,
#endif /* USE_HMAC_RIPEMD160 */
getHmacSHA1Capability,
#ifdef USE_HMAC_SHA2
getHmacSHA2Capability,
#endif /* USE_SHA2 */
#ifdef USE_DH
getDHCapability,
#endif /* USE_DH */
#ifdef USE_DSA
getDSACapability,
#endif /* USE_DSA */
#ifdef USE_ELGAMAL
getElgamalCapability,
#endif /* USE_ELGAMAL */
#ifdef USE_RSA
getRSACapability,
#endif /* USE_RSA */
#ifdef USE_ECC
getECDSACapability,
#endif /* USE_ECC */
/* Vendors may want to use their own algorithms, which aren't part of the
general cryptlib suite. The following provides the ability to include
vendor-specific algorithm capabilities defined in the file
vendalgo.c */
#ifdef USE_VENDOR_ALGOS
#include "vendalgo.c"
#endif /* USE_VENDOR_ALGOS */
/* End-of-list marker */
NULL, NULL
};
static CAPABILITY_INFO_LIST FAR_BSS capabilityInfoList[ MAX_NO_CAPABILITIES ];
/* Initialise the capability info */
CHECK_RETVAL \
static int initCapabilities( void )
{
int i;
/* Perform a consistency check on the encryption mode values, which
are used to index a table of per-mode function pointers */
assert( CRYPT_MODE_CBC == CRYPT_MODE_ECB + 1 && \
CRYPT_MODE_CFB == CRYPT_MODE_CBC + 1 && \
CRYPT_MODE_OFB == CRYPT_MODE_CFB + 1 && \
CRYPT_MODE_LAST == CRYPT_MODE_OFB + 1 );
/* Build the list of available capabilities */
memset( capabilityInfoList, 0,
sizeof( CAPABILITY_INFO_LIST ) * MAX_NO_CAPABILITIES );
for( i = 0;
getCapabilityTable[ i ] != NULL && \
i < FAILSAFE_ARRAYSIZE( getCapabilityTable, GETCAPABILITY_FUNCTION );
i++ )
{
const CAPABILITY_INFO *capabilityInfoPtr = getCapabilityTable[ i ]();
REQUIRES( sanityCheckCapability( capabilityInfoPtr, FALSE ) );
capabilityInfoList[ i ].info = capabilityInfoPtr;
capabilityInfoList[ i ].next = NULL;
if( i > 0 )
capabilityInfoList[ i - 1 ].next = &capabilityInfoList[ i ];
}
REQUIRES( i < FAILSAFE_ARRAYSIZE( getCapabilityTable, \
GETCAPABILITY_FUNCTION ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Device Access Routines *
* *
****************************************************************************/
/* Set up the function pointers to the device methods */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int setDeviceSystem( INOUT DEVICE_INFO *deviceInfo )
{
assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
deviceInfo->initFunction = initFunction;
deviceInfo->shutdownFunction = shutdownFunction;
deviceInfo->controlFunction = controlFunction;
deviceInfo->selftestFunction = selftestFunction;
deviceInfo->getRandomFunction = getRandomFunction;
deviceInfo->capabilityInfoList = capabilityInfoList;
deviceInfo->createObjectFunctions = createObjectFunctions;
deviceInfo->createObjectFunctionCount = \
FAILSAFE_ARRAYSIZE( createObjectFunctions, CREATEOBJECT_FUNCTION_INFO );
deviceInfo->mechanismFunctions = mechanismFunctions;
deviceInfo->mechanismFunctionCount = \
FAILSAFE_ARRAYSIZE( mechanismFunctions, MECHANISM_FUNCTION_INFO );
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -