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 + -
显示快捷键?