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

📄 user_attr.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						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 + -