📄 cryptusr.c
字号:
RESOURCE_IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_KEYUSAGE );
if( cryptStatusError( status ) || !( value & requiredKeyUsage ) )
return( CRYPT_ARGERROR_NUM1 );
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/* Save this in the keyset at some point */
/* Handle get (gets public key) */
/* Handle delete (removes key) */
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
unlockResourceExit( userInfoPtr, status );
}
/* Anything else has to be a config option */
assert( message == RESOURCE_MESSAGE_SETATTRIBUTE || \
message == RESOURCE_MESSAGE_GETATTRIBUTE || \
message == RESOURCE_MESSAGE_SETATTRIBUTE_S || \
message == RESOURCE_MESSAGE_GETATTRIBUTE_S );
assert( messageValue > CRYPT_OPTION_FIRST && \
messageValue < CRYPT_OPTION_LAST );
/* Get/set string attributes */
if( message == RESOURCE_MESSAGE_GETATTRIBUTE_S )
{
RESOURCE_DATA *msgData = messageDataPtr;
const char *retVal = getOptionString( userInfoPtr->configOptions,
messageValue );
if( retVal == NULL )
{
/* No value set, clear the return value in case the caller
isn't checking the return code */
if( msgData->data != NULL )
*( ( char * ) msgData->data ) = '\0';
msgData->length = 0;
status = CRYPT_ERROR_NOTFOUND;
}
else
status = attributeCopy( msgData, retVal, strlen( retVal ) );
unlockResourceExit( userInfoPtr, status );
}
if( message == RESOURCE_MESSAGE_SETATTRIBUTE_S )
{
const RESOURCE_DATA *msgData = messageDataPtr;
status = setOptionString( userInfoPtr->configOptions,
messageValue, msgData->data,
msgData->length );
unlockResourceExit( userInfoPtr, status );
}
/* Get/set numeric attributes */
if( message == RESOURCE_MESSAGE_GETATTRIBUTE )
{
/* Numeric get can never fail */
*( ( int * ) messageDataPtr ) = \
getOption( userInfoPtr->configOptions,
messageValue );
unlockResourceExit( userInfoPtr, CRYPT_OK );
}
status = setOption( userInfoPtr->configOptions, messageValue,
*( ( int * ) messageDataPtr ) );
if( !( status == OK_SPECIAL && \
( messageValue == CRYPT_OPTION_CONFIGCHANGED || \
messageValue == CRYPT_OPTION_SELFTESTOK ) ) )
unlockResourceExit( userInfoPtr, status );
/* The following options control operations which are performed
in two phases. The reason for the split is that the second phase
doesn't require the use of the user object data any more and can
be a somewhat lengthy process due to disk accesses or lengthy
crypto operations. Because of this we unlock the user object
between the two phases to ensure that the second phase doesn't
stall all other operations which require this user object */
assert( status == OK_SPECIAL );
/* If it's a self-test, forward the message to the system object with
the user object unlocked, then re-lock it and set the self-test
result value. Since the self-test value will be in the busy state
at this point, we need to update it by setting the
CRYPT_OPTION_LAST pseudo-option */
if( messageValue == CRYPT_OPTION_SELFTESTOK )
{
unlockResource( userInfoPtr );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_SELFTEST );
getCheckInternalResource( cryptUser, userInfoPtr, OBJECT_TYPE_USER );
setOption( userInfoPtr->configOptions, CRYPT_OPTION_LAST,
cryptStatusOK( status ) ? TRUE : FALSE );
unlockResourceExit( userInfoPtr, status );
}
/* The config option write is performed in two phases, a first phase
which encodes the config data and a second phase which writes the
data to disk */
assert( messageValue == CRYPT_OPTION_CONFIGCHANGED );
if( userInfoPtr->fileRef == CRYPT_UNUSED )
strcpy( userFileName, "cryptlib" );
else
sprintf( userFileName, "u%06x", userInfoPtr->fileRef );
status = encodeConfigData( userInfoPtr->configOptions,
userFileName, &data, &length );
if( status != OK_SPECIAL )
unlockResourceExit( userInfoPtr, status );
/* We've got the config data in a memory buffer, we can unlock the
user object to allow external access while we commit the in-memory
data to disk */
unlockResource( userInfoPtr );
status = commitConfigData( userFileName, data, length );
free( data );
return( status );
}
/* Process messages which lock/unlock an object for exclusive use */
if( message == RESOURCE_MESSAGE_LOCK )
/* Exit without unlocking the object. Any other threads trying to
use the object after this point will be blocked */
return( CRYPT_OK );
if( message == RESOURCE_MESSAGE_UNLOCK )
{
/* "Wenn drei Leute in ein Zimmer reingehen und fuenf kommen raus,
dann muessen erst mal zwei wieder reingehen bis das Zimmer leer
ist" */
unlockResource( userInfoPtr ); /* Undo RESOURCE_MESSAGE_LOCK lock */
unlockResourceExit( userInfoPtr, CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Open a user object. This is a low-level function encapsulated by
createUser() and used to manage error exits */
static int openUser( CRYPT_USER *iCryptUser, const CRYPT_USER cryptOwner,
const USER_FILE_INFO *userFileInfo,
USER_INFO **userInfoPtrPtr )
{
USER_INFO *userInfoPtr;
const int subType = \
( userFileInfo->type == CRYPT_USER_NORMAL ) ? SUBTYPE_USER_NORMAL : \
( userFileInfo->type == CRYPT_USER_SO ) ? SUBTYPE_USER_SO : \
( userFileInfo->type == CRYPT_USER_CA ) ? SUBTYPE_USER_CA : \
( SUBTYPE_USER_NORMAL | SUBTYPE_USER_SO );
int status;
/* The default user is a special type which has both normal user and SO
privileges. This is because in its usual usage mode where cryptlib is
functioning as a single-user system the user doesn't know about the
existence of user objects and just wants everything to work the way
they expect. Because of this, the default user has to be able to
perform the full range of available operations, requiring that they
appear as both a normal user and an SO */
assert( userFileInfo->type == CRYPT_USER_NORMAL || \
userFileInfo->type == CRYPT_USER_SO || \
userFileInfo->type == CRYPT_USER_CA || \
( userFileInfo->type == CRYPT_USER_NONE && \
userFileInfo->userNameLength == \
defaultUserInfo.userNameLength && \
!memcmp( userFileInfo->userName, defaultUserInfo.userName,
defaultUserInfo.userNameLength ) ) );
/* Clear the return values */
*iCryptUser = CRYPT_ERROR;
*userInfoPtrPtr = NULL;
/* Create the user object */
status = krnlCreateObject( ( void ** ) &userInfoPtr, cryptOwner,
OBJECT_TYPE_USER, subType,
sizeof( USER_INFO ), 0, 0,
userMessageFunction );
if( cryptStatusError( status ) )
return( status );
initResourceLock( userInfoPtr );
lockResource( userInfoPtr );
*userInfoPtrPtr = userInfoPtr;
*iCryptUser = userInfoPtr->objectHandle = status;
userInfoPtr->type = userFileInfo->type;
userInfoPtr->state = userFileInfo->state;
userInfoPtr->fileRef = userFileInfo->fileRef;
memcpy( userInfoPtr->userName, userFileInfo->userName,
userFileInfo->userNameLength );
userInfoPtr->userNameLength = userFileInfo->userNameLength;
memcpy( userInfoPtr->userID, userFileInfo->userID, KEYID_SIZE );
memcpy( userInfoPtr->creatorID, userFileInfo->creatorID, KEYID_SIZE );
/* Set up any internal objects to contain invalid handles */
userInfoPtr->iKeyset = userInfoPtr->iCryptContext = CRYPT_ERROR;
/* Initialise the default user config options */
return( initOptions( &userInfoPtr->configOptions ) );
}
int createUser( MESSAGE_CREATEOBJECT_INFO *createInfo,
const void *auxDataPtr, const int auxValue )
{
CRYPT_USER iCryptUser;
USER_INFO *userInfoPtr;
char userFileName[ 16 ];
int fileRef, initStatus, status;
assert( auxDataPtr == NULL );
assert( auxValue == 0 );
/* Perform basic error checking */
if( createInfo->strArgLen1 < 2 || \
createInfo->strArgLen1 > CRYPT_MAX_TEXTSIZE )
return( CRYPT_ARGERROR_STR1 );
if( createInfo->strArgLen2 < 2 || \
createInfo->strArgLen2 > CRYPT_MAX_TEXTSIZE )
return( CRYPT_ARGERROR_STR2 );
/* We can't create another user object with the same name as the
cryptlib default user (actually we could and nothing bad would happen,
but we reserve the use of this name just in case) */
if( createInfo->strArgLen1 == defaultUserInfo.userNameLength && \
!strnicmp( createInfo->strArg1, defaultUserInfo.userName,
defaultUserInfo.userNameLength ) )
return( CRYPT_ERROR_INITED );
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/* Logging on with the primary SO default password triggers a zeroise,
normally we can only use this login after a zeroise but currently there's
no way for a user to trigger this so we perform it at the same time as
the login - the effect is the same, it just combines two operations in
one */
if( createInfo->strArgLen2 == PRIMARYSO_PASSWORD_LENGTH && \
( !memcmp( createInfo->strArg2, PRIMARYSO_PASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) || \
!memcmp( createInfo->strArg2, PRIMARYSO_ALTPASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) ) )
zeroiseUsers();
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/* Find the user information for the given user */
status = fileRef = findUserFileRef( USERID_NAME, createInfo->strArg1,
createInfo->strArgLen1 );
if( cryptStatusError( status ) )
{
/* If we get a special-case OK status, we're in the zeroised state
with no user info present, make sure the user is logging in with
the default SO password */
if( status == OK_SPECIAL )
status = ( createInfo->strArgLen2 == PRIMARYSO_PASSWORD_LENGTH && \
( !memcmp( createInfo->strArg2, PRIMARYSO_PASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) || \
!memcmp( createInfo->strArg2, PRIMARYSO_ALTPASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) ) ) ? \
CRYPT_OK : CRYPT_ERROR_WRONGKEY;
if( cryptStatusError( status ) )
return( status );
fileRef = -1; /* No user file present yet for primary SO */
/* We're logging in as the primary SO with the SO default password,
create the primary SO user object */
assert( createInfo->strArgLen1 == primarySOInfo.userNameLength && \
!memcmp( createInfo->strArg1, primarySOInfo.userName,
primarySOInfo.userNameLength ) );
assert( createInfo->strArgLen2 == PRIMARYSO_PASSWORD_LENGTH && \
( !memcmp( createInfo->strArg2, PRIMARYSO_PASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) || \
!memcmp( createInfo->strArg2, PRIMARYSO_ALTPASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) ) );
initStatus = openUser( &iCryptUser, createInfo->cryptOwner,
&primarySOInfo, &userInfoPtr );
}
else
{
USER_FILE_INFO userFileInfo;
/* We're in the non-zeroised state, no user can use the default SO
password */
if( createInfo->strArgLen2 == PRIMARYSO_PASSWORD_LENGTH && \
( !memcmp( createInfo->strArg2, PRIMARYSO_PASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) || \
!memcmp( createInfo->strArg2, PRIMARYSO_ALTPASSWORD,
PRIMARYSO_PASSWORD_LENGTH ) ) )
return( CRYPT_ERROR_WRONGKEY );
/* Read the user info from the user file and perform access
verification */
status = getCheckUserInfo( &userFileInfo, fileRef );
if( cryptStatusError( status ) )
return( status );
/* Pass the call on to the lower-level open function */
assert( createInfo->strArgLen1 == userFileInfo.userNameLength && \
!memcmp( createInfo->strArg1, userFileInfo.userName,
userFileInfo.userNameLength ) );
initStatus = openUser( &iCryptUser, createInfo->cryptOwner,
&userFileInfo, &userInfoPtr );
zeroise( &userFileInfo, sizeof( USER_FILE_INFO ) );
}
if( userInfoPtr == NULL )
return( initStatus ); /* Create object failed, return immediately */
if( cryptStatusError( initStatus ) )
/* The session open failed, make sure the object gets destroyed when
we notify the kernel that the setup process is complete */
krnlSendNotifier( iCryptUser, RESOURCE_IMESSAGE_DESTROY );
/* We've finished setting up the object-type-specific info, tell the
kernel the object is ready for use */
unlockResource( userInfoPtr );
status = krnlSendMessage( iCryptUser, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
return( cryptStatusError( initStatus ) ? initStatus : status );
/* If the user object has a corresponding user info file, read any
stored config options into the object. We have to do this after
it's initialised because the config data, coming from an external
(and therefore untrusted) source has to go through the kernel's
ACL checking */
if( fileRef >= 0 )
{
sprintf( userFileName, "u%06x", fileRef );
readConfig( iCryptUser, userFileName );
}
createInfo->cryptHandle = iCryptUser;
return( CRYPT_OK );
}
/* Create the default user object */
int createDefaultUserObject( void )
{
CRYPT_USER iUserObject;
USER_INFO *userInfoPtr;
int status;
/* Pass the call on to the lower-level open function. This user is
unique and has no owner or type */
status = openUser( &iUserObject, SYSTEM_OBJECT_HANDLE, &defaultUserInfo,
&userInfoPtr );
if( userInfoPtr == NULL )
return( status ); /* Create object failed, return immediately */
if( cryptStatusError( status ) )
{
/* The user create call failed, we'd normally have to signal the user
object to destroy itself when the init completes, however we don't
have the privileges to do this so we just pass the error code back
to the caller which causes the cryptlib init to fail */
unlockResource( userInfoPtr );
return( status );
}
assert( iUserObject == DEFAULTUSER_OBJECT_HANDLE );
/* We've finished setting up the object-type-specific info, tell the
kernel the object is ready for use */
unlockResource( userInfoPtr );
status = krnlSendMessage( iUserObject, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
if( cryptStatusError( status ) )
return( status );
/* Read any stored config options into the object. We have to do this
after it's initialised because the config data, coming from an
external (and therefore untrusted) source has to go through the
kernel's ACL checking */
readConfig( DEFAULTUSER_OBJECT_HANDLE, "cryptlib" );
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -