📄 cryptkrn.c
字号:
/****************************************************************************
* *
* cryptlib Security Kernel *
* Copyright Peter Gutmann 1992-2003 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#ifndef NDEBUG
#include <stdio.h> /* Needed for POST macro on some systems */
#endif /* Debug version */
#include "crypt.h"
#include "cryptacd.h"
/* RAY and EGON look over code.
EGON: The structure of this kernel is exactly like the kind of telemetry
tracker that NASA uses to secure dead pulsars in deep space.
RAY: All message dispatch mechanisms and callback functions.
PETER (to other jailbirds): Everyone getting this so far? So what? I
guess they just don't make them like they used to.
RAY: No! Nobody ever made them like this! The architect was either a
certified genius or an authentic wacko! */
/* "There is a fine line between genius and insanity. I have erased this
line" - Oscar Levant (or "Nullum magnum ingenium sine mixtura dementiae"
if you want it in the usual style) */
/* The initialisation state and a lock to protect it. The object
management functions check the state before they do anything and return
CRYPT_INITED if cryptlib hasn't been initialised. Since everything in
cryptlib depends on the creation of objects, any attempts to use cryptlib
without it being properly initialised are caught.
Reading the isInitialised flag presents something of a chicken-and-egg
problem since the read should be protected by the intialisation mutex, but
we can't try and grab it unless the mutex has been initialised. If we
just read the flag directly and rely on the object map mutex to protect
access we run into a potential race condition on shutdown:
thread1 thread2
inited = T read inited = T
inited = F, destroy objects
lock objects, die
The usual way to avoid this is to perform an interlocked mutex lock, but
this isn't possible here since the initialisation mutex may not be
initialised. Under Win32 it's set by DllMain() */
DECLARE_LOCKING_VARS( initialisation )
static BOOLEAN isInitialised = FALSE;
static BOOLEAN isClosingDown = FALSE;
/* Some messages communicate standard data values that are used again and
again so we predefine values for these that can be used globally */
const int messageValueTrue = TRUE;
const int messageValueFalse = FALSE;
const int messageValueCryptOK = CRYPT_OK;
const int messageValueCryptError = CRYPT_ERROR;
const int messageValueCryptSignalled = CRYPT_ERROR_SIGNALLED;
const int messageValueCryptUnused = CRYPT_UNUSED;
const int messageValueCryptUseDefault = CRYPT_USE_DEFAULT;
const int messageValueCursorFirst = CRYPT_CURSOR_FIRST;
const int messageValueCursorNext = CRYPT_CURSOR_NEXT;
const int messageValueCursorPrevious = CRYPT_CURSOR_PREVIOUS;
const int messageValueCursorLast = CRYPT_CURSOR_LAST;
/****************************************************************************
* *
* Object Definitions and Information *
* *
****************************************************************************/
/* Macros to perform validity checks on objects and handles. These checks
are:
isValidHandle(): Whether a handle is a valid index into the object table.
isValidObject(): Whether a handle refers to an object in the table.
isFreeObject(): Whether a handle refers to an empty entry in the table.
isInternalObject(): Whether an object is an internal object.
isInvalidObjectState(): Whether an object is in an invalid (error) state.
isInUse(): Whether an object is currently in use (processing a message).
isObjectOwner(): if inUse == TRUE, whether this thread is the one using
the object.
isInHighState(): Whether an object is in the 'high' security state.
isSameOwningObject(): Whether two objects have the same owner. We also
have to handle the situation where the first object
is a user object, in which case it has to be the
owner of the second object.
isAliasedObject(): Whether an object is an alias for another object and
subject to copy-on-write.
isClonedObject(): Whether an aliased object is the original or the clone.
isObjectAccessValid(): Internal/external object access check.
isValidMessage(): Whether a message type is valid.
isValidType(): Whether an object type is valid
isValidSubtype(): Whether an object subtype is allowed based on access
bitflags */
#define isValidHandle( handle ) \
( ( handle ) >= 0 && ( handle ) < objectTableSize )
#define isValidObject( handle ) \
( isValidHandle( handle ) && objectTable[ ( handle ) ].objectPtr != NULL )
#define isFreeObject( handle ) \
( isValidHandle( handle ) && objectTable[ ( handle ) ].objectPtr == NULL )
#define isInternalObject( handle ) \
( objectTable[ handle ].flags & OBJECT_FLAG_INTERNAL )
#define isObjectAccessValid( objectHandle, message ) \
!( isInternalObject( objectHandle ) && \
!( message & MESSAGE_FLAG_INTERNAL ) )
#define isInvalidObjectState( handle ) \
( objectTable[ ( handle ) ].flags & OBJECT_FLAGMASK_STATUS )
#define isInUse( handle ) \
( objectTable[ ( handle ) ].lockCount > 0 )
#define isObjectOwner( handle ) \
THREAD_SAME( objectTable[ ( handle ) ].lockOwner, THREAD_SELF() )
#define isInHighState( handle ) \
( objectTable[ ( handle ) ].flags & OBJECT_FLAG_HIGH )
#define isSameOwningObject( handle1, handle2 ) \
( objectTable[ ( handle1 ) ].owner == CRYPT_UNUSED || \
objectTable[ ( handle2 ) ].owner == CRYPT_UNUSED || \
( objectTable[ ( handle1 ) ].owner == objectTable[ ( handle2 ) ].owner ) || \
( ( handle1 ) == objectTable[ ( handle2 ) ].owner ) )
#define isAliasedObject( handle ) \
( objectTable[ handle ].flags & OBJECT_FLAG_ALIASED )
#define isClonedObject( handle ) \
( objectTable[ handle ].flags & OBJECT_FLAG_CLONE )
#define isValidMessage( message ) \
( ( message ) > MESSAGE_NONE && ( message ) < MESSAGE_LAST )
#define isValidType( type ) \
( ( type ) > OBJECT_TYPE_NONE && ( type ) < OBJECT_TYPE_LAST )
#define isValidSubtype( subtypeMask, subtype ) \
( ( ( subtypeMask ) & ( subtype ) ) == ( subtype ) )
/* Macros to test whether a message falls into a certain class. These tests
are:
isParamMessage(): Whether a message contains an object as a parameter */
#define isParamMessage( message ) \
( ( message ) == MESSAGE_CRT_SIGN || \
( message ) == MESSAGE_CRT_SIGCHECK )
/* Macros to manage object ownership, if the OS supports it */
#define checkObjectOwnership( objectPtr ) \
( !( ( objectPtr ).flags & OBJECT_FLAG_OWNED ) || \
THREAD_SAME( ( objectPtr ).objectOwner, THREAD_SELF() ) )
/* A macro to turn an abnormal status indicated in an object's flags into a
status code. The values are prioritised so notinited > signalled > busy */
#define getObjectStatusValue( flags ) \
( ( flags & OBJECT_FLAG_NOTINITED ) ? CRYPT_ERROR_NOTINITED : \
( flags & OBJECT_FLAG_SIGNALLED ) ? CRYPT_ERROR_SIGNALLED : \
( flags & OBJECT_FLAG_BUSY ) ? CRYPT_ERROR_TIMEOUT : CRYPT_OK )
/* The initial allocation size of the object table. In memory-starved
environments we limit the size, in general these are embedded systems or
single-tasking OSs that aren't going to need many objects anyway */
#ifdef CONFIG_CONSERVE_MEMORY
#define OBJECT_TABLE_ALLOCSIZE 128
#define INITIAL_LFSRPOLY 0x83
#else
#define OBJECT_TABLE_ALLOCSIZE 1024
#define INITIAL_LFSRPOLY 0x409
#endif /* Memory-starved environments */
/* The information maintained by the kernel for each object */
typedef struct {
/* Object type and value */
OBJECT_TYPE type; /* Object type */
int subType; /* Object subtype */
void *objectPtr; /* Object data */
/* Object properties */
int flags; /* Internal-only, locked, etc */
int actionFlags; /* Permitted actions */
int referenceCount; /* Number of references to this object */
int lockCount; /* Message-processing lock recursion count */
THREAD_HANDLE lockOwner; /* Lock owner if lockCount > 0 */
unsigned int uniqueID; /* Unique ID for this object */
/* time_t lastAccess; // Last access time */
/* Object security properties */
int forwardCount; /* Number of times ownership can be transferred */
int usageCount; /* Number of times obj.can be used */
THREAD_HANDLE objectOwner; /* The object's owner */
/* Object methods */
MESSAGE_FUNCTION messageFunction;
/* The object's message handler */
/* Owning and dependent objects */
CRYPT_USER owner; /* Owner object handle */
CRYPT_HANDLE dependentObject; /* Dependent object (context or cert) */
CRYPT_HANDLE dependentDevice; /* Dependent crypto device */
CRYPT_HANDLE clonedObject; /* Cloned object if aliased */
} OBJECT_INFO;
/* The flags that apply to each object in the table */
#define OBJECT_FLAG_NONE 0x0000 /* Non-flag */
#define OBJECT_FLAG_INTERNAL 0x0001 /* Internal-use only */
#define OBJECT_FLAG_NOTINITED 0x0002 /* Still being initialised */
#define OBJECT_FLAG_HIGH 0x0004 /* In 'high' security state */
#define OBJECT_FLAG_SIGNALLED 0x0008 /* In signalled state */
#define OBJECT_FLAG_BUSY 0x0010 /* Busy with async.op */
#define OBJECT_FLAG_ALIASED 0x0020 /* Object is alias for another object */
#define OBJECT_FLAG_CLONE 0x0040 /* Aliased object is the clone */
#define OBJECT_FLAG_OWNED 0x0080 /* Object is bound to a thread */
#define OBJECT_FLAG_ATTRLOCKED 0x0100 /* Security properties can't be modified */
/* The flags that convey information about an object's status */
#define OBJECT_FLAGMASK_STATUS \
( OBJECT_FLAG_NOTINITED | OBJECT_FLAG_BUSY | OBJECT_FLAG_SIGNALLED )
/* The table to map external object handles to object data */
static OBJECT_INFO *objectTable;
static int objectTableSize;
DECLARE_LOCKING_VARS( objectTable )
static unsigned int objectUniqueID;
/* A template used to initialise object table entries. Some of the entries
are either object handles that have to be set to CRYPT_ERROR or values
for which 0 is significant (so they're set to CRYPT_UNUSED), because of
this we can't just memset the entry to all zeroes */
static const OBJECT_INFO OBJECT_INFO_TEMPLATE = {
OBJECT_TYPE_NONE, 0, NULL, /* Type, subtype, and data pointer */
OBJECT_FLAG_INTERNAL | OBJECT_FLAG_NOTINITED, /* Flags */
0, /* Action flags */
0, 0, THREAD_INITIALISER, /* Ref.count, lock count, lock owner */
0, /* Unique ID */
CRYPT_UNUSED, CRYPT_UNUSED, THREAD_INITIALISER,
/* Forward count, usage count, owner */
NULL, /* Message function */
CRYPT_ERROR, CRYPT_ERROR,
CRYPT_ERROR, CRYPT_ERROR /* Owning/dependent objects */
};
/* The object allocation state data and a template used to initialise it.
This controls the allocation of handles to newly-created objects. The
first NO_SYSTEM_OBJECTS handles are system objects that exist with
fixed handles, the remainder are allocated pseudorandomly under the
control of an LFSR (see the comments further down for more details on
this) */
typedef struct {
int lfsrMask, lfsrPoly; /* LFSR state values */
int objectHandle; /* Current object handle */
} OBJECT_STATE_INFO;
static const OBJECT_STATE_INFO OBJECT_STATE_INFO_TEMPLATE = {
OBJECT_TABLE_ALLOCSIZE, /* Mask for LFSR output */
INITIAL_LFSRPOLY, /* LFSR polynomial */
-1 /* Initial-1'th object handle */
};
static OBJECT_STATE_INFO objectStateInfo;
/* Create and destroy the object table. The destroy process is handled in
two stages, the first of which is called fairly early in the shutdown
process to destroy any remaining objects, and the second which is called
at the end of the shutdown when the kernel data is being deleted. This
is because some of the objects are tied to things like external devices,
and deleting them at the end when everything else has been shut down
isn't possible */
static int initObjectTable( void )
{
int i;
/* Allocate and initialise the object table */
objectTable = clAlloc( "initObjectTable",
OBJECT_TABLE_ALLOCSIZE * sizeof( OBJECT_INFO ) );
if( objectTable == NULL )
return( CRYPT_ERROR_MEMORY );
for( i = 0; i < OBJECT_TABLE_ALLOCSIZE; i++ )
objectTable[ i ] = OBJECT_INFO_TEMPLATE;
objectTableSize = OBJECT_TABLE_ALLOCSIZE;
objectStateInfo = OBJECT_STATE_INFO_TEMPLATE;
/* Initialise object-related information. This isn't strictly part of
the object table but is used to assing unique ID values to objects
within the table, since table entries (object handles) may be reused
as objects are destroyed and new ones created in their place */
objectUniqueID = 0;
/* Initialize any data structures required to make the object table
thread-safe */
initResourceLock( objectTable );
/* Postconditions */
POST( objectTable != NULL );
POST( objectTableSize == OBJECT_TABLE_ALLOCSIZE );
FORALL( i, 0, OBJECT_TABLE_ALLOCSIZE,
!memcmp( &objectTable[ i ], &OBJECT_INFO_TEMPLATE, \
sizeof( OBJECT_INFO ) ) );
POST( objectStateInfo.lfsrMask == OBJECT_TABLE_ALLOCSIZE && \
objectStateInfo.lfsrPoly == INITIAL_LFSRPOLY && \
objectStateInfo.objectHandle == SYSTEM_OBJECT_HANDLE - 1 );
POST( objectUniqueID == 0 );
return( CRYPT_OK );
}
static int destroySelectedObjects( const int currentDepth )
{
int objectHandle, status = CRYPT_OK;
for( objectHandle = NO_SYSTEM_OBJECTS; objectHandle < objectTableSize;
objectHandle++ )
{
const int dependentObject = \
objectTable[ objectHandle ].dependentObject;
int depth = 1;
/* If there's nothing there, continue */
if( objectTable[ objectHandle ].objectPtr == NULL )
continue;
/* There's an object still present, determine its nesting depth.
Dependent devices are terminal so we only follow the path down for
dependent objects */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -