📄 cryptdev.c
字号:
/****************************************************************************
* *
* cryptlib Crypto Device Routines *
* Copyright Peter Gutmann 1997-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
#include "device.h"
#else
#include "misc/device.h"
#endif /* Compiler-specific includes */
/* When we get random data from a device, we run the (practical) FIPS 140
tests over the output to make sure it's really random (at least as far
as the tests can tell us). If the data fails the test, we get more and
try again. The following value defines how many times we retry before
giving up. In test runs, a count of 2 failures is reached every ~50,000
iterations, 5 is never reached (in fact with 1M tests, 3 is never
reached) */
#define NO_ENTROPY_FAILURES 5
/* Some device types aren't supported on some platforms, so we replace a
call to the mapping function with an error code */
#ifndef __WINDOWS__
#define setDeviceFortezza( x ) CRYPT_ARGERROR_NUM1
#endif /* !__WINDOWS__ */
#ifndef DEV_PKCS11
#define setDevicePKCS11( x, y, z ) CRYPT_ARGERROR_NUM1
#endif /* !DEV_PKCS11 */
/* Prototypes for functions in crypt.c */
const void FAR_BSS *findCapabilityInfo( const void FAR_BSS *capabilityInfoPtr,
const CRYPT_ALGO cryptAlgo );
void copyCapabilityInfo( const void FAR_BSS *capabilityInfoPtr,
CRYPT_QUERY_INFO *cryptQueryInfo );
/* Prototypes for functions in cryptmis.c */
BOOLEAN checkEntropy( const BYTE *data, const int dataLength );
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Initialise and down any devices we're working with */
void deviceInitFortezza( void );
void deviceEndFortezza( void );
void deviceInitPKCS11( void );
void deviceEndPKCS11( void );
void initDevices( void )
{
#if defined( __WINDOWS__ ) && !defined( NT_DRIVER )
deviceInitFortezza();
#endif /* __WINDOWS__ && !NT_DRIVER */
#ifdef DEV_PKCS11
deviceInitPKCS11();
#endif /* DEV_PKCS11 */
}
void shutdownDevices( void )
{
#if defined( __WINDOWS__ ) && !defined( NT_DRIVER )
deviceEndFortezza();
#endif /* __WINDOWS__ && !NT_DRIVER */
#ifdef DEV_PKCS11
deviceEndPKCS11();
#endif /* DEV_PKCS11 */
}
/* Get a random data block with FIPS 140 checking */
static int getRandomData( DEVICE_INFO *deviceInfoPtr, void *data,
const int length )
{
int i;
/* Get random data from the device and check it using the FIPS 140
tests. If it's less than 64 bits we let it pass since the sample
size is too small to be useful, samples this small are only ever
drawn from the generator for use as padding with crypto keys which
are always >= 64 bits, so a problem with the generator will be
detected even if we don't check small samples */
for( i = 0; i < NO_ENTROPY_FAILURES; i++ )
{
int status;
status = deviceInfoPtr->getRandomFunction( deviceInfoPtr, data,
length );
if( cryptStatusOK( status ) && \
( length < 8 || checkEntropy( data, length ) ) )
return( CRYPT_OK );
}
/* We couldn't get anything which passed the FIPS 140 tests, we can't
go any further */
zeroise( data, length );
assert( NOTREACHED );
return( CRYPT_ERROR_RANDOM );
}
/****************************************************************************
* *
* Device API Functions *
* *
****************************************************************************/
/* Default object creation routines used when the device code doesn't set
anything up */
int createContext( MESSAGE_CREATEOBJECT_INFO *createInfo,
const void *auxDataPtr, const int auxValue );
static const CREATEOBJECT_FUNCTION_INFO defaultCreateFunctions[] = {
{ OBJECT_TYPE_CONTEXT, createContext },
{ OBJECT_TYPE_NONE, NULL }
};
/* Handle a message sent to a device object */
static int deviceMessageFunction( const CRYPT_DEVICE cryptDevice,
const RESOURCE_MESSAGE_TYPE message,
void *messageDataPtr,
const int messageValue )
{
DEVICE_INFO *deviceInfoPtr;
getCheckInternalResource( cryptDevice, deviceInfoPtr, OBJECT_TYPE_DEVICE );
/* Process the destroy object message */
if( message == RESOURCE_MESSAGE_DESTROY )
{
/* Shut down the device if required */
if( deviceInfoPtr->flags & DEVICE_ACTIVE && \
deviceInfoPtr->shutdownFunction != NULL )
deviceInfoPtr->shutdownFunction( deviceInfoPtr );
/* Delete the objects locking variables and the object itself */
unlockResource( deviceInfoPtr );
deleteResourceLock( deviceInfoPtr );
zeroise( deviceInfoPtr, sizeof( DEVICE_INFO ) );
free( deviceInfoPtr );
return( CRYPT_OK );
}
/* Process attribute get/set/delete messages */
if( message == RESOURCE_MESSAGE_SETATTRIBUTE )
{
int status;
/* If it's an initialisation message, there's nothing to do */
if( messageValue == CRYPT_IATTRIBUTE_INITIALISED )
unlockResourceExit( deviceInfoPtr, CRYPT_OK );
/* Send the control information to the device */
status = deviceInfoPtr->controlFunction( deviceInfoPtr, messageValue,
NULL, *( ( int * ) messageDataPtr ), NULL, 0 );
unlockResourceExit( deviceInfoPtr, status );
}
if( message == RESOURCE_MESSAGE_SETATTRIBUTE_S )
{
const RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int status;
/* Make sure the device which can handle device control attributes */
if( deviceInfoPtr->controlFunction == NULL )
unlockResourceExit( deviceInfoPtr, CRYPT_ARGERROR_VALUE );
/* If it's a PIN attribute, make sure that a login is actually
required for the device */
if( ( messageValue == CRYPT_DEVINFO_AUTHENT_USER || \
messageValue == CRYPT_DEVINFO_AUTHENT_SUPERVISOR ) && \
!( deviceInfoPtr->flags & DEVICE_NEEDSLOGIN ) )
unlockResourceExit( deviceInfoPtr, CRYPT_ERROR_INITED );
/* If it's a PIN attribute, make sure the supplied PIN is valid */
if( messageValue == CRYPT_DEVINFO_INITIALISE || \
messageValue == CRYPT_DEVINFO_AUTHENT_USER || \
messageValue == CRYPT_DEVINFO_AUTHENT_SUPERVISOR || \
messageValue == CRYPT_DEVINFO_SET_AUTHENT_USER || \
messageValue == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR || \
messageValue == CRYPT_DEVINFO_ZEROISE )
if( msgData->length < deviceInfoPtr->minPinSize || \
msgData->length > deviceInfoPtr->maxPinSize )
unlockResourceExit( deviceInfoPtr, CRYPT_ARGERROR_NUM1 );
/* Send the control information to the device */
status = deviceInfoPtr->controlFunction( deviceInfoPtr, messageValue,
msgData->data, msgData->length, NULL, 0 );
unlockResourceExit( deviceInfoPtr, status );
}
if( message == RESOURCE_MESSAGE_GETATTRIBUTE )
{
int *valuePtr = ( int * ) messageDataPtr;
switch( messageValue )
{
case CRYPT_ATTRIBUTE_ERRORTYPE:
*valuePtr = deviceInfoPtr->errorType;
break;
case CRYPT_ATTRIBUTE_ERRORLOCUS:
*valuePtr = deviceInfoPtr->errorLocus;
break;
case CRYPT_ATTRIBUTE_INT_ERRORCODE:
*valuePtr = deviceInfoPtr->errorCode;
break;
case CRYPT_DEVINFO_LOGGEDIN:
*valuePtr = ( deviceInfoPtr->flags & DEVICE_LOGGEDIN ) ? \
TRUE : FALSE;
break;
default:
assert( NOTREACHED );
}
unlockResourceExit( deviceInfoPtr, CRYPT_OK );
}
if( message == RESOURCE_MESSAGE_GETATTRIBUTE_S )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int status = CRYPT_ERROR_NOTAVAIL;
switch( messageValue )
{
case CRYPT_ATTRIBUTE_INT_ERRORMESSAGE:
if( !*deviceInfoPtr->errorMessage )
status = CRYPT_ERROR_NOTFOUND;
else
status = attributeCopy( msgData, deviceInfoPtr->errorMessage,
strlen( deviceInfoPtr->errorMessage ) );
break;
case CRYPT_DEVINFO_LABEL:
if( !*deviceInfoPtr->label )
status = CRYPT_ERROR_NOTFOUND;
else
status = attributeCopy( msgData, deviceInfoPtr->label,
strlen( deviceInfoPtr->label ) );
break;
case CRYPT_IATTRIBUTE_RANDOM:
if( deviceInfoPtr->getRandomFunction != NULL )
status = getRandomData( deviceInfoPtr, msgData->data,
msgData->length );
break;
case CRYPT_IATTRIBUTE_RANDOM_NZ:
if( deviceInfoPtr->getRandomFunction != NULL )
{
BYTE randomBuffer[ 128 ], *outBuffer = msgData->data;
int count = msgData->length;
/* The extraction of data is a little complex because we
don't know how much data we'll need (as a rule of
thumb it'll be size + ( size / 256 ) bytes, but in a
worst-case situation we could need to draw out
megabytes of data), so we copy out 128 bytes worth at
a time (a typical value for a 1K bit key) and keep
going until we've filled the output requirements */
while( count )
{
int i;
/* Copy as much as we can from the randomness pool */
status = getRandomData( deviceInfoPtr, randomBuffer,
128 );
if( cryptStatusError( status ) )
break;
for( i = 0; count && i < 128; i++ )
if( randomBuffer[ i ] )
{
*outBuffer++ = randomBuffer[ i ];
count--;
}
}
zeroise( randomBuffer, 128 );
if( cryptStatusError( status ) )
zeroise( msgData->data, msgData->length );
}
break;
default:
assert( NOTREACHED );
}
unlockResourceExit( deviceInfoPtr, status );
}
/* Process action messages */
if( isMechanismActionMessage( message ) )
{
CRYPT_DEVICE localCryptDevice = cryptDevice;
MECHANISM_FUNCTION mechanismFunction = NULL;
int status;
/* Find the function to handle this action and mechanism */
if( deviceInfoPtr->mechanismFunctions != NULL )
{
int i = 0;
while( deviceInfoPtr->mechanismFunctions[ i ].action != RESOURCE_MESSAGE_NONE )
{
if( deviceInfoPtr->mechanismFunctions[ i ].action == message && \
deviceInfoPtr->mechanismFunctions[ i ].mechanism == messageValue )
{
mechanismFunction = \
deviceInfoPtr->mechanismFunctions[ i ].function;
break;
}
i++;
}
}
if( mechanismFunction == NULL )
{
/* If this is the system object and it can't handle this
mechanism, we can't go any further */
unlockResource( deviceInfoPtr );
if( localCryptDevice == SYSTEM_OBJECT_HANDLE )
return( CRYPT_ERROR_NOTAVAIL );
/* This isn't the system object, fall back to the system object
and see if it can handle the mechanism. We do it this way
rather than sending the message through the kernel a second
time because all the kernel checking of message parameters has
already been done (in terms of access control checks, we can
always send the message to the system object so this isn't a
problem), this saves the overhead of a second, redundant
kernel pass */
getCheckInternalResource( SYSTEM_OBJECT_HANDLE, deviceInfoPtr,
OBJECT_TYPE_DEVICE );
if( deviceInfoPtr->mechanismFunctions != NULL )
{
int i = 0;
while( deviceInfoPtr->mechanismFunctions[ i ].action != RESOURCE_MESSAGE_NONE )
{
if( deviceInfoPtr->mechanismFunctions[ i ].action == message && \
deviceInfoPtr->mechanismFunctions[ i ].mechanism == messageValue )
{
mechanismFunction = \
deviceInfoPtr->mechanismFunctions[ i ].function;
break;
}
i++;
}
}
unlockResource( deviceInfoPtr );
if( mechanismFunction == NULL )
return( CRYPT_ERROR_NOTAVAIL );
/* The system object can handle this mechanism, forward the
message on to the appropriate handler */
return( mechanismFunction( NULL, messageDataPtr ) );
}
/* If the message has been sent to the system object, unlock it to
allow it to be used by others and dispatch the message */
if( localCryptDevice == SYSTEM_OBJECT_HANDLE )
{
unlockResource( deviceInfoPtr );
return( mechanismFunction( NULL, messageDataPtr ) );
}
/* Send the message to the device */
status = mechanismFunction( deviceInfoPtr, messageDataPtr );
unlockResourceExit( deviceInfoPtr, status );
}
/* Process messages which check a device. In some cases a device can act
as a keyset, so if the device could store keys of this type we report
it as being an appropriate keyset */
if( message == RESOURCE_MESSAGE_CHECK )
{
if( ( messageValue == RESOURCE_MESSAGE_CHECK_PKC_ENCRYPT || \
messageValue == RESOURCE_MESSAGE_CHECK_PKC_DECRYPT || \
messageValue == RESOURCE_MESSAGE_CHECK_PKC_SIGCHECK || \
messageValue == RESOURCE_MESSAGE_CHECK_PKC_SIGN ) && \
( deviceInfoPtr->type == CRYPT_DEVICE_FORTEZZA || \
deviceInfoPtr->type == CRYPT_DEVICE_PKCS11 ) )
unlockResourceExit( deviceInfoPtr, CRYPT_OK );
unlockResourceExit( deviceInfoPtr, CRYPT_ARGERROR_OBJECT );
}
/* Process messages which lock/unlock an object for exclusive use */
if( message == RESOURCE_MESSAGE_LOCK )
/* Exit without unlocking the object. Any other threads trying to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -