cryptkrn.c
来自「提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发」· C语言 代码 · 共 1,648 行 · 第 1/5 页
C
1,648 行
/****************************************************************************
* *
* cryptlib Security Kernel *
* Copyright Peter Gutmann 1992-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt.h"
#include "cryptacl.h"
/* 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 in
the same way as the krnlGetXXXObject() macros, 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 which are used again and
again so we predefine values for these which 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).
isInHighState(): Whether an object is in the 'high' security state.
isSameOwner(): Whether two objects have the same owner.
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 & RESOURCE_MESSAGE_INTERNAL ) )
#define isInvalidObjectState( handle ) \
( objectTable[ ( handle ) ].flags & OBJECT_FLAGMASK_STATUS )
#define isInUse( handle ) \
( objectTable[ ( handle ) ].inUse )
#define isInHighState( handle ) \
( objectTable[ ( handle ) ].flags & OBJECT_FLAG_HIGH )
#define isSameOwner( handle1, handle2 ) \
( objectTable[ ( handle1 ) ].owner == CRYPT_UNUSED || \
objectTable[ ( handle2 ) ].owner == CRYPT_UNUSED || \
( objectTable[ ( handle1 ) ].owner == objectTable[ ( handle2 ) ].owner ) )
#define isValidMessage( message ) \
( ( message ) > RESOURCE_MESSAGE_NONE && \
( message ) < RESOURCE_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:
isIncomingAttributeMessage(): Whether a message represents an incoming
attribute.
isOutgoingAttributeMessage(): Whether a message represents an outgoing
attribute.
isParamMessage(): Whether a message contains an object as a parameter */
#define isIncomingAttributeMessage( message ) \
( ( message ) == RESOURCE_MESSAGE_SETATTRIBUTE || \
( message ) == RESOURCE_MESSAGE_SETATTRIBUTE_S )
#define isOutgoingAttributeMessage( message ) \
( ( message ) == RESOURCE_MESSAGE_GETATTRIBUTE || \
( message ) == RESOURCE_MESSAGE_GETATTRIBUTE_S )
#define isParamMessage( message ) \
( ( message ) == RESOURCE_MESSAGE_CRT_SIGN || \
( message ) == RESOURCE_MESSAGE_CRT_SIGCHECK )
/* 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_BUSY : 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 which aren't going to need many objects anyway */
#ifdef __MSDOS16__
#define OBJECT_TABLE_ALLOCSIZE 128
#define INITIAL_LFSRPOLY 0x83
#else
#define OBJECT_TABLE_ALLOCSIZE 1024
#define INITIAL_LFSRPOLY 0x409
#endif /* Memory-starved environments */
/* The table to map external object handles to object data */
OBJECT_INFO *objectTable;
int objectTableSize;
DECLARE_LOCKING_VARS( objectTable )
/* A template used to initialise object table entries. Some of the entries
are either object handles which 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 objectTemplate = {
OBJECT_TYPE_NONE, NULL, /* Type and data pointer */
OBJECT_FLAG_INTERNAL | OBJECT_FLAG_NOTINITED, /* Flags */
0, 0, /* Action flags, and subtype */
CRYPT_UNUSED, CRYPT_UNUSED, /* Forward count, usage count */
0, 0, /* Reference count, in use flag */
NULL, /* Message function */
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 which 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 objectStateTemplate = {
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 one 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 = malloc( OBJECT_TABLE_ALLOCSIZE * sizeof( OBJECT_INFO ) );
if( objectTable == NULL )
return( CRYPT_ERROR_MEMORY );
for( i = 0; i < OBJECT_TABLE_ALLOCSIZE; i++ )
objectTable[ i ] = objectTemplate;
objectTableSize = OBJECT_TABLE_ALLOCSIZE;
objectStateInfo = objectStateTemplate;
/* Initialize any data structures required to make the object table
thread-safe */
initGlobalResourceLock( objectTable );
/* Postconditions */
POST( objectTable != NULL );
POST( objectTableSize == OBJECT_TABLE_ALLOCSIZE );
FORALL( i, 0, OBJECT_TABLE_ALLOCSIZE,
!memcmp( &objectTable[ i ], &objectTemplate, sizeof( OBJECT_INFO ) ) );
POST( objectStateInfo.lfsrMask == OBJECT_TABLE_ALLOCSIZE && \
objectStateInfo.lfsrPoly == INITIAL_LFSRPOLY && \
objectStateInfo.objectHandle == SYSTEM_OBJECT_HANDLE - 1 );
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 */
if( dependentObject != CRYPT_ERROR )
depth = \
( objectTable[ dependentObject ].dependentObject != CRYPT_ERROR || \
objectTable[ dependentObject ].dependentDevice != CRYPT_ERROR ) ? \
3 : 2;
else
if( objectTable[ objectHandle ].dependentDevice != CRYPT_ERROR )
depth = 2;
/* If the nesting level of the object matches the current level,
destroy it. We unlock the object table around the access to
prevent remaining active objects from blocking the shutdown (the
closingDown flag takes care of any other messages which may arrive
during this process).
"For death is come up into our windows, and it is entered into
our palaces, to cut off the children from the without"
-- Jeremiah 9:21 */
if( depth >= currentDepth )
{
unlockGlobalResource( objectTable );
krnlSendNotifier( objectHandle, RESOURCE_IMESSAGE_DESTROY );
status = CRYPT_ERROR_INCOMPLETE;
lockGlobalResource( objectTable );
}
}
return( status );
}
int destroyObjects( void )
{
int depth, objectHandle, status = CRYPT_OK;
/* Lock the object table to ensure other threads don't try to access
it */
lockGlobalResource( objectTable );
/* Indicate that we're in the middle of a shutdown. From now on all
messages other than object-destruction ones will be rejected by the
kernel. This is needed in order to have any remaining active objects
exit quickly, since we don't want them to block the shutdown */
isClosingDown = TRUE;
/* Delete every standard entry in the table. This is rather more complex
than just rumbling through deleting each object we find since some
objects have dependent objects underneath them, and deleting the
lower-level object causes problems when we later delete their parents
(the code handles it cleanly, but we get a kernel trap warning us that
we're trying to delete a non-present object). Because of this we have
to delete the objects in order of depth, first all three-level objects
(eg cert -> context -> device), then all two-level objects, and
finally all one-level objects. This means we can never delete another
object out from under a dependent object */
for( depth = 3; depth > 0; depth-- )
{
int localStatus = destroySelectedObjects( depth );
if( cryptStatusError( localStatus ) )
status = localStatus;
}
/* Postcondition: All user objects have been destroyed */
FORALL( i, NO_SYSTEM_OBJECTS, objectTableSize,
!memcmp( &objectTable[ i ], &objectTemplate, sizeof( OBJECT_INFO ) ) );
/* Destroy the system objects, which are all one-level objects. This is
done explicitly here because the dispatcher checks to make sure
they're never destroyed through a standard message, which indicates a
programming error */
for( objectHandle = 0; objectHandle < NO_SYSTEM_OBJECTS; objectHandle++ )
{
if( objectTable[ objectHandle ].messageFunction != NULL )
objectTable[ objectHandle ].messageFunction( objectHandle,
RESOURCE_MESSAGE_DESTROY, NULL, 0 );
objectTable[ objectHandle ] = objectTemplate;
}
/* Postcondition: All system objects have been destroyed */
FORALL( i, 0, NO_SYSTEM_OBJECTS,
!memcmp( &objectTable[ i ], &objectTemplate, sizeof( OBJECT_INFO ) ) );
/* Unlock the object table to allow access by other threads */
unlockGlobalResource( objectTable );
return( status );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?