📄 obj_acc.c
字号:
/****************************************************************************
* *
* Object Alternative Access *
* Copyright Peter Gutmann 1997-2005 *
* *
****************************************************************************/
/* Sending a message to an object only makes the one object which is the
target of the message available for use. When we need simultaneous
access to two objects (for example when copying a collection of cert
extensions from one cert to another), we have to use the
krnlAcquireObject()/krnlReleaseObject() functions to obtain access to
the second object's internals.
There is a second situation in which we need access to an object's
internals, and that occurs when we need to export/import a key from/to
a context. This is handled via the key extract functions at the end
of this module, see the comments there for further information */
#if defined( INC_ALL )
#include "crypt.h"
#include "acl.h"
#include "kernel.h"
#else
#include "crypt.h"
#include "kernel/acl.h"
#include "kernel/kernel.h"
#endif /* Compiler-specific includes */
/* A pointer to the kernel data block */
static KERNEL_DATA *krnlData = NULL;
/* Optionally include the Intel Thread Checker API to control analysis of
the object mutexes */
#if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && 0
#include "../../../Intel/VTune/tcheck/Include/libittnotify.h"
#pragma comment( lib, "C:/Program Files/Intel/VTune/Analyzer/Lib/libittnotify.lib" )
#define THREAD_NOTIFY_PREPARE( id ) __itt_notify_sync_prepare( ( void * ) id );
#define THREAD_NOTIFY_CANCELLED( id ) __itt_notify_sync_prepare( ( void * ) id );
#define THREAD_NOTIFY_ACQUIRED( id ) __itt_notify_sync_acquired( ( void * ) id );
#define THREAD_NOTIFY_RELEASED( id ) __itt_notify_sync_releasing( ( void * ) id );
#else
#define THREAD_NOTIFY_PREPARE( dummy )
#define THREAD_NOTIFY_CANCELLED( dummy )
#define THREAD_NOTIFY_ACQUIRED( dummy )
#define THREAD_NOTIFY_RELEASED( dummy )
#endif /* VC++ 6.0 with Intel Thread Checker */
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* The type of checking that we perform for the object access. The check
types are:
CHECK_EXTACCESS
Kernel-external call with a cert or crypto device to allow access to
object-internal data.
CHECK_KEYACCESS
Kernel-internal call with a context for key export/import.
CHECK_SUSPEND
Kernel-external call with a user or system object to temporarily
suspend object use and allow others access, providing a (somewhat
crude) mechanism for making kernel calls interruptible */
typedef enum {
ACCESS_CHECK_NONE, /* No access check type */
ACCESS_CHECK_EXTACCESS, /* Generic external call: Cert or crypt.dev.*/
ACCESS_CHECK_KEYACCESS, /* Internal call: Context for key export */
ACCESS_CHECK_SUSPEND, /* Suspend object use: User or sys.obj.*/
ACCESS_CHECK_LAST /* Last access check type */
} ACCESS_CHECK_TYPE;
/* Check that this is an object for which direct access is valid. We can
only access the following object types:
Certificates: EXTACCESS, used when copying internal state such as cert
extensions or CRL info from one cert object to another.
Contexts: KEYACCESS, used when importing/exporting keys to/from contexts
during key wrap/unwrap operations.
Crypto hardware devices other than the system object: EXTACCESS, used
when a context tied to a device needs to perform an operation using
the device.
System object: ACCESS_CHECK_SUSPEND, used when performing a randomness
data read/write, which can take some time to complete.
User objects: ACCESS_CHECK_SUSPEND, used when committing config data to
persistent storage. We don't actually use the object data but
merely unlock it to allow others access while performing the
potentially lengthy update. Also used when performing the self-
test */
CHECK_RETVAL \
static int checkAccessValid( const int objectHandle,
const ACCESS_CHECK_TYPE checkType,
const int errorCode )
{
OBJECT_INFO *objectTable = krnlData->objectTable, *objectInfoPtr;
PRE( isValidObject( objectHandle ) );
PRE( checkType > ACCESS_CHECK_NONE && checkType < ACCESS_CHECK_LAST );
PRE( errorCode < 0 );
/* Perform similar access checks to the ones performed in
krnlSendMessage(): It's a valid object owned by the calling
thread */
if( !isValidObject( objectHandle ) || \
!checkObjectOwnership( objectTable[ objectHandle ] ) )
return( errorCode );
/* It's a valid object, get its info */
objectInfoPtr = &objectTable[ objectHandle ];
/* Make sure that the object access is valid */
switch( objectInfoPtr->type )
{
case OBJECT_TYPE_CONTEXT:
/* Used when exporting/importing keying info, valid for contexts
with keys when called from within the kernel */
if( checkType != ACCESS_CHECK_KEYACCESS )
return( errorCode );
if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_CTX_CONV ) && \
!isValidSubtype( objectInfoPtr->subType, SUBTYPE_CTX_MAC ) && \
!isValidSubtype( objectInfoPtr->subType, SUBTYPE_CTX_PKC ) )
return( errorCode );
break;
case OBJECT_TYPE_CERTIFICATE:
/* Used when copying internal state such as cert extensions or
CRL info from one cert object to another. This is valid for
all cert types */
if( checkType != ACCESS_CHECK_EXTACCESS )
return( errorCode );
break;
case OBJECT_TYPE_DEVICE:
/* If it's an external access operation, it's used when a
context tied to a crypto hardware device needs to perform an
operation using the device. This is valid for all devices
other than the system object */
if( checkType == ACCESS_CHECK_EXTACCESS )
{
if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_FORTEZZA ) && \
!isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_PKCS11 ) && \
!isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_CRYPTOAPI ) )
return( errorCode );
}
else
{
/* If it's a suspend operation, it's used to temporarily
allow access to the system object while other operations
are being performed */
if( checkType != ACCESS_CHECK_SUSPEND )
return( errorCode );
if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_DEV_SYSTEM ) )
return( errorCode );
}
break;
case OBJECT_TYPE_USER:
/* Used when updating config data, which can take awhile. The
default user is an SO user, which is why we check for this
user type */
if( checkType != ACCESS_CHECK_SUSPEND )
return( errorCode );
if( !isValidSubtype( objectInfoPtr->subType, SUBTYPE_USER_SO ) )
return( errorCode );
break;
default:
retIntError();
}
/* Postcondition: The object is of the appropriate type for the access */
POST( ( ( checkType == ACCESS_CHECK_EXTACCESS ) && \
( objectInfoPtr->type == OBJECT_TYPE_CERTIFICATE || \
objectInfoPtr->type == OBJECT_TYPE_DEVICE ) ) || \
( checkType == ACCESS_CHECK_KEYACCESS && \
objectInfoPtr->type == OBJECT_TYPE_CONTEXT ) || \
( checkType == ACCESS_CHECK_SUSPEND && \
( objectInfoPtr->type == OBJECT_TYPE_DEVICE || \
objectInfoPtr->type == OBJECT_TYPE_USER ) ) );
return( CRYPT_OK );
}
/* Get a pointer to an object's data from its handle */
int getObject( const int objectHandle, const OBJECT_TYPE type,
const ACCESS_CHECK_TYPE checkType, void **objectPtr,
const int refCount, const int errorCode )
{
OBJECT_INFO *objectTable, *objectInfoPtr;
int status;
/* Preconditions: It's a valid object */
PRE( isValidHandle( objectHandle ) );
PRE( isValidType( type ) && \
( type == OBJECT_TYPE_CONTEXT || type == OBJECT_TYPE_CERTIFICATE || \
type == OBJECT_TYPE_DEVICE || type == OBJECT_TYPE_USER ) );
PRE( checkType > ACCESS_CHECK_NONE && \
checkType < ACCESS_CHECK_LAST );
PRE( ( ( objectHandle == SYSTEM_OBJECT_HANDLE || \
objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
objectPtr == NULL && refCount > 0 ) || \
( !( objectHandle == SYSTEM_OBJECT_HANDLE || \
objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
isWritePtr( objectPtr, sizeof( void * ) ) && \
refCount == CRYPT_UNUSED ) );
/* Clear the return value */
if( objectPtr != NULL )
*objectPtr = NULL;
THREAD_NOTIFY_PREPARE( objectHandle );
MUTEX_LOCK( objectTable );
objectTable = krnlData->objectTable;
/* Perform similar access checks to the ones performed in
krnlSendMessage(), as well as situation-specific additional checks
for correct object types */
status = checkAccessValid( objectHandle, checkType, errorCode );
if( cryptStatusError( status ) )
{
MUTEX_UNLOCK( objectTable );
THREAD_NOTIFY_CANCELLED( objectHandle );
retIntError_Ext( status );
}
/* Perform additional checks for correct object types */
if( ( ( objectHandle == SYSTEM_OBJECT_HANDLE || \
objectHandle == DEFAULTUSER_OBJECT_HANDLE ) && \
objectPtr != NULL ) || \
objectTable[ objectHandle ].type != type )
{
MUTEX_UNLOCK( objectTable );
THREAD_NOTIFY_CANCELLED( objectHandle );
retIntError_Ext( errorCode );
}
/* It's a valid object, get its info */
objectInfoPtr = &objectTable[ objectHandle ];
/* Inner precondition: The object is of the requested type */
PRE( objectInfoPtr->type == type && \
( objectInfoPtr->type == OBJECT_TYPE_CONTEXT || \
objectInfoPtr->type == OBJECT_TYPE_CERTIFICATE || \
objectInfoPtr->type == OBJECT_TYPE_DEVICE || \
objectInfoPtr->type == OBJECT_TYPE_USER ) );
/* If the object is busy, wait for it to become available */
if( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) )
status = waitForObject( objectHandle, &objectInfoPtr );
if( cryptStatusError( status ) )
{
MUTEX_UNLOCK( objectTable );
THREAD_NOTIFY_CANCELLED( objectHandle );
return( status );
}
/* If it's an external access to certificate/device info or an internal
access to access the object's keying data, increment the object's
reference count to reserve it for our exclusive use */
if( checkType == ACCESS_CHECK_EXTACCESS || \
checkType == ACCESS_CHECK_KEYACCESS )
objectInfoPtr->lockCount++;
else
{
/* If we're resuming use of an object that we suspended to allow
others access, reset the reference count */
PRE( checkType == ACCESS_CHECK_SUSPEND );
PRE( objectInfoPtr->lockCount == 0 );
PRE( refCount > 0 && refCount < 100 );
objectInfoPtr->lockCount = refCount;
}
#ifdef USE_THREADS
objectInfoPtr->lockOwner = THREAD_SELF();
#endif /* USE_THREADS */
if( objectPtr != NULL )
*objectPtr = objectInfoPtr->objectPtr;
MUTEX_UNLOCK( objectTable );
THREAD_NOTIFY_ACQUIRED( objectHandle );
return( status );
}
/* Release an object that we previously acquired directly. We don't require
that the return value of this function be checked by the caller since the
only time that we can get an error is if it's a 'can't-occur' internal
error and it's not obvious what they should do in that case */
static int releaseObject( const int objectHandle,
const ACCESS_CHECK_TYPE checkType,
OUT_OPT int *refCount )
{
OBJECT_INFO *objectTable, *objectInfoPtr;
int status;
DECLARE_ORIGINAL_INT( lockCount );
/* Preconditions */
PRE( checkType > ACCESS_CHECK_NONE && \
checkType < ACCESS_CHECK_LAST );
PRE( ( ( checkType == ACCESS_CHECK_EXTACCESS || \
checkType == ACCESS_CHECK_KEYACCESS ) && refCount == NULL ) || \
( checkType == ACCESS_CHECK_SUSPEND && \
isWritePtr( refCount, sizeof( int ) ) ) );
THREAD_NOTIFY_PREPARE( objectHandle );
MUTEX_LOCK( objectTable );
objectTable = krnlData->objectTable;
/* Preconditions: It's a valid object in use by the caller. Since these
checks require access to the object table we can only perform them
after we've locked it */
PRE( isValidObject( objectHandle ) );
PRE( isInUse( objectHandle ) && isObjectOwner( objectHandle ) );
/* Perform similar access checks to the ones performed in
krnlSendMessage(), as well as situation-specific additional checks
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -