📄 cryptdev.c
字号:
status = createObjectFunction( messageDataPtr, auxInfo,
CREATEOBJECT_FLAG_DUMMY );
}
if( cryptStatusError( status ) )
return( status );
/* Make the newly-created object a dependent object of the device */
return( krnlSendMessage( \
( ( MESSAGE_CREATEOBJECT_INFO * ) messageDataPtr )->cryptHandle,
IMESSAGE_SETDEPENDENT, ( void * ) &iCryptDevice,
SETDEP_OPTION_INCREF ) );
}
if( message == MESSAGE_DEV_CREATEOBJECT_INDIRECT )
{
CRYPT_DEVICE iCryptDevice = deviceInfoPtr->objectHandle;
int refCount;
/* At the moment the only objects where can be created in this manner
are certificates */
REQUIRES( messageValue == OBJECT_TYPE_CERTIFICATE );
REQUIRES( deviceInfoPtr->objectHandle == SYSTEM_OBJECT_HANDLE );
/* Unlock the system object to allow it to be used by others and
dispatch the message */
setMessageObjectUnlocked( messageExtInfo );
status = krnlSuspendObject( SYSTEM_OBJECT_HANDLE, &refCount );
ENSURES( cryptStatusOK( status ) );
assert( refCount == 1 );
status = createCertificateIndirect( messageDataPtr, NULL, 0 );
if( cryptStatusError( status ) )
return( status );
/* Make the newly-created object a dependent object of the device */
return( krnlSendMessage( \
( ( MESSAGE_CREATEOBJECT_INFO * ) messageDataPtr )->cryptHandle,
IMESSAGE_SETDEPENDENT, ( void * ) &iCryptDevice,
SETDEP_OPTION_INCREF ) );
}
retIntError();
}
/* Open a device. This is a common function called to create both the
internal system device object and general devices */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
static int openDevice( OUT_HANDLE_OPT CRYPT_DEVICE *iCryptDevice,
IN_HANDLE const CRYPT_USER iCryptOwner,
IN_ENUM( CRYPT_DEVICE ) const CRYPT_DEVICE_TYPE deviceType,
IN_BUFFER_OPT( nameLength ) const char *name,
IN_LENGTH_SHORT_Z const int nameLength,
OUT_PTR DEVICE_INFO **deviceInfoPtrPtr )
{
DEVICE_INFO *deviceInfoPtr;
OBJECT_SUBTYPE subType;
static const MAP_TABLE subtypeMapTbl[] = {
{ CRYPT_DEVICE_NONE, SUBTYPE_DEV_SYSTEM },
{ CRYPT_DEVICE_FORTEZZA, SUBTYPE_DEV_FORTEZZA },
{ CRYPT_DEVICE_PKCS11, SUBTYPE_DEV_PKCS11 },
{ CRYPT_DEVICE_CRYPTOAPI, SUBTYPE_DEV_CRYPTOAPI },
{ CRYPT_ERROR, CRYPT_ERROR }, { CRYPT_ERROR, CRYPT_ERROR }
};
int value, storageSize, status;
assert( isWritePtr( iCryptDevice, sizeof( CRYPT_DEVICE ) ) );
assert( ( name == NULL && nameLength == 0 ) || \
( isReadPtr( name, nameLength ) ) );
assert( isWritePtr( deviceInfoPtrPtr, sizeof( DEVICE_INFO * ) ) );
REQUIRES( ( deviceType == CRYPT_DEVICE_NONE && \
iCryptOwner == CRYPT_UNUSED ) || \
( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE ) || \
isHandleRangeValid( iCryptOwner ) );
REQUIRES( deviceType >= CRYPT_DEVICE_NONE && \
deviceType < CRYPT_DEVICE_LAST );
REQUIRES( ( name == NULL && nameLength == 0 ) || \
( name != NULL && \
nameLength >= MIN_NAME_LENGTH && \
nameLength <= CRYPT_MAX_TEXTSIZE ) );
/* Clear return values */
*iCryptDevice = CRYPT_ERROR;
*deviceInfoPtrPtr = NULL;
/* Set up subtype-specific information */
status = mapValue( deviceType, &value, subtypeMapTbl,
FAILSAFE_ARRAYSIZE( subtypeMapTbl, MAP_TABLE ) );
ENSURES( cryptStatusOK( status ) );
subType = value;
switch( deviceType )
{
case CRYPT_DEVICE_NONE:
storageSize = sizeof( SYSTEMDEV_INFO );
break;
case CRYPT_DEVICE_FORTEZZA:
storageSize = sizeof( FORTEZZA_INFO );
break;
case CRYPT_DEVICE_PKCS11:
storageSize = sizeof( PKCS11_INFO );
break;
case CRYPT_DEVICE_CRYPTOAPI:
storageSize = sizeof( CRYPTOAPI_INFO );
break;
default:
retIntError();
}
/* Create the device object and connect it to the device */
status = krnlCreateObject( iCryptDevice, ( void ** ) &deviceInfoPtr,
sizeof( DEVICE_INFO ) + storageSize,
OBJECT_TYPE_DEVICE, subType,
CREATEOBJECT_FLAG_NONE, iCryptOwner,
ACTION_PERM_NONE_ALL, deviceMessageFunction );
if( cryptStatusError( status ) )
return( status );
*deviceInfoPtrPtr = deviceInfoPtr;
deviceInfoPtr->objectHandle = *iCryptDevice;
deviceInfoPtr->ownerHandle = iCryptOwner;
deviceInfoPtr->type = deviceType;
switch( deviceType )
{
case CRYPT_DEVICE_NONE:
deviceInfoPtr->deviceSystem = \
( SYSTEMDEV_INFO * ) deviceInfoPtr->storage;
break;
case CRYPT_DEVICE_FORTEZZA:
deviceInfoPtr->deviceFortezza = \
( FORTEZZA_INFO * ) deviceInfoPtr->storage;
break;
case CRYPT_DEVICE_PKCS11:
deviceInfoPtr->devicePKCS11 = \
( PKCS11_INFO * ) deviceInfoPtr->storage;
break;
case CRYPT_DEVICE_CRYPTOAPI:
deviceInfoPtr->deviceCryptoAPI = \
( CRYPTOAPI_INFO * ) deviceInfoPtr->storage;
break;
default:
retIntError();
}
deviceInfoPtr->storageSize = storageSize;
/* Set up the access information for the device and connect to it */
switch( deviceType )
{
case CRYPT_DEVICE_NONE:
status = setDeviceSystem( deviceInfoPtr );
break;
case CRYPT_DEVICE_FORTEZZA:
status = setDeviceFortezza( deviceInfoPtr );
break;
case CRYPT_DEVICE_PKCS11:
status = setDevicePKCS11( deviceInfoPtr, name, nameLength );
break;
case CRYPT_DEVICE_CRYPTOAPI:
status = setDeviceCryptoAPI( deviceInfoPtr );
break;
default:
retIntError();
}
if( cryptStatusOK( status ) )
status = deviceInfoPtr->initFunction( deviceInfoPtr, name,
nameLength );
if( cryptStatusOK( status ) && \
deviceInfoPtr->createObjectFunctions == NULL )
{
/* The device-specific code hasn't set up anything, use the default
create-object functions, which just create encryption contexts
using the device capability information */
deviceInfoPtr->createObjectFunctions = defaultCreateFunctions;
deviceInfoPtr->createObjectFunctionCount = \
FAILSAFE_ARRAYSIZE( defaultCreateFunctions, CREATEOBJECT_FUNCTION_INFO );
}
return( status );
}
/* Create a (non-system) device object */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int createDevice( INOUT MESSAGE_CREATEOBJECT_INFO *createInfo,
STDC_UNUSED const void *auxDataPtr,
STDC_UNUSED const int auxValue )
{
CRYPT_DEVICE iCryptDevice;
DEVICE_INFO *deviceInfoPtr = NULL;
int initStatus, status;
assert( isWritePtr( createInfo, sizeof( MESSAGE_CREATEOBJECT_INFO ) ) );
REQUIRES( auxDataPtr == NULL && auxValue == 0 );
REQUIRES( createInfo->arg1 > CRYPT_DEVICE_NONE && \
createInfo->arg1 < CRYPT_DEVICE_LAST );
REQUIRES( ( createInfo->arg1 != CRYPT_DEVICE_PKCS11 && \
createInfo->arg1 != CRYPT_DEVICE_CRYPTOAPI ) || \
( createInfo->strArgLen1 >= MIN_NAME_LENGTH && \
createInfo->strArgLen1 <= CRYPT_MAX_TEXTSIZE ) );
/* Wait for any async device driver binding to complete */
if( !krnlWaitSemaphore( SEMAPHORE_DRIVERBIND ) )
{
/* The kernel is shutting down, bail out */
assert( DEBUG_WARN );
return( CRYPT_ERROR_PERMISSION );
}
/* Pass the call on to the lower-level open function */
initStatus = openDevice( &iCryptDevice, createInfo->cryptOwner,
createInfo->arg1, createInfo->strArg1,
createInfo->strArgLen1, &deviceInfoPtr );
if( cryptStatusError( initStatus ) )
{
/* If the create object failed, return immediately */
if( deviceInfoPtr == NULL )
return( initStatus );
/* The init failed, make sure that the object gets destroyed when we
notify the kernel that the setup process is complete */
krnlSendNotifier( iCryptDevice, IMESSAGE_DESTROY );
}
/* We've finished setting up the object-type-specific info, tell the
kernel that the object is ready for use */
status = krnlSendMessage( iCryptDevice, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
if( cryptStatusOK( status ) && \
createInfo->arg1 == CRYPT_DEVICE_CRYPTOAPI )
{
/* If it's a device that doesn't require an explicit login, move it
into the initialised state */
status = krnlSendMessage( iCryptDevice, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED );
if( cryptStatusError( status ) )
krnlSendNotifier( iCryptDevice, IMESSAGE_DESTROY );
}
if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
return( cryptStatusError( initStatus ) ? initStatus : status );
createInfo->cryptHandle = iCryptDevice;
return( CRYPT_OK );
}
/* Create the internal system device object. This is somewhat special in
that it can't be destroyed through a normal message (it can only be done
from one place in the kernel) so if the open fails we don't use the normal
signalling mechanism to destroy it but simply return an error code to the
caller (the cryptlib init process). This causes the init to fail and
destroys the object when the kernel shuts down */
CHECK_RETVAL \
static int createSystemDeviceObject( void )
{
CRYPT_DEVICE iSystemObject;
DEVICE_INFO *deviceInfoPtr;
int initStatus, status;
/* Pass the call on to the lower-level open function. This device is
unique and has no owner or type.
Normally if an object init fails we tell the kernel to destroy it by
sending it a destroy message, which is processed after the object's
status has been set to normal. However we don't have the privileges
to do this for the system object (or the default user object) so we
just pass the error code back to the caller, which causes the
cryptlib init to fail.
In addition the init can fail in one of two ways the object isn't
even created (deviceInfoPtr == NULL, nothing to clean up) in which
case we bail out immediately, or the object is created but wasn't set
up properly (deviceInfoPtr is allocated, but the object can't be
used) in which case we bail out after we update its status.
A failure at this point is a bit problematic because it's not
possible to inform the caller that the system object was successfully
created but something went wrong after that. That is, it's assumed
that create-object operations are atomic so that a failure status
indicates that all allocations and whatnot were rolled back, but
since the system object can only be destroyed from within the kernel
once it's been created there's no way to roll back the creation of an
incomplete system object. In fact it's not even clear what *could*
cause a failure at this point apart from "circumstances beyond our
control" (memory corruption, a coding error, or something similar).
Because this is a can't-occur situation the best course of action for
backing out of having a partially-initialised system object that's
created at and exists at a level below what the standard system
cleanup routines can handle is uncertain.
At the moment we just exit and (potentialy) leak the memory, if this
situation ever occurs then presumably the calling application will
exit and the OS will release the memory for us. This is somewhat
ugly, but it's not really clear what other action we can take in the
error handler for a can-never-occur error */
initStatus = openDevice( &iSystemObject, CRYPT_UNUSED, CRYPT_DEVICE_NONE,
NULL, 0, &deviceInfoPtr );
if( deviceInfoPtr == NULL )
return( initStatus ); /* Create object failed, return immediately */
ENSURES( iSystemObject == SYSTEM_OBJECT_HANDLE );
/* We've finished setting up the object-type-specific info, tell the
kernel that the object is ready for use */
status = krnlSendMessage( iSystemObject, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
return( cryptStatusError( initStatus ) ? initStatus : status );
/* The object has been initialised, move it into the initialised state */
return( krnlSendMessage( iSystemObject, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED ) );
}
/* Generic management function for this class of object. Unlike the usual
multilevel init process which is followed for other objects, the devices
have an OR rather than an AND relationship since the devices are
logically independent, so we set a flag for each device type that is
successfully initialised rather than recording an init level */
#define DEV_NONE_INITED 0x00
#define DEV_FORTEZZA_INITED 0x01
#define DEV_PKCS11_INITED 0x02
#define DEV_CRYPTOAPI_INITED 0x04
CHECK_RETVAL \
int deviceManagementFunction( IN_ENUM( MANAGEMENT_ACTION ) \
const MANAGEMENT_ACTION_TYPE action )
{
static int initFlags = DEV_NONE_INITED;
REQUIRES( action == MANAGEMENT_ACTION_PRE_INIT || \
action == MANAGEMENT_ACTION_INIT || \
action == MANAGEMENT_ACTION_PRE_SHUTDOWN || \
action == MANAGEMENT_ACTION_SHUTDOWN );
switch( action )
{
case MANAGEMENT_ACTION_PRE_INIT:
return( createSystemDeviceObject() );
case MANAGEMENT_ACTION_INIT:
if( cryptStatusOK( deviceInitFortezza() ) )
initFlags |= DEV_FORTEZZA_INITED;
if( krnlIsExiting() )
{
/* The kernel is shutting down, exit */
return( CRYPT_ERROR_PERMISSION );
}
if( cryptStatusOK( deviceInitPKCS11() ) )
initFlags |= DEV_PKCS11_INITED;
if( krnlIsExiting() )
{
/* The kernel is shutting down, exit */
return( CRYPT_ERROR_PERMISSION );
}
if( cryptStatusOK( deviceInitCryptoAPI() ) )
initFlags |= DEV_CRYPTOAPI_INITED;
return( CRYPT_OK );
case MANAGEMENT_ACTION_PRE_SHUTDOWN:
/* In theory we could signal the background entropy poll to
start wrapping up at this point, however if the background
polling is being performed in a thread or task then the
shutdown is already signalled via the kernel shutdown flag.
If it's performed by forking off a process, as it is on Unix
systems, there's no easy way to communicate with this process
so the shutdown function just kill()s it. Because of this we
don't try and do anything here, although this call is left in
place as a no-op in case it's needed in the future */
return( CRYPT_OK );
case MANAGEMENT_ACTION_SHUTDOWN:
if( initFlags & DEV_FORTEZZA_INITED )
deviceEndFortezza();
if( initFlags & DEV_PKCS11_INITED )
deviceEndPKCS11();
if( initFlags & DEV_CRYPTOAPI_INITED )
deviceEndCryptoAPI();
initFlags = DEV_NONE_INITED;
return( CRYPT_OK );
}
retIntError();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -