📄 cryptlib.c
字号:
/****************************************************************************
* *
* cryptlib Core Routines *
* Copyright Peter Gutmann 1992-2002 *
* *
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crypt.h"
/* Prototypes for functions in cryptkrn.c */
BOOLEAN beginInitialisation( const BOOLEAN checkState );
void endInitialisation( const BOOLEAN newState );
int initInternalFunctions( void );
int destroyObjects( void );
void endInternalFunctions( void );
/* Prototypes for functions in cryptcrt.c */
int initTrustInfo( void );
void endTrustInfo( void );
/* Prototypes for functions in cryptdev.c and cryptusr.c */
int createSystemDeviceObject( void );
int createDefaultUserObject( void );
/****************************************************************************
* *
* Startup/Shutdown Routines *
* *
****************************************************************************/
/* Initialisation/shutdown functions for other parts of the library */
void initDevices( void );
void shutdownDevices( void );
void initKeysets( void );
void shutdownKeysets( void );
/* There isn't any good place to put the networking init/shutdown code so we
handle it ourselves here. Before we can end the networking subsystem we
have to signal that a shutdown is about to occur in order to gracefully
exit from any currently occurring network I/O, if we didn't do this then
objects blocked on network I/O couldn't be cleaned up */
void netInitTCP( void );
void netSignalShutdown( void );
void netEndTCP( void );
static void initNetworking( void )
{
#ifdef NET_TCP
netInitTCP();
#endif /* NET_TCP */
}
static void shutdownNetworking( void )
{
#ifdef NET_TCP
netEndTCP();
#endif /* NET_TCP */
}
static void signalShutdownNetworking( void )
{
#ifdef NET_TCP
#if defined( __WIN32__ ) && !defined( NT_DRIVER )
/* We have to wait for the driver binding to complete before we can
start the shutdown process */
waitSemaphore( SEMAPHORE_DRIVERBIND );
#endif /* __WIN32__ && !NT_DRIVER */
netSignalShutdown();
#endif /* NET_TCP */
}
/* Under various OS's we bind to a number of drivers at runtime. We can
either do this sychronously or, under Win32, asynchronously (depending on
the setting of a config option). By default we use the async init since
it speeds up the startup. Synchronisation is achieved by having the open/
init functions in the modules which require the drivers call
waitSemaphore() on the driver binding semaphore, which blocks until the
drivers are bound if an async bind is in progress, or returns immediately
if no bind is in progress */
#if defined( __WIN32__ ) && !defined( NT_DRIVER )
#include <process.h>
void threadedBind( void *dummy )
{
UNUSED( dummy );
initKeysets();
initDevices();
initNetworking();
clearSemaphore( SEMAPHORE_DRIVERBIND );
_endthread();
}
static void bindDrivers( void )
{
int asyncInit;
/* Bind the drivers asynchronously or synchronously depending on the
config option setting. We always send this query to the default
user object since no other user objects exist at this time */
krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
RESOURCE_IMESSAGE_GETATTRIBUTE, &asyncInit,
CRYPT_OPTION_MISC_ASYNCINIT );
if( asyncInit )
{
HANDLE hThread;
/* Fire up the thread. Note the use of _beginthread() rather than
_beginthreadex(), since we want the thread to close its own
handle when it terminates */
hThread = ( HANDLE ) _beginthread( threadedBind, 0, NULL );
if( hThread )
{
setSemaphore( SEMAPHORE_DRIVERBIND, hThread );
return;
}
}
initKeysets();
initDevices();
initNetworking();
}
static void unbindDrivers( void )
{
/* Shut down any external interfaces after making sure that the
initalisation ran to completion */
waitSemaphore( SEMAPHORE_DRIVERBIND );
shutdownKeysets();
shutdownDevices();
shutdownNetworking();
}
#else
static void bindDrivers( void )
{
initKeysets();
initDevices();
initNetworking();
}
static void unbindDrivers( void )
{
shutdownKeysets();
shutdownDevices();
shutdownNetworking();
}
#endif /* __WIN32__ && !NT_DRIVER */
/* Test the kernel mechanisms to make sure everything's working as expected */
static BOOLEAN testKernelMechanisms( void )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
CRYPT_CONTEXT cryptContext;
static const BYTE key[] = { 0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31 };
BYTE buffer[ 8 ];
int value, status;
/* Verify object creation */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_DES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( FALSE );
cryptContext = createInfo.cryptHandle;
/* Verify inability to access internal object using external message */
if( krnlSendMessage( cryptContext, RESOURCE_MESSAGE_GETATTRIBUTE,
&value, CRYPT_CTXINFO_ALGO ) != CRYPT_ARGERROR_OBJECT )
{
krnlSendNotifier( cryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( FALSE );
}
/* Verify inability to perform state=high operation on state=low object */
if( krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_CTX_ENCRYPT,
buffer, 8 ) != CRYPT_ERROR_NOTINITED )
{
krnlSendNotifier( cryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( FALSE );
}
/* Verify ability to transition state=low object to state=high */
setResourceData( &msgData, ( void * ) key, 8 );
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEY );
if( cryptStatusError( status ) )
{
krnlSendNotifier( cryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( FALSE );
}
setResourceData( &msgData, ( void * ) key, 8 );
krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_IV );
/* Verify inability to perform state=low operations on state=high object.
These also test things like trying to load/generate a key into a non-
crypto context or non-native context since they're protected by the
same state=high check in the kernel */
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEY );
if( status == CRYPT_ERROR_PERMISSION )
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_CTX_GENKEY,
NULL, FALSE );
if( status != CRYPT_ERROR_PERMISSION )
{
krnlSendNotifier( cryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( FALSE );
}
/* Verify inability to perform disallowed action externally but still
perform it internally. Note that the object does become very briefly
visible externally at this point, but there's nothing which can be
done with it */
value = \
MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL );
krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE, &value,
CRYPT_IATTRIBUTE_ACTIONPERMS );
krnlSendMessage( createInfo.cryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_INTERNAL );
if( krnlSendMessage( cryptContext, RESOURCE_MESSAGE_CTX_ENCRYPT,
buffer, 8 ) != CRYPT_ERROR_PERMISSION || \
krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_CTX_ENCRYPT,
buffer, 8 ) != CRYPT_OK )
{
krnlSendNotifier( cryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( FALSE );
}
/* Verify ability to use object with a finite usage count and inability
to exceed the usage count */
value = 1;
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE,
&value, CRYPT_PROPERTY_USAGECOUNT );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_CTX_ENCRYPT,
buffer, 8 );
if( cryptStatusError( status ) || \
krnlSendMessage( cryptContext, RESOURCE_IMESSAGE_CTX_ENCRYPT,
buffer, 8 ) != CRYPT_ERROR_PERMISSION )
{
krnlSendNotifier( cryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( FALSE );
}
krnlSendNotifier( cryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
return( TRUE );
}
/* Initialise and shut down the system */
#if defined( __WIN32__ ) && defined( STATIC_LIB )
DEFINE_LOCKING_VARS( initialisation )
BOOLEAN isWin95;
#endif /* __WIN32__ && STATIC_LIB */
static int initCrypt( void )
{
int initLevel = 0, status;
/* If the Win32 version is being compiled as a static .LIB (not
recommended) we need to perform initialisation here. Note that in
this form cryptlib is no longer thread-safe */
#if defined( __WIN32__ ) && defined( STATIC_LIB )
static DWORD dwPlatform = ( DWORD ) CRYPT_ERROR;
/* Figure out which OS we're running under */
if( dwPlatform == CRYPT_ERROR )
{
OSVERSIONINFO osvi = { sizeof( osvi ) };
GetVersionEx( &osvi );
dwPlatform = osvi.dwPlatformId;
isWin95 = ( dwPlatform == VER_PLATFORM_WIN32_WINDOWS ) ? TRUE : FALSE;
/* Check for Win32s just in case someone tries to load the DLL under
it */
if( dwPlatform == VER_PLATFORM_WIN32s )
return( CRYPT_ERROR );
}
/* Set up the library initialisation lock */
initGlobalResourceLock( initialisation );
#endif /* __WIN32__ && STATIC_LIB */
/* If we've already been initialised, don't do anything */
if( !beginInitialisation( TRUE ) )
return( CRYPT_OK );
/* VisualAge C++ doesn't set the TZ correctly */
#if defined( __IBMC__ ) || defined( __IBMCPP__ )
tzset();
#endif /* VisualAge C++ */
/* Set up the initial hardwired configuration options, the internal
resources (semaphores, message functions, and the object table), and
the randomness pseudo-device */
status = initInternalFunctions();
if( cryptStatusOK( status ) )
{
/* Internal functions initialised, create the system objects */
initLevel++;
status = createSystemDeviceObject();
if( cryptStatusOK( status ) )
status = createDefaultUserObject();
}
if( cryptStatusOK( status ) )
{
/* System object created, read the config options and initialise the
certificate trust info (we have to initialise the trust info first
because reading the config options typically also reads in any
saved trust information). We ignore any return codes at this
point because we don't want all of cryptlib to fail because of a
problem in the config file - if there's a problem we fall back to
internal defaults */
initLevel++;
initTrustInfo();
bindDrivers();
}
/* Everything's set up, verify that the kernel's security mechanisms
are working as required */
if( cryptStatusOK( status ) && !testKernelMechanisms() )
{
/* We should probably sound klaxons as well at this point */
assert( NOTREACHED );
status = CRYPT_ERROR_FAILED;
}
/* If anything failed, shut down the internal functions and services
before we exit - this can only happens under exception circumstances,
because of this and because undoing the async.driver bind is rather
complex we don't bother with this (the OS will undo it anyway when
we're unloaded) */
if( !cryptStatusOK( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -