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

📄 user.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*							cryptlib User Routines							*
*						Copyright Peter Gutmann 1999-2007					*
*																			*
****************************************************************************/

#include <stdio.h>		/* For snprintf_s() */
#include "crypt.h"
#ifdef INC_ALL
  #include "trustmgr.h"
  #include "asn1.h"
  #include "asn1_ext.h"
  #include "user.h"
#else
  #include "cert/trustmgr.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
  #include "misc/user.h"
#endif /* Compiler-specific includes */

/* The different types of userID that we can use to look up users in the 
   index */

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;

/* cryptlib can work with multiple users (although it's extremely unlikely 
   that there'll ever be more than one or two), we allow a maximum of 
   MAX_USER_OBJECTS in order to discourage them from being used as a
   substitute for OS user management.  A setting of 32 objects consumes 
   ~4K of memory (32 x ~128), so we choose that as the limit */

#ifdef CONFIG_CONSERVE_MEMORY
  #define MAX_USER_OBJECTS		4
#else
  #define MAX_USER_OBJECTS		32
#endif /* CONFIG_CONSERVE_MEMORY */

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

#define USERDATA_BUFFERSIZE		1024

/* The maximum size of the encoded index data */

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

/* Primary SO user info */

static const USER_FILE_INFO FAR_BSS 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

/* The structure that stores the user index in the default user object */

typedef struct {
	USER_FILE_INFO userIndex[ MAX_USER_OBJECTS ];	/* User index */
	int lastEntry;					/* Last entry in user index */
	} USER_INDEX_INFO;

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

/* Open a user or index keyset */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int openKeyset( OUT_HANDLE_OPT CRYPT_KEYSET *iKeyset, 
					   IN_BUFFER( fileNameLen ) const char *fileName, 
					   IN_LENGTH_SHORT const int fileNameLen, 
					   IN_ENUM_OPT( CRYPT_KEYOPT ) const int options )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	char userFilePath[ MAX_PATH_LENGTH + 8 ];
	int userFilePathLen, status;

	assert( isWritePtr( iKeyset, sizeof( CRYPT_KEYSET ) ) );
	assert( isReadPtr( fileName, fileNameLen ) );

	REQUIRES( fileNameLen > 0 && fileNameLen < MAX_INTLENGTH_SHORT );
	REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );

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

	/* Open the given keyset */
	status = fileBuildCryptlibPath( userFilePath, MAX_PATH_LENGTH, 
									&userFilePathLen, fileName, fileNameLen, 
									( options == CRYPT_KEYOPT_READONLY ) ? \
									BUILDPATH_GETPATH : BUILDPATH_CREATEPATH );
	if( cryptStatusError( status ) )
		{
		/* Map the lower-level filesystem-specific error into a more 
		   meaningful generic error */
		return( CRYPT_ERROR_OPEN );
		}
	setMessageCreateObjectInfo( &createInfo, CRYPT_KEYSET_FILE );
	createInfo.arg2 = options;
	createInfo.strArg1 = userFilePath;
	createInfo.strArgLen1 = userFilePathLen;
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
							  OBJECT_TYPE_KEYSET );
	if( cryptStatusOK( status ) )
		*iKeyset = createInfo.cryptHandle;
	return( status );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int openUserKeyset( OUT_HANDLE_OPT CRYPT_KEYSET *iUserKeyset, 
						   IN_INT_SHORT_Z const int fileRef, 
						   IN_ENUM_OPT( CRYPT_KEYOPT ) const int options )
	{
	char userFileName[ 16 + 8 ];
	int userFileNameLen;

	assert( isWritePtr( iUserKeyset, sizeof( CRYPT_KEYSET ) ) );

	REQUIRES( fileRef >= 0 && fileRef < MAX_INTLENGTH_SHORT );
	REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );

	userFileNameLen = sprintf_s( userFileName, 16, "u%06x", fileRef );
	return( openKeyset( iUserKeyset, userFileName, userFileNameLen, 
						options ) );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int openIndexKeyset( OUT CRYPT_KEYSET *iIndexKeyset, 
							IN_ENUM_OPT( CRYPT_KEYOPT ) const int options )
	{
	assert( isWritePtr( iIndexKeyset, sizeof( CRYPT_KEYSET ) ) );

	REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );

	return( openKeyset( iIndexKeyset, "index", 5, options ) );
	}

/* Add a user key to the keyset */

CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5 ) ) \
static int addKey( IN_HANDLE const CRYPT_KEYSET iUserKeyset, 
				   IN_HANDLE const CRYPT_CONTEXT iCryptContext,
				   IN_BUFFER( userIdLength ) const void *userID, 
				   IN_LENGTH_SHORT const int userIdLength,
				   IN_BUFFER( passwordLength ) const char *password, 
				   IN_LENGTH_SHORT const int passwordLength,
				   const BOOLEAN isPrivateKey )
	{
	MESSAGE_KEYMGMT_INFO setkeyInfo;
	MESSAGE_DATA msgData;
	int status;

	assert( isReadPtr( userID, userIdLength ) );
	assert( isReadPtr( password, passwordLength ) );

	REQUIRES( isHandleRangeValid( iUserKeyset ) );
	REQUIRES( isHandleRangeValid( iCryptContext ) );
	REQUIRES( userIdLength > 0 && userIdLength < MAX_INTLENGTH_SHORT );
	REQUIRES( passwordLength > 0 && passwordLength < MAX_INTLENGTH_SHORT );

	setMessageData( &msgData, ( void * ) userID, userIdLength );
	status = krnlSendMessage( iUserKeyset, IMESSAGE_SETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_USERID );
	if( cryptStatusError( status ) )
		return( status );

	setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
						   ( void * ) password, passwordLength,
						   KEYMGMT_FLAG_NONE );
	setkeyInfo.cryptHandle = iCryptContext;
	status = krnlSendMessage( iUserKeyset, IMESSAGE_KEY_SETKEY,
							  &setkeyInfo, isPrivateKey ? \
								KEYMGMT_ITEM_PRIVATEKEY : \
								KEYMGMT_ITEM_SECRETKEY );
	return( status );
	}

/****************************************************************************
*																			*
*								Manage User Index							*
*																			*
****************************************************************************/

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
static const USER_FILE_INFO *findUser( IN_ARRAY( noUserIndexEntries ) \
										const USER_FILE_INFO *userIndex,
									   IN_RANGE( 1, MAX_USER_OBJECTS ) \
										const int noUserIndexEntries, 
									   IN_ENUM( USERID ) const USERID_TYPE idType, 
									   IN_BUFFER( idLength ) const BYTE *id, 
									   IN_LENGTH_SHORT const int idLength )
	{
	int i, iterationCount;

	assert( isReadPtr( userIndex, \
					   sizeof( USER_FILE_INFO ) * noUserIndexEntries ) );
	assert( isReadPtr( id, idLength ) );

	REQUIRES_N( noUserIndexEntries > 0 && \
				noUserIndexEntries <= MAX_USER_OBJECTS );
	REQUIRES_N( idType > USERID_NONE && idType < USERID_LAST );
	REQUIRES_N( idLength > 0 && idLength < MAX_INTLENGTH_SHORT );

	for( i = 0, iterationCount = 0; 
		 i < noUserIndexEntries && \
			iterationCount < FAILSAFE_ITERATIONS_LARGE; 
		 i++, iterationCount++ )
		{
		const USER_FILE_INFO *userIndexPtr = &userIndex[ i ];

		switch( idType )
			{
			case USERID_USERID:
				if( idLength == KEYID_SIZE && \
					!memcmp( userIndexPtr->userID, id, idLength ) )
					return( userIndexPtr );
				break;

			case USERID_CREATORID:
				if( idLength == KEYID_SIZE && \
					!memcmp( userIndexPtr->creatorID, id, idLength ) )
					return( userIndexPtr );
				break;

			case USERID_NAME:
				if( idLength == userIndexPtr->userNameLength && \
					!memcmp( userIndexPtr->userName, id, idLength ) )
					return( userIndexPtr );
				break;

			default:
				retIntError_Null();
			}
		}
	ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );

	return( NULL );
	}

/* Find a free user entry */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static USER_FILE_INFO *findFreeEntry( IN_ARRAY( noUserIndexEntries ) \
										USER_FILE_INFO *userIndex,
									  IN_RANGE( 1, MAX_USER_OBJECTS ) \
										const int noUserIndexEntries,
									  OUT_INT_SHORT_Z int *fileRef )
	{
	USER_FILE_INFO *userIndexPtr;
	int newFileRef, i, iterationCount;

	assert( isWritePtr( userIndex, \
						sizeof( USER_FILE_INFO ) * noUserIndexEntries ) );
	assert( isWritePtr( fileRef, sizeof( int ) ) );

	REQUIRES_N( noUserIndexEntries > 0 && \
				noUserIndexEntries <= MAX_USER_OBJECTS );

	/* Look for an available free entry */
	for( i = 0, iterationCount  = 0; 
		 i < noUserIndexEntries && \
			iterationCount < FAILSAFE_ITERATIONS_LARGE; 
		 i++, iterationCount++ )
		{
		if( userIndex[ i ].state == USER_STATE_NONE )
			break;
		}
	ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );
	if( i >= noUserIndexEntries )
		{
		/* No more available entries */
		*fileRef = CRYPT_ERROR;
		return( NULL );
		}

	/* Remember where we found our match */
	userIndexPtr = &userIndex[ i ];

	/* We've found a free entry, now look for an unused fileRef.  There are 
	   two possible strategies for this, the first is to make it generational
	   and always allocate a new fileRef, the second is to use the smallest
	   available value, i.e. to re-use values.  The former has problems with
	   overflow (although it'd have to be a pretty funny situation to cause 
	   this), the latter has potential problems with user confusion when one
	   ref #3 user file is replaced by another ref #3 file that belongs to
	   a completely different user.  However, even the generational approach
	   has problems (unless we can make the last-used fileRef persistent)
	   because deleting the highest-numbered ref. and then creating a new one
	   will result in the fileRef being re-allocated to the newly-created
	   file.

	   Since this is all highly speculative (it's not certain under what 
	   conditions we could run into these problems because users aren't 
	   expected to be bypassing cryptlib to directly access the user files),
	   we take the simplest approach and use the lowest-value free fileRef.
	   This is somewhat ugly because it's potentially an O( n^2 ) operation,
	   but the actualy impact is insignificant because the number of users
	   is tiny and new user creation is extremely rare, so it's not worth
	   switching to the complexity of a more sophisticated algorithm */
	for( newFileRef = 0; newFileRef < MAX_USER_OBJECTS; newFileRef++ )
		{
		/* Check whether this fileRef is already in use.  If not, we're
		   done */
		for( i = 0; i < noUserIndexEntries; i++ )
			{
			if( userIndex[ i ].fileRef == newFileRef )

⌨️ 快捷键说明

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