?? cryptusr.c
字號:
/****************************************************************************
* *
* 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 + -