📄 dev_sys.c
字号:
static const CREATEOBJECT_FUNCTION_INFO createObjectFunctions[] = {
{ OBJECT_TYPE_CONTEXT, createContext },
{ OBJECT_TYPE_CERTIFICATE, createCertificate },
{ OBJECT_TYPE_ENVELOPE, createEnvelope },
{ OBJECT_TYPE_KEYSET, createKeyset },
{ OBJECT_TYPE_DEVICE, createDevice },
{ OBJECT_TYPE_SESSION, createSession },
{ OBJECT_TYPE_USER, createUser },
{ OBJECT_TYPE_NONE, NULL }
};
/* Initialise and shut down the system device */
static void shutdownFunction( DEVICE_INFO *deviceInfo )
{
/* Call any special-case shutdown functions */
endRandomPolling();
endX917( deviceInfo->randomInfo );
/* Delete the random data pool */
if( deviceInfo->randomInfo != NULL )
krnlMemfree( ( void ** ) &deviceInfo->randomInfo );
}
static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
const int nameLength )
{
STATIC_FN void initCapabilities( void );
int status;
UNUSED( name );
/* Set up the random data pool */
if( ( status = krnlMemalloc( ( void ** ) &deviceInfo->randomInfo,
sizeof( RANDOM_INFO ) ) ) != CRYPT_OK )
return( status );
initRandomPool( deviceInfo->randomInfo );
if( ( status = initX917( deviceInfo->randomInfo ) ) != CRYPT_OK )
{
krnlMemfree( ( void ** ) &deviceInfo->randomInfo );
return( status );
}
initRandomPolling();
/* Set up the capability information for this device and mark it as
active */
initCapabilities();
deviceInfo->flags = DEVICE_ACTIVE | DEVICE_LOGGEDIN;
return( CRYPT_OK );
}
/* Handle device control functions */
static int controlFunction( DEVICE_INFO *deviceInfo,
const CRYPT_ATTRIBUTE_TYPE type,
const void *data1, const int data1Length,
const void *data2, const int data2Length )
{
RANDOM_INFO *randomInfo = deviceInfo->randomInfo;
BYTE *buffer = ( BYTE * ) data1;
int count = data1Length;
assert( type == CRYPT_IATTRIBUTE_RANDOM || \
type == CRYPT_IATTRIBUTE_RANDOM_QUALITY || \
type == CRYPT_IATTRIBUTE_SELFTEST );
/* Handle random data management */
if( type == CRYPT_IATTRIBUTE_RANDOM )
{
/* Mix the incoming data into the pool. This operation is resistant
to chosen- and known-input attacks because the pool contents are
unknown to an attacker, so XOR'ing in known data won't help them.
In an attacker could determine pool contents by observing the
generator output (which is defeated by the postprocessing), we'd
have to perform an extra input mixing operation to defeat these
attacks */
while( count-- )
{
if( randomInfo->randomPoolPos > RANDOMPOOL_SIZE - 1 )
mixRandomPool( randomInfo );
randomInfo->randomPool[ randomInfo->randomPoolPos++ ] ^= *buffer++;
}
return( CRYPT_OK );
}
if( type == CRYPT_IATTRIBUTE_RANDOM_QUALITY )
{
if( randomInfo->randomQuality < 100 )
randomInfo->randomQuality += data1Length;
return( CRYPT_OK );
}
/* Handle algorithm self-test */
if( type == CRYPT_IATTRIBUTE_SELFTEST )
{
const CAPABILITY_INFO *capabilityInfoPtr = deviceInfo->capabilityInfo;
while( capabilityInfoPtr != NULL )
{
const CRYPT_ALGO cryptAlgo = capabilityInfoPtr->cryptAlgo;
int status;
assert( capabilityInfoPtr->selfTestFunction != NULL );
/* Perform the self-test for this algorithm type and skip to the
next algorithm */
status = capabilityInfoPtr->selfTestFunction();
if( cryptStatusError( status ) )
return( status );
while( capabilityInfoPtr != NULL && \
capabilityInfoPtr->cryptAlgo == cryptAlgo )
capabilityInfoPtr = capabilityInfoPtr->next;
}
return( CRYPT_OK );
}
/* Anything else isn't handled */
return( CRYPT_ARGERROR_VALUE );
}
/****************************************************************************
* *
* Misc.Device Interface Routines *
* *
****************************************************************************/
/* Get a block of random data from the randomness pool in such a way that
compromise of the data doesn't compromise the pool, and vice versa. This
is done by performing the (one-way) pool mixing operation on the pool, and
on a transformed version of the pool which becomes the key. The
transformed version of the pool from which the key data will be drawn is
then further processed by running each 64-bit block through the X9.17
generator. As an additional precaution the key data is folded in half to
ensure that not even a hashed or encrypted form of the previous contents
is available. No pool data ever leaves the pool.
This function performs a more paranoid version of the FIPS 140 continuous
test on both the main pool contents and the X9.17 generator output which
will detect stuck-at faults and short cycles in the output. In addition
the higher-level message handler applies the FIPS 140 statistical tests
to the output and will retry the get if the output fails the tests (this
is performed at the higher level because it's then applied to all
randomness sources used by cryptlib, not just the built-in one).
Since the pool output is folded to mask the output, the output from each
round of mixing is only half the pool size as defined below */
#define RANDOM_OUTPUTSIZE ( RANDOMPOOL_SIZE / 2 )
static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
const int length )
{
RANDOM_INFO *randomInfo = deviceInfo->randomInfo;
RANDOM_INFO exportedRandomInfo;
BYTE *bufPtr = buffer;
int count;
/* Clear the return value and make sure we fail the FIPS 140 tests on
the output if there's a problem */
zeroise( buffer, length );
/* Precondition: We're not asking for more data than the maximum needed
in any cryptlib operation, which in this case is the size of a
maximum-length PKC key */
PRE( length >= 1 && length <= CRYPT_MAX_PKCSIZE );
/* Perform a failsafe check to make sure there's data available, this
should only ever be called once per app because after the first
blocking poll the programmer of the calling app will make sure there's
a slow poll done earlier on */
if( randomInfo->randomQuality < 100 )
slowPoll();
/* Make sure any background randomness-gathering process has finished.
Since the background poll will be injecting new data into the device,
we have to unlock it to avoid deadlock */
unlockResource( deviceInfo );
waitforRandomCompletion();
lockResource( deviceInfo );
/* If we still can't get any random information, let the user know */
if( randomInfo->randomQuality < 100 )
return( CRYPT_ERROR_RANDOM );
/* If the process has forked, we need to restart the generator output
process, but we can't determine this until after we've already
produced the output. If we do need to restart, we do it from this
point */
restartPoint:
/* Keep producing RANDOMPOOL_OUTPUTSIZE bytes of output until the request
is satisfied */
for( count = 0; count < length; count += RANDOM_OUTPUTSIZE )
{
LONG sample, x917Sample;
const int outputBytes = min( length - count, RANDOM_OUTPUTSIZE );
int noRandomRetries, i;
ORIGINAL_PTR( bufPtr );
/* Precondition for output quantity: Either we're on the last output
block or we're producing the maximum-size output quantity, and
we're never trying to use more than half the pool contents */
PRE( length - count < RANDOM_OUTPUTSIZE || \
outputBytes == RANDOM_OUTPUTSIZE );
PRE( outputBytes <= RANDOMPOOL_SIZE / 2 );
/* Prepare to get data from the randomness pool. Before we do this,
we perform a final quick poll of the system to get any last bit of
entropy, and mix the entire pool. If the pool hasn't been
sufficiently mixed, we iterate until we've reached the minimum mix
count */
do
{
fastPoll();
mixRandomPool( randomInfo );
randomInfo->randomPoolMixes++;
}
while( randomInfo->randomPoolMixes < RANDOMPOOL_MIXES );
/* If the X9.17 generator cryptovariables haven't been initialised
yet or have reached their use-by date, set the generator key and
seed from the pool contents, then mix the pool and crank the
generator twice to obscure the data which was used */
if( !randomInfo->x917Inited || \
randomInfo->x917Count >= X917_MAX_CYCLES )
{
setKeyX917( randomInfo, randomInfo->randomPool,
randomInfo->randomPool + X917_KEYSIZE );
mixRandomPool( randomInfo );
generateX917( randomInfo, randomInfo->randomPool,
RANDOMPOOL_ALLOCSIZE );
mixRandomPool( randomInfo );
generateX917( randomInfo, randomInfo->randomPool,
RANDOMPOOL_ALLOCSIZE );
}
/* Precondition for drawing output from the generator: The pool is
sufficiently mixed, there's enough entropy present, and the X9.17
postprocessor is ready for use */
PRE( randomInfo->randomPoolMixes >= RANDOMPOOL_MIXES );
PRE( randomInfo->randomQuality >= 100 );
PRE( randomInfo->x917Inited );
for( noRandomRetries = 0; noRandomRetries < RANDOMPOOL_RETRIES;
noRandomRetries++ )
{
const BYTE *samplePtr = randomInfo->randomPool;
const BYTE *x917SamplePtr = exportedRandomInfo.randomPool;
BOOLEAN repeatedOutput = FALSE;
/* Initialise the copy of the random pool being used to generate
the key and copy the main pool information across,
transforming it as we go by flipping all the bits */
initRandomPool( &exportedRandomInfo );
for( i = 0; i < RANDOMPOOL_ALLOCSIZE; i++ )
exportedRandomInfo.randomPool[ i ] = \
randomInfo->randomPool[ i ] ^ 0xFF;
/* Postcondition for the bit-flipping: The two pools differ, and
the difference is in the flipped bits */
POST( memcmp( randomInfo->randomPool,
exportedRandomInfo.randomPool,
RANDOMPOOL_ALLOCSIZE ) );
FORALL( i, 0, RANDOMPOOL_ALLOCSIZE, \
randomInfo->randomPool[ i ] == \
( exportedRandomInfo.randomPool[ i ] ^ 0xFF ) );
/* Mix the original and key pools so that neither can be
recovered from the other */
mixRandomPool( randomInfo );
mixRandomPool( &exportedRandomInfo );
/* Postcondition for the mixing: The two pools differ, and the
difference is more than just the bit flipping (this has a
1e-12 chance of a false positive and even that's only in the
debug version) */
POST( memcmp( randomInfo->randomPool,
exportedRandomInfo.randomPool,
RANDOMPOOL_ALLOCSIZE ) );
POST( randomInfo->randomPool[ 0 ] != \
( exportedRandomInfo.randomPool[ 0 ] ^ 0xFF ) ||
randomInfo->randomPool[ 8 ] != \
( exportedRandomInfo.randomPool[ 8 ] ^ 0xFF ) ||
randomInfo->randomPool[ 16 ] != \
( exportedRandomInfo.randomPool[ 16 ] ^ 0xFF ) ||
randomInfo->randomPool[ 24 ] != \
( exportedRandomInfo.randomPool[ 24 ] ^ 0xFF ) ||
randomInfo->randomPool[ 32 ] != \
( exportedRandomInfo.randomPool[ 32 ] ^ 0xFF ) );
/* Precondition for sampling the output: It's a sample from the
start of the pool */
PRE( samplePtr == randomInfo->randomPool );
PRE( x917SamplePtr == exportedRandomInfo.randomPool );
/* Check for stuck-at faults by comparing a short sample from the
current output with samples from the previous
RANDOMPOOL_SAMPLES outputs */
sample = mgetLong( samplePtr );
for( i = 0; i < RANDOMPOOL_SAMPLES; i++ )
if( randomInfo->prevOutput[ i ] == sample )
{
repeatedOutput = TRUE;
break;
}
if( repeatedOutput )
continue; /* We're repeating previous output, try again */
repeatedOutput = FALSE;
/* Process the exported pool with the X9.17 generator */
generateX917( randomInfo, exportedRandomInfo.randomPool,
RANDOMPOOL_ALLOCSIZE );
/* Check for stuck-at faults in the X9.17 generator by comparing
a short sample from the current output with samples from the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -