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

📄 dev_pk11.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	if( sBufPtr != sBuffer )
		free( sBufPtr );
	if( iAndSBufPtr != iAndSBuffer )
		free( iAndSBufPtr );
	if( certBufPtr != certBuffer )
		free( certBufPtr );
	return( cryptStatus );
	}

/****************************************************************************
*																			*
*					Device Init/Shutdown/Device Control Routines			*
*																			*
****************************************************************************/

/* Prototypes for functions to get and free device capability information */

static void freeCapabilities( DEVICE_INFO *deviceInfo );
static int getCapabilities( DEVICE_INFO *deviceInfo );

/* Prototypes for device-specific functions */

static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
							  const int length );

/* Close a previously-opened session with the device.  We have to have this
   before the init function since it may be called by it if the init process
   fails */

static void shutdownFunction( DEVICE_INFO *deviceInfo )
	{
	/* Log out and close the session with the device */
	if( deviceInfo->flags & DEVICE_LOGGEDIN )
		C_Logout( deviceInfo->deviceHandle );
	C_CloseSession( deviceInfo->deviceHandle );
	deviceInfo->deviceHandle = CRYPT_ERROR;
	deviceInfo->flags &= ~( DEVICE_ACTIVE | DEVICE_LOGGEDIN );

	/* Free the device capability information */
	freeCapabilities( deviceInfo );
	}

/* Open a session with the device */

static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
						 const int nameLength )
	{
	CK_SESSION_HANDLE hSession;
	CK_SLOT_ID slotList[ MAX_PKCS11_SLOTS ];
	CK_ULONG slotCount = MAX_PKCS11_SLOTS;
	CK_TOKEN_INFO tokenInfo;
	CK_RV status;
	int tokenSlot = DEFAULT_SLOT, i, cryptStatus;

	/* Get information on all available slots */
	memset( slotList, 0, sizeof( slotList ) );
	status = C_GetSlotList( TRUE, slotList, &slotCount );
	if( status != CKR_OK )
		return( mapError( deviceInfo, status, CRYPT_ERROR_OPEN ) );
	if( !slotCount )	/* Can happen in some circumstances */
		return( CRYPT_ERROR_OPEN );

	/* Check whether a token name (used to select the slot) has been 
	   specified */
	for( i = 1; i < nameLength - 1; i++ )
		if( name[ i ] == ':' && name[ i + 1 ] == ':' )
			{
			const void *tokenName = name + i + 2;	/* Skip '::' */
			const int tokenNameLength = nameLength - ( i + 2 );

			if( tokenNameLength <= 0 )
				return( CRYPT_ARGERROR_STR1 );

			/* Check each slot for a token matching the given name */
			for( tokenSlot = 0; tokenSlot < slotCount; tokenSlot++ )
				{
				status = C_GetTokenInfo( slotList[ tokenSlot ], &tokenInfo );
				if( status == CKR_OK && \
					!strnicmp( tokenName, tokenInfo.label, tokenNameLength ) )
					break;
				};
			if( tokenSlot == slotCount )
				return( CRYPT_ERROR_NOTFOUND );
			}
	deviceInfo->slotHandle = slotList[ tokenSlot ];

	/* Get information on device-specific capabilities */
	status = C_GetTokenInfo( deviceInfo->slotHandle, &tokenInfo );
	if( status != CKR_OK )
		{
		shutdownFunction( deviceInfo );
		return( mapError( deviceInfo, status, CRYPT_ERROR_OPEN ) );
		}
	if( tokenInfo.flags & CKF_RNG )
		/* The device has an onboard RNG we can use */
		deviceInfo->getRandomFunction = getRandomFunction;
	if( tokenInfo.flags & CKF_WRITE_PROTECTED )
		/* The device can't have data on it changed */
		deviceInfo->flags |= DEVICE_READONLY;
	if( tokenInfo.flags & CKF_LOGIN_REQUIRED )
		/* The user needs to log in before using various device functions */
		deviceInfo->flags |= DEVICE_NEEDSLOGIN;
	if( ( deviceInfo->minPinSize = ( int ) tokenInfo.ulMinPinLen ) < 4 )
		/* Some devices report silly PIN sizes */
		deviceInfo->minPinSize = 4;
	if( ( deviceInfo->maxPinSize = ( int ) tokenInfo.ulMaxPinLen ) < 4 )
		/* Some devices report silly PIN sizes (setting this to ULONG_MAX or
		   4GB, which becomes -1 as an int, counts as silly).  Since we can't
		   differentiate between 0xFFFFFFFF = bogus value and 0xFFFFFFFF = 
		   ULONG_MAX we play it safe and set the limit to 8 bytes, which most
		   devices should be able to handle */
		deviceInfo->maxPinSize = 8;
	memcpy( deviceInfo->label, tokenInfo.label, 32 );
	for( i = 32;
		 i && ( deviceInfo->label[ i - 1 ] == ' ' || \
				!deviceInfo->label[ i - 1 ] ); i-- );
	deviceInfo->label[ i ] = '\0';

	/* Open a session with the device in the first slot.  This gets a bit
	   awkward because we can't tell whether a R/W session is OK without
	   opening a session, but we can't open a session unless we know whether
	   a R/W session is OK, so first we try for a RW session and if that
	   fails we go for a read-only session */
	status = C_OpenSession( deviceInfo->slotHandle, 
							CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL_PTR, 
							NULL_PTR, &hSession );
	if( status == CKR_TOKEN_WRITE_PROTECTED )
		status = C_OpenSession( deviceInfo->slotHandle, 
								CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, 
								&hSession );
	if( status != CKR_OK )
		{
		cryptStatus = mapError( deviceInfo, status, CRYPT_ERROR_OPEN );
		if( cryptStatus == CRYPT_ERROR_OPEN && \
			!( tokenInfo.flags & CKF_USER_PIN_INITIALIZED ) )
			/* We couldn't do much with the error code, it could be that the
			   token hasn't been initialised yet but unfortunately PKCS #11 
			   doesn't define an error code for this condition.  In addition
			   many tokens will allow a session to be opened and then fail 
			   with a "PIN not set" error at a later point (which allows for
			   more accurate error reporting), however a small number won't
			   allow a session to be opened and return some odd-looking error
			   because there's nothing useful available.  The best way to
			   report this in a meaningful manner to the caller is to check
			   whether the user PIN has been initialised, if it hasn't then 
			   it's likely that the token as a whole hasn't been initialised 
			   so we return a not initialised error */
			cryptStatus = CRYPT_ERROR_NOTINITED;
		return( cryptStatus );
		}
	deviceInfo->deviceHandle = hSession;
	deviceInfo->flags |= DEVICE_ACTIVE;

	/* Set up the capability information for this device */
	cryptStatus = getCapabilities( deviceInfo );
	if( cryptStatusError( cryptStatus ) )
		{
		shutdownFunction( deviceInfo );
		return( ( cryptStatus == CRYPT_ERROR ) ? \
				CRYPT_ERROR_OPEN : ( int ) cryptStatus );
		}

	return( CRYPT_OK );
	}

/* Handle device control functions */

static int controlFunction( DEVICE_INFO *deviceInfo,
							const CRYPT_ATTRIBUTE_TYPE type,
							const void *data1, const int data1Length,
							const void *data2, const int data2Length )
	{
	CK_RV status;

	/* Handle user authorisation */
	if( type == CRYPT_DEVINFO_AUTHENT_USER || \
		type == CRYPT_DEVINFO_AUTHENT_SUPERVISOR )
		{
		/* If the user is already logged in, log them out before we try
		   logging in with a new authentication value */
		if( deviceInfo->flags & DEVICE_LOGGEDIN )
			{
			C_Logout( deviceInfo->deviceHandle );
			deviceInfo->flags &= ~DEVICE_LOGGEDIN;
			}

		/* Authenticate the user to the device */
		status = C_Login( deviceInfo->deviceHandle,
						  ( type == CRYPT_DEVINFO_AUTHENT_USER ) ? \
						  CKU_USER : CKU_SO, ( CK_CHAR_PTR ) data1,
						  ( CK_ULONG ) data1Length );
		if( status == CKR_OK || status == CKR_USER_ALREADY_LOGGED_IN )
			deviceInfo->flags |= DEVICE_LOGGEDIN;
		return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
		}

	/* Handle authorisation value change */
	if( type == CRYPT_DEVINFO_SET_AUTHENT_USER || \
		type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR )
		{
		status = C_SetPIN( deviceInfo->deviceHandle, ( CK_CHAR_PTR ) data1,
						   ( CK_ULONG ) data1Length, ( CK_CHAR_PTR ) data2,
						   ( CK_ULONG ) data2Length );
		return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
		}

	/* Handle initialisation and zeroisation */
	if( type == CRYPT_DEVINFO_INITIALISE || \
		type == CRYPT_DEVINFO_ZEROISE )
		{
		CK_SESSION_HANDLE hSession;
		CK_CHAR label[ 32 ];

		/* If there's a session active with the device, log out and terminate
		   the session, since the token init will reset this */
		if( deviceInfo->deviceHandle != CRYPT_ERROR )
			{
			C_Logout( deviceInfo->deviceHandle );
			C_CloseSession( deviceInfo->deviceHandle );
			}
		deviceInfo->deviceHandle = CRYPT_ERROR;

		/* Initialise/clear the device */
		memset( label, ' ', 32 );
		status = C_InitToken( deviceInfo->slotHandle, 
							  ( CK_CHAR_PTR ) data1,
							  ( CK_ULONG ) data1Length, label );
		if( status != CKR_OK )
			return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );

		/* Reopen the session with the device */
		status = C_OpenSession( deviceInfo->slotHandle,
								CKF_RW_SESSION | CKF_SERIAL_SESSION,
								NULL_PTR, NULL_PTR, &hSession );
		if( status != CKR_OK )
			return( mapError( deviceInfo, status, CRYPT_ERROR_OPEN ) );
		deviceInfo->deviceHandle = hSession;

		/* If it's a straight zeroise, we're done */
		if( type == CRYPT_DEVINFO_ZEROISE )
			return( CRYPT_OK );

		/* We're initialising it, log in as supervisor and set the initial 
		   user PIN to the same as the SSO PIN.  We do this because the init
		   user PIN functionality is a bit of an oddball function which has
		   to fill the gap between C_InitToken() (which sets the SSO PIN) and
		   C_SetPIN() (which can only set the SSO PIN for the SSO or the user 
		   PIN for the user).  Setting the user PIN by the SSO, which is 
		   usually required to perform any useful (non-administrative) 
		   function with the token, requires the special-case C_InitPIN().
		   Since the token will initially be used by the SSO we set it to the 
		   same as the SSO PIN and rely on the user to change it before they
		   hand it over to the user.  In most cases the user *is* the SSO, so
		   this ensures the device behaves as expected when the user isn't 
		   even aware that there are SSO and user roles.
		   
		   A useful side-effect of this is that it eliminates problems with
		   some devices which behave somewhat strangely if the SSO PIN is set
		   but the user PIN isn't */
		status = C_Login( deviceInfo->deviceHandle, CKU_SO,
						  ( CK_CHAR_PTR ) data1, ( CK_ULONG ) data1Length );
		if( status == CKR_OK )
			status = C_InitPIN( deviceInfo->deviceHandle, 
								( CK_CHAR_PTR ) data1, 
								( CK_ULONG ) data1Length );
		if( status != CKR_OK )
			{
			C_Logout( deviceInfo->deviceHandle );
			C_CloseSession( deviceInfo->deviceHandle );
			deviceInfo->deviceHandle = CRYPT_ERROR;
			return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
			}

		/* We're logged in and ready to go */
		deviceInfo->flags |= DEVICE_LOGGEDIN;
		return( CRYPT_OK );
		}

	assert( NOTREACHED );
	return( CRYPT_ERROR_NOTAVAIL );	/* Get rid of compiler warning */
	}

/****************************************************************************
*																			*
*						 	Misc.Device Interface Routines					*
*																			*
****************************************************************************/

/* Get random data from the device */

static int getRandomFunction( DEVICE_INFO *deviceInfo, void *buffer,
							  const int length )
	{
	CK_RV status;

	status = C_GenerateRandom( deviceInfo->deviceHandle, buffer, length );
	return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
	}

/* Get the label for an object */

static int getObjectLabel( DEVICE_INFO *deviceInfo, 
						   const CK_OBJECT_HANDLE hObject, 
						   char *label, int *labelLength )
	{
	CK_ATTRIBUTE keyLabelTemplate = \
		{ CKA_LABEL, NULL_PTR, 0 };
	CK_RV status;
	char labelBuffer[ CRYPT_MAX_TEXTSIZE ], *labelPtr = labelBuffer;

	status = C_GetAttributeValue( deviceInfo->deviceHandle, hObject,
								  &keyLabelTemplate, 1 );
	if( status == CKR_OK )
		{
		if( keyLabelTemplate.ulValueLen > CRYPT_MAX_TEXTSIZE && \
			( labelPtr = malloc( ( size_t ) \
							( keyLabelTemplate.ulValueLen ) ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		keyLabelTemplate.pValue = labelPtr;
		status = C_GetAttributeValue( deviceInfo->deviceHandle, hObject,
									  &keyLabelTemplate, 1 );
		}
	if( status != CKR_OK )
		{
		*labelLength = 0;
		if( label != NULL )
			label[ 0 ] = '\0';
		}
	else
		{
		*labelLength = min( keyLabelTemplate.ulValueLen, CRYPT_MAX_TEXTSIZE );
		if( label != NULL )
			memcpy( label, labelPtr, *labelLength );
		}
	if( labelPtr != labelBuffer )
		free( labelPtr );
	return( mapError( deviceInfo, status, CRYPT_ERROR_FAILED ) );
	}

⌨️ 快捷键说明

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