📄 user_attr.c
字号:
/****************************************************************************
* *
* cryptlib User Attribute Routines *
* Copyright Peter Gutmann 1999-2007 *
* *
****************************************************************************/
#include <stdio.h> /* For snprintf_s() */
#include "crypt.h"
#ifdef INC_ALL
#include "trustmgr.h"
#include "user.h"
#else
#include "cert/trustmgr.h"
#include "misc/user.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Exit after setting extended error information */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int exitError( INOUT USER_INFO *userInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,
IN_ENUM( CRYPT_ERRTYPE ) const CRYPT_ERRTYPE_TYPE errorType,
IN_ERROR const int status )
{
assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
REQUIRES( isAttribute( errorLocus ) || \
isInternalAttribute( errorLocus ) );
REQUIRES( errorType > CRYPT_ERRTYPE_NONE && \
errorType < CRYPT_ERRTYPE_LAST );
REQUIRES( cryptStatusError( status ) );
setErrorInfo( userInfoPtr, errorLocus, errorType );
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int exitErrorInited( INOUT USER_INFO *userInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
REQUIRES( isAttribute( errorLocus ) || \
isInternalAttribute( errorLocus ) );
return( exitError( userInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
CRYPT_ERROR_INITED ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int exitErrorNotFound( INOUT USER_INFO *userInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
REQUIRES( isAttribute( errorLocus ) || \
isInternalAttribute( errorLocus ) );
return( exitError( userInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
CRYPT_ERROR_NOTFOUND ) );
}
/* Process a set-attribute operation that initiates an operation that's
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
that require this user object */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int twoPhaseConfigUpdate( INOUT USER_INFO *userInfoPtr,
IN_INT_Z const int value )
{
const CRYPT_USER iCryptUser = userInfoPtr->objectHandle;
char userFileName[ 16 + 8 ];
void *data;
int length, commitStatus, refCount, status;
assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
REQUIRES( value == FALSE );
/* The configuration option write is performed in two phases, a first
phase that encodes the configuration data and a second phase that
writes the data to disk */
if( userInfoPtr->userFileInfo.fileRef == CRYPT_UNUSED )
strlcpy_s( userFileName, 16, "cryptlib" );
else
{
sprintf_s( userFileName, 16, "u%06x",
userInfoPtr->userFileInfo.fileRef );
}
status = prepareConfigData( userInfoPtr->configOptions, userFileName,
userInfoPtr->trustInfoPtr, &data, &length );
if( status != OK_SPECIAL )
return( status );
/* If nothing in the configuration data has changed, we're done */
if( length <= 0 && !userInfoPtr->trustInfoChanged )
return( CRYPT_OK );
/* We've got the configuration data in a memory buffer, we can unlock
the user object to allow external access while we commit the in-
memory data to disk */
status = krnlSuspendObject( iCryptUser, &refCount );
ENSURES( cryptStatusOK( status ) );
commitStatus = commitConfigData( iCryptUser, userFileName, data, length );
clFree( "userMessageFunction", data );
status = krnlResumeObject( iCryptUser, refCount );
if( cryptStatusError( status ) )
{
/* Handling errors at this point is rather tricky because an error
response from krnlResumeObject() is a can't-occur condition. In
particular this will mean that we return to the kernel with the
user object released, which will cause it to throw an exception
due to the inconsistent object state. On the other hand we can
only get to this point because of an exception condition anyway
so it's just going to propagate the exception back */
retIntError();
}
if( cryptStatusOK( commitStatus ) )
userInfoPtr->trustInfoChanged = FALSE;
return( commitStatus );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int twoPhaseSelftest( INOUT USER_INFO *userInfoPtr,
IN_INT_Z const int value )
{
const CRYPT_USER iCryptUser = userInfoPtr->objectHandle;
int refCount, selfTestStatus, status;
assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
REQUIRES( value == TRUE );
/* It's a self-test, forward the message to the system object with
the user object unlocked, tell the system object to perform its self-
test, and then re-lock the user object and set the self-test result
value. Since the self-test configuration setting will be marked as
in-use at this point (to avoid having another thread update it while
the user object was unlocked) it can't be written to directly so we
have to update it via setOptionSpecial(). In addition since this is
now an action message we forward it as a MESSAGE_SELFTEST since the
CRYPT_OPTION_SELFTESTOK attribute only applies to the user object.
An alternative way to handle this would be implement an advisory-
locking mechanism for configuration options, but this adds a great
deal of complexity just to handle this one single case so until
there's a wider need for general-purpose configuration option locking
the current approach will do */
status = krnlSuspendObject( iCryptUser, &refCount );
ENSURES( cryptStatusOK( status ) );
selfTestStatus = krnlSendNotifier( SYSTEM_OBJECT_HANDLE,
IMESSAGE_SELFTEST );
status = krnlResumeObject( iCryptUser, refCount );
/* See comment above on krnlResumeObject() error handling */
if( cryptStatusError( status ) )
return( status );
return( setOptionSpecial( userInfoPtr->configOptions,
CRYPT_OPTION_SELFTESTOK,
cryptStatusOK( selfTestStatus ) ? \
TRUE : FALSE ) );
}
/****************************************************************************
* *
* Get Attributes *
* *
****************************************************************************/
/* Get a numeric/boolean attribute */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int getUserAttribute( INOUT USER_INFO *userInfoPtr,
OUT_INT_Z int *valuePtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
{
int status;
assert( isWritePtr( userInfoPtr, sizeof( USER_INFO ) ) );
assert( isWritePtr( valuePtr, sizeof( int ) ) );
REQUIRES( isAttribute( attribute ) || \
isInternalAttribute( attribute ) );
/* Clear return value */
*valuePtr = 0;
switch( attribute )
{
case CRYPT_USERINFO_CAKEY_CERTSIGN:
case CRYPT_USERINFO_CAKEY_CRLSIGN:
case CRYPT_USERINFO_CAKEY_OCSPSIGN:
{
CRYPT_CERTIFICATE caCert;
/* Make sure that the key type that we're after is present in
the object */
if( userInfoPtr->iCryptContext == CRYPT_UNUSED )
return( exitErrorNotFound( userInfoPtr, attribute ) );
/* Since the CA signing key tied to the user object is meant to
be used only through cryptlib-internal means we shouldn't
really be returning it to the caller. We can return the
ssociated CA cert, but this may be an internal-only object
that the caller can't do anything with. To avoid this
problem we isolate the cert by returning a copy of the
associated certificate object */
status = krnlSendMessage( userInfoPtr->iCryptContext,
IMESSAGE_GETATTRIBUTE, &caCert,
CRYPT_IATTRIBUTE_CERTCOPY );
if( cryptStatusOK( status ) )
*valuePtr = caCert;
return( status );
}
case CRYPT_IATTRIBUTE_CTL:
{
MESSAGE_CREATEOBJECT_INFO createInfo;
/* Check whether there are trusted certs present */
status = enumTrustedCerts( userInfoPtr->trustInfoPtr,
CRYPT_UNUSED, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
/* Create a cert chain meta-object to hold the overall set of
certs */
setMessageCreateObjectInfo( &createInfo,
CRYPT_CERTTYPE_CERTCHAIN );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -