⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cryptkrn.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 that 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 )
			{
			unlockResource( objectTable );
			krnlSendNotifier( objectHandle, IMESSAGE_DESTROY );
			status = CRYPT_ERROR_INCOMPLETE;
			lockResource( objectTable );
			}
		}

	return( status );
	}

int destroyObjects( void )
	{
	int depth, objectHandle, status = CRYPT_OK;

	/* 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.  Note
	   that we do this before we lock the object table to encourage anything
	   that might have the table locked to exit quickly */
	isClosingDown = TRUE;

	/* Lock the object table to ensure that other threads don't try to
	   access it */
	lockResource( objectTable );

	/* Destroy all system objects except the root system object ("The death of
	   God left the angels in a strange position" - Donald Barthelme, "On
	   Angels").  We have to do this before we destroy any unclaimed leftover
	   objects because some of them may depend on system objects, if the
	   system objects aren't destroyed they'll be erroneously flagged as
	   leftover objects.  The destruction is done explicitly by invoking the
	   object's message function directly because the dispatcher checks to
	   make sure that they're never destroyed through a standard message,
	   which indicates a programming error */
	for( objectHandle = SYSTEM_OBJECT_HANDLE + 1;
		 objectHandle < NO_SYSTEM_OBJECTS; objectHandle++ )
		{
		if( objectTable[ objectHandle ].messageFunction != NULL )
			objectTable[ objectHandle ].messageFunction( \
									objectTable[ objectHandle ].objectPtr,
									MESSAGE_DESTROY, NULL, 0 );
		objectTable[ objectHandle ] = OBJECT_INFO_TEMPLATE;
		}

	/* Postcondition: All system objects except the root system object have
	   been destroyed */
	FORALL( i, SYSTEM_OBJECT_HANDLE + 1, NO_SYSTEM_OBJECTS,
			!memcmp( &objectTable[ i ], &OBJECT_INFO_TEMPLATE, \
					 sizeof( OBJECT_INFO ) ) );

	/* Delete any unclaimed leftover objects.  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
	   (e.g. 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 objects except the root system object have been
	   destroyed */
	FORALL( i, SYSTEM_OBJECT_HANDLE + 1, objectTableSize,
			!memcmp( &objectTable[ i ], &OBJECT_INFO_TEMPLATE, \
					 sizeof( OBJECT_INFO ) ) );

	/* Finally, destroy the root system object */
	objectTable[ SYSTEM_OBJECT_HANDLE ].messageFunction( \
								objectTable[ SYSTEM_OBJECT_HANDLE ].objectPtr,
								MESSAGE_DESTROY, NULL, 0 );
	objectTable[ SYSTEM_OBJECT_HANDLE ] = OBJECT_INFO_TEMPLATE;

	/* Unlock the object table to allow access by other threads */
	unlockResource( objectTable );

	return( status );
	}

static void endObjectTable( void )
	{
	/* Hinc igitur effuge */
	lockResource( objectTable );
	zeroise( objectTable, objectTableSize * sizeof( OBJECT_INFO ) );
	clFree( "endObjectTable", objectTable );
	objectTable = NULL;
	isClosingDown = FALSE;
	unlockResource( objectTable );
	deleteResourceLock( objectTable );
	}

/****************************************************************************
*																			*
*						Alternative Object Acquisition						*
*																			*
****************************************************************************/

/* 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 krnlGetObject()/
   krnlReleaseObject() functions to obtain access to the second object's
   internals.  These two functions can only provide access to certificates
   (used when copying internal state such as cert extensions or CRL info
   from one cert object to another), crypt hardware devices other than the
   system object (used when a context tied to a device needs to perform an
   operation using the device), and user objects (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).

   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 */

/* Wait for an object to become available so that we can use it, with a
   timeout for blocked objects.  This is an internal function which is used
   when mapping an object handle to object data, and is never called
   directly.  As an aid in identifying objects acting as bottlenecks, we
   provide a function to warn about excessive waiting, along with information
   on the object that was waited on, in debug mode */

#define MAX_WAITCOUNT				10000
#define WAITCOUNT_WARN_THRESHOLD	10

#ifndef NDEBUG

#include <stdio.h>

static void waitWarn( const int objectHandle, const int waitCount )
	{
	static const char *objectTypeNames[] = {
		"None", "Context", "Keyset", "Envelope", "Certificate", "Device",
		"Session", "User", "None", "None"
		};
	const OBJECT_INFO *objectInfoPtr = &objectTable[ objectHandle ];
	char buffer[ 128 ];

	if( objectHandle == SYSTEM_OBJECT_HANDLE )
		strcpy( buffer, "system object" );
	else
		sPrintf( buffer, "%d (type %s, subtype %lX)",
				 objectHandle, objectInfoPtr->type, objectInfoPtr->subType );
	fprintf( stderr, "\nWarning: Thread %X waited %d iteration%s for %s.\n",
			 THREAD_SELF(), waitCount, ( waitCount == 1 ) ? "" : "s",
			 buffer );
	}
#endif /* Debug mode only */

static int waitForObject( const int objectHandle,
						  OBJECT_INFO **objectInfoPtrPtr )
	{
	const unsigned int uniqueID = objectTable[ objectHandle ].uniqueID;
	int waitCount = 0;

	/* Preconditions: The object is in use by another thread */
	PRE( isValidObject( objectHandle ) );
	PRE( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) );

	/* While the object is busy, put the thread to sleep.  This is the
	   optimal portable way to wait on the resource, since it gives up this
	   thread's timeslice to allow other threads (including the one using
	   the object) to run (other methods such as mutexes with timers are
	   difficult to manage portably across different platforms) */
	while( objectTable[ objectHandle ].uniqueID == uniqueID && \
		   isInUse( objectHandle ) && waitCount < MAX_WAITCOUNT && \
		   !isClosingDown )
		{
		unlockResource( objectTable );
		waitCount++;
		THREAD_YIELD();
		lockResource( objectTable );
		}
#ifndef NDEBUG
	if( waitCount > WAITCOUNT_WARN_THRESHOLD )
		/* If we waited more than WAITCOUNT_WARN_THRESHOLD iterations for
		   something this could be a sign of a resource usage bottleneck,
		   warn the user that there's a potential problem */
		waitWarn( objectHandle, waitCount );
#endif /* NDEBUG */

	/* If cryptlib is shutting down, exit */
	if( isClosingDown )
		return( CRYPT_ERROR_PERMISSION );

	/* If we timed out waiting for the object, return a timeout error */
	if( waitCount >= MAX_WAITCOUNT )
		{
		assert( NOTREACHED );
		return( CRYPT_ERROR_TIMEOUT );
		}

	/* Make sure that nothing happened to the object while we were waiting
	   on it */
	if( objectTable[ objectHandle ].uniqueID != uniqueID )
		return( CRYPT_ERROR_SIGNALLED );

	/* Update the object info pointer in case the object table was updated
	   while we had yielded control */
	*objectInfoPtrPtr = &objectTable[ objectHandle ];

	/* Postconditions: The object is available for use */
	POST( isValidObject( objectHandle ) );
	POST( !isInUse( objectHandle ) );

	return( CRYPT_OK );
	}

/* Release an object that we previously acquired directly.  Note that we can
   release the system object here (done when we don't need it any more but
   need to carry out further operations with other objects), but we can't
   ever acquire it */

static int releaseObject( const int objectHandle,
						  const BOOLEAN isNonKernelCall )
	{
	OBJECT_INFO *objectInfoPtr;
	DECLARE_ORIGINAL_INT( lockCount );

	lockResource( objectTable );

	/* Preconditions: The object is in use by the caller */
	PRE( isValidObject( objectHandle ) );
	PRE( isInUse( objectHandle ) && isObjectOwner( objectHandle ) );

	/* 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 ] ) )
		{
		unlockResource( objectTable );
		return( CRYPT_ARGERROR_OBJECT );
		}

	/* It's a valid object, get its info */
	objectInfoPtr = &objectTable[ objectHandle ];
	STORE_ORIGINAL_INT( lockCount, objectInfoPtr->lockCount );

	/* Inner precondition: The object is in use and is of the correct type */
	PRE( isInUse( objectHandle ) && isObjectOwner( objectHandle ) );
	PRE( ( isNonKernelCall && \
					( objectInfoPtr->type == OBJECT_TYPE_CERTIFICATE || \
					  objectInfoPtr->type == OBJECT_TYPE_DEVICE || \
					  objectInfoPtr->type == OBJECT_TYPE_USER ) ) || \
		 ( !isNonKernelCall && objectInfoPtr->type == OBJECT_TYPE_CONTEXT ) );

	/* Safety check: We should never be releasing an object that we don't
	   hold or which is of the incorrect type */
	if( !isInUse( objectHandle ) || !isObjectOwner( objectHandle ) )
		{
		unlockResource( objectTable );
		assert( NOTREACHED );
		return( CRYPT_ERROR_PERMISSION );
		}
	if( ( isNonKernelCall && \
		  objectInfoPtr->type != OBJECT_TYPE_CERTIFICATE && \
		  objectInfoPtr->type != OBJECT_TYPE_DEVICE && \
		  objectInfoPtr->type != OBJECT_TYPE_USER ) || \
		( !isNonKernelCall && objectInfoPtr->type != OBJECT_TYPE_CONTEXT ) )
		{
		unlockResource( objectTable );
		assert( NOTREACHED );
		return( CRYPT_ERROR_PERMISSION );
		}

	objectInfoPtr->lockCount--;

	/* Postcondition: The object's lock count has been decremented and is
	   non-negative */
	POST( objectInfoPtr->lockCount == \
							ORIGINAL_VALUE( lockCount ) - 1 );
	POST( objectInfoPtr->lockCount >= 0 );

	unlockResource( objectTable );
	return( CRYPT_OK );
	}

/* Acquire/release an object */

int krnlGetObject( const int objectHandle, const OBJECT_TYPE type,
				   void **objectPtr, const int errorCode )
	{
	OBJECT_INFO *objectInfoPtr;
	int status = CRYPT_OK;

	/* Preconditions: It's a valid object */
	PRE( isValidHandle( objectHandle ) && \
		 objectHandle != SYSTEM_OBJECT_HANDLE );
	PRE( isValidType( type ) && \
		 ( type == OBJECT_TYPE_CERTIFICATE || \
		   type == OBJECT_TYPE_DEVICE || type == OBJECT_TYPE_USER ) );
	PRE( isWritePtr( objectPtr, sizeof( void * ) ) );

	/* Clear the return value */
	*objectPtr = NULL;

	lockResource( objectTable );

	/* Perform similar access checks to the ones performed in
	   krnlSendMessage(): It's a valid object of the correct type, and owned
	   by the calling thread */
	if( !isValidObject( objectHandle ) || \

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -