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

📄 cryptusr.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*							cryptlib User Routines							*
*						Copyright Peter Gutmann 1999-2002					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
  #include "asn1.h"
  #include "asn1oid.h"
#else
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1oid.h"
#endif /* Compiler-specific includes */

/* States for the user object */

typedef enum {
	USER_STATE_NONE,				/* No initialisation state */
	USER_STATE_SOINITED,			/* SSO inited, not usable */
	USER_STATE_USERINITED,			/* User inited, usable */
	USER_STATE_LOCKED,				/* Disabled, not usable */
	USER_STATE_LAST					/* Last possible state */
	} USER_STATE_TYPE;

/* The structure which stores the information on a user */

typedef struct UI {
	/* Control and status information */
	CRYPT_USER_TYPE type;			/* User type */
	USER_STATE_TYPE state;			/* User object state */
	BYTE userName[ CRYPT_MAX_TEXTSIZE + 1 ];
	int userNameLength;				/* User name */
	BYTE userID[ KEYID_SIZE ], creatorID[ KEYID_SIZE ];
									/* ID of user and creator of this user */
	int fileRef;					/* User info keyset reference */

	/* Configuration options for this user.  These aren't handled directly by
	   the user object code but are managed externally through the config 
	   code, so they're just treated as a dynamically-allocated blob within
	   the user object */
	void *configOptions;

	/* The user object contains an associated keyset which is used to store
	   user information to disk, in addition for SOs and CAs it also contains
	   an associated encryption context, either a private key (for an SO) or
	   a conventional key (for a CA) */
	CRYPT_KEYSET iKeyset;			/* Keyset */
	CRYPT_CONTEXT iCryptContext;	/* Private/secret key */

	/* Error information */
	CRYPT_ATTRIBUTE_TYPE errorLocus;/* Error locus */
	CRYPT_ERRTYPE_TYPE errorType;	/* Error type */

	/* When we clone an object, there are certain per-instance fields which
	   don't get cloned.  These fields are located after the following
	   member, and must be initialised by the cloning function */
	int _sharedEnd;					/* Dummy used for end of shared fields */

	/* The object's handle, used when sending messages to the object when
	   only the xxx_INFO is available */
	CRYPT_HANDLE objectHandle;

	/* In multithreaded environments we need to protect the information from
	   access by other threads while we use it.  The following macro declares
	   the actual variables required to handle the resource locking (the
	   actual values are defined in cryptos.h) */
	DECLARE_OBJECT_LOCKING_VARS
	} USER_INFO;

/* User information as read from the user info file */

typedef struct {
	CRYPT_USER_TYPE type;			/* User type */
	USER_STATE_TYPE state;			/* User state */
	BYTE userName[ CRYPT_MAX_TEXTSIZE + 1 ];
	int userNameLength;				/* User name */
	BYTE userID[ KEYID_SIZE ];		/* User ID */
	BYTE creatorID[ KEYID_SIZE ];	/* Creator ID */
	int fileRef;					/* User info file reference */
	} USER_FILE_INFO;

/* Default and primary SO user info */

static const USER_FILE_INFO defaultUserInfo = {
	CRYPT_USER_NONE,				/* Special-case SO+normal user */
	USER_STATE_USERINITED,			/* Initialised, ready for use */
	"Default cryptlib user", 21,	/* Pre-set user name */
	"<<<<DEFAULT_USER>>>>", "<<<<DEFAULT_USER>>>>", 
	CRYPT_UNUSED					/* No corresponding user file */
	};
static const USER_FILE_INFO primarySOInfo = {
	CRYPT_USER_SO,					/* SO user */
	USER_STATE_SOINITED,			/* SO initialised, not ready for use */
	"Security officer", 16,			/* Pre-set user name */
	"<<<PRIMARYSO_USER>>>", "<<<TETRAGRAMMATON>>>",
	-1			/* No user file when starting from zeroised state */
	};

/* The primary SO password after zeroisation */

#define PRIMARYSO_PASSWORD		"zeroised"
#define PRIMARYSO_ALTPASSWORD	"zeroized"
#define PRIMARYSO_PASSWORD_LENGTH 8

/* Prototypes for functions in cryptcfg.c */

int initOptions( void **configOptionsPtr );
void endOptions( void *configOptions );
int setOption( void *configOptions, const CRYPT_ATTRIBUTE_TYPE option, 
			   const int value );
int setOptionString( void *configOptions, const CRYPT_ATTRIBUTE_TYPE option, 
					 const char *value, const int valueLength );
int getOption( void *configOptions, const CRYPT_ATTRIBUTE_TYPE option );
char *getOptionString( void *configOptions, 
					   const CRYPT_ATTRIBUTE_TYPE option );
int readConfig( const CRYPT_USER cryptUser, const char *fileName );
int encodeConfigData( void *configOptions, const char *fileName, 
					  void **data, int *length );
int commitConfigData( const char *fileName, const void *data, 
					  const int length );

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* The maximum size of the index data for a user, ~128 bytes, and for the 
   fixed user information */

#define MAX_USERINDEX_SIZE	( 16 + ( KEYID_SIZE * 2 ) + CRYPT_MAX_TEXTSIZE + 8 )
#define MAX_USERINFO_SIZE	MAX_USERINDEX_SIZE

/* The size of the default buffer used to read data from a keyset.  If
   the data is larger than this, a large buffer is allocated dynamically */

#define KEYSET_BUFFERSIZE	1024

/* The different types of userID which we can use for matching purposes */

typedef enum {
	USERID_NONE,		/* No userID type */
	USERID_USERID,		/* User's userID */
	USERID_CREATORID,	/* Creating SO's userID */
	USERID_NAME,		/* User's name */
	USERID_LAST			/* Last possible userID type */
	} USERID_TYPE;

/* Find a user in the user index.  Note that this search implements a flat
   namespace rather than allowing duplicate names created by different SOs
   because when we're looking up a user we don't know which SO they belong
   to until after we've looked them up */

static int findUser( const void *userIndexData, const int userIndexDataLength,
					 const USERID_TYPE idType, const void *userID, 
					 const int userIDlength )
	{
	STREAM stream;
	int fileReference = CRYPT_ERROR_NOTFOUND, status;

	/* Check each entry to make sure the user name or ID aren't already 
	   present */
	sMemConnect( &stream, userIndexData, userIndexDataLength );
	while( stell( &stream ) < userIndexDataLength )
		{
		BYTE userData[ 128 ];
		long newFileReference;
		int userDataLength;

		readSequence( &stream, NULL );
		if( idType == USERID_USERID )
			readOctetString( &stream, userData, &userDataLength, KEYID_SIZE );
		else
			readUniversal( &stream );
		if( idType == USERID_CREATORID )
			readOctetString( &stream, userData, &userDataLength, KEYID_SIZE );
		else
			readUniversal( &stream );
		if( idType == USERID_NAME )
			readOctetStringTag( &stream, userData, &userDataLength, 
								CRYPT_MAX_TEXTSIZE, BER_STRING_UTF8 );
		else
			readUniversal( &stream );
		status = readShortInteger( &stream, &newFileReference );
		if( cryptStatusError( status ) )
			break;
		if( userIDlength == userDataLength && \
			!memcmp( userData, userData, userDataLength ) )
			{
			fileReference = ( int ) newFileReference;
			break;
			}
		}
	sMemDisconnect( &stream );

	return( cryptStatusError( status ) ? status : fileReference );
	}

/* Open a user keyset */

static int openUserKeyset( CRYPT_KEYSET *iUserKeyset, const char *fileName,
						   const int options )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	char userFilePath[ MAX_PATH_LENGTH + 128 ];	/* Protection for Windows */
	int status;

	/* Clear return value */
	*iUserKeyset = CRYPT_ERROR;

	/* Open the given keyset */
	fileBuildCryptlibPath( userFilePath, fileName, 
						   ( options == CRYPT_KEYOPT_READONLY ) ? \
						   FALSE : TRUE );
	setMessageCreateObjectInfo( &createInfo, CRYPT_KEYSET_FILE );
	createInfo.arg2 = options;
	createInfo.strArg1 = userFilePath;
	createInfo.strArgLen1 = strlen( userFilePath );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_KEYSET );
	if( cryptStatusOK( status ) )
		*iUserKeyset = createInfo.cryptHandle;
	return( status );
	}

/* Read data from a user keyset.  This takes a pointer to a buffer and
   optionally allocates a larger buffer if required, with behaviour
   determined by the overallocSize parameter.  If it's less than zero
   then no attempt to allocate a larger buffer is made, if it's zero
   then a larger buffer is allocated, and if it's larger than zero then
   a buffer of the required size plus the overallocSize value is
   allocated */

static int readUserData( const CRYPT_KEYSET iUserKeyset, 
						 const CRYPT_ATTRIBUTE_TYPE dataType, 
						 void **data, int *dataLength, 
						 const int overallocSize )
	{
	RESOURCE_DATA msgData;
	void *dataPtr = *data;
	int status;

	/* Clear return value */
	*dataLength = 0;

	/* Read the requested data from the keyset, allocating a bigger
	   buffer if required.  When we allocate the buffer we add a caller-
	   specified over-allocation amount to handle any extra data the caller
	   wants to add to the buffer */
	setResourceData( &msgData, NULL, 0 );
	status = krnlSendMessage( iUserKeyset, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
							  &msgData, dataType );
	if( cryptStatusError( status ) )
		return( status );
	if( msgData.length > KEYSET_BUFFERSIZE )
		{
		if( overallocSize == CRYPT_ERROR )
			/* Don't try to reallocate the buffer if it's too small, there
			   shouldn't be this much data present */
			return( CRYPT_ERROR_OVERFLOW );
		if( ( dataPtr = malloc( msgData.length + overallocSize ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		}
	msgData.data = dataPtr;
	status = krnlSendMessage( iUserKeyset, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
							  &msgData, dataType );
	if( cryptStatusError( status ) )
		{
		if( dataPtr != *data )
			free( dataPtr );
		}
	else
		{
		*data = dataPtr;
		*dataLength = msgData.length;
		}
	return( status );
	}

/* Find the file reference for a given user in the index keyset */

static int findUserFileRef( const USERID_TYPE idType, const BYTE *id, 
							const int idLength )
	{
	CRYPT_KEYSET iUserKeyset;
	BYTE buffer[ KEYSET_BUFFERSIZE ];
	void *bufPtr = buffer;
	int length, status;

	/* Open the index file and read the index entries from it */
	status = openUserKeyset( &iUserKeyset, "index", CRYPT_KEYOPT_READONLY );
	if( cryptStatusError( status ) )
		{
		/* If there's no index file present, we're in the zeroised state,
		   the only valid user is the (implicitly present) primary SO */
		if( status == CRYPT_ERROR_NOTFOUND && idType == USERID_NAME && \
			idLength == primarySOInfo.userNameLength && \
			!memcmp( id, primarySOInfo.userName, 
					 primarySOInfo.userNameLength ) )
			status = OK_SPECIAL;

		return( status );
		}
	status = readUserData( iUserKeyset, CRYPT_IATTRIBUTE_USERINDEX,
						   &bufPtr, &length, 0 );
	krnlSendNotifier( iUserKeyset, RESOURCE_IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		{
		if( bufPtr != buffer )
			free( bufPtr );
		return( status );
		}

	/* Check whether this user is present in the index */
	status = findUser( bufPtr, length, idType, id, idLength );
	if( bufPtr != buffer )
		free( bufPtr );

	return( status );
	}

/* Insert a new entry into the index */

static int insertIndexEntry( const USER_INFO *userInfoPtr, 
							 BYTE *userIndexData, int *userIndexDataLength )
	{
	STREAM stream;
	BYTE userInfoBuffer[ MAX_USERINDEX_SIZE ];
	int userInfoLength, newReference = 0, lastPos = 0;

	/* If there's already index data present, find the appropriate place to
	   insert the new entry and the file reference to use */
	if( *userIndexDataLength )
		{
		sMemConnect( &stream, userIndexData, *userIndexDataLength );
		while( stell( &stream ) < *userIndexDataLength )
			{
			long fileReference;
			int status;

			/* Read an index entry and check whether the file reference
			   matches the expected file reference */
			readSequence( &stream, NULL );
			readUniversal( &stream );
			readUniversal( &stream );
			status = readShortInteger( &stream, &fileReference );
			if( cryptStatusError( status ) )
				{
				sMemDisconnect( &stream );
				return( status );
				}
			if( fileReference != newReference )
				break;
			lastPos = stell( &stream );
			newReference++;
			}
		sMemDisconnect( &stream );
		}

	/* We've found an unused reference, insert the user data at this point */
	sMemOpen( &stream, userInfoBuffer, MAX_USERINDEX_SIZE );

⌨️ 快捷键说明

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