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

📄 pkcs11_rw.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*					cryptlib PKCS #11 Item Read/Write Routines				*
*						Copyright Peter Gutmann 1998-2007					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "context.h"
  #include "device.h"
  #include "pkcs11_api.h"
  #include "asn1.h"
#else
  #include "crypt.h"
  #include "context/context.h"
  #include "device/device.h"
  #include "device/pkcs11_api.h"
  #include "misc/asn1.h"
#endif /* Compiler-specific includes */

#ifdef USE_PKCS11

/****************************************************************************
*																			*
*						 		Utility Routines							*
*																			*
****************************************************************************/

/* Convert a time_t to a PKCS #11 CK_DATE */

static void convertDate( CK_DATE *date, const time_t theTime )
	{
	STREAM stream;
	BYTE dateBuffer[ 32 + 8 ];

	assert( isWritePtr( date, sizeof( CK_DATE ) ) );

	/* Clear return value */
	memset( date, 0, sizeof( CK_DATE ) );

	/* Convert the time_t value to an ASN.1 time string that we can use to
	   populate the CK_DATE fields, which are stored as ASCII text strings */
	sMemOpen( &stream, dateBuffer, 32 );
	writeGeneralizedTime( &stream, theTime, DEFAULT_TAG );
	sMemDisconnect( &stream );
	memcpy( &date->year, dateBuffer + 2, 4 );
	memcpy( &date->month, dateBuffer + 6, 2 );
	memcpy( &date->day, dateBuffer + 8, 2 );
	}

/* Get the label for an object.  We can't use a dynBuf for this because it's 
   a PKCS #11 attribute rather than a cryptlib attribute */

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

	assert( isReadPtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
	assert( isWritePtr( label, maxLabelSize ) );
	assert( isWritePtr( labelLength, sizeof( int ) ) );

	status = C_GetAttributeValue( pkcs11Info->hSession, hObject,
								  &keyLabelTemplate, 1 );
	if( status == CKR_OK )
		{
		if( keyLabelTemplate.ulValueLen > CRYPT_MAX_TEXTSIZE && \
			( labelPtr = clAlloc( "getObjectLabel", \
					( size_t ) ( keyLabelTemplate.ulValueLen ) ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		keyLabelTemplate.pValue = labelPtr;
		status = C_GetAttributeValue( pkcs11Info->hSession, hObject,
									  &keyLabelTemplate, 1 );
		}
	if( status != CKR_OK )
		{
		*labelLength = 0;
		if( label != NULL )
			label[ 0 ] = '\0';
		}
	else
		{
		*labelLength = min( keyLabelTemplate.ulValueLen, maxLabelSize );
		if( label != NULL )
			memcpy( label, labelPtr, *labelLength );
		}
	if( labelPtr != labelBuffer )
		clFree( "getObjectLabel", labelPtr );
	return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_FAILED ) );
	}

/* Read a flag for an object.  An absent value is treated as FALSE */

static BOOLEAN readFlag( const PKCS11_INFO *pkcs11Info, 
						 const CK_OBJECT_HANDLE hObject,
						 const CK_ATTRIBUTE_TYPE flagType )
	{
	CK_BBOOL bFlag = FALSE;
	CK_ATTRIBUTE flagTemplate = { flagType, &bFlag, sizeof( CK_BBOOL ) };

	assert( isReadPtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );

	/* Some buggy implementations return CKR_OK but forget to set the
	   data value in the template (!!!) so we have to initialise bFlag
	   to a default of FALSE to handle this */
	return( ( C_GetAttributeValue( pkcs11Info->hSession, hObject,
								   &flagTemplate, 1 ) == CKR_OK && bFlag ) ? \
			TRUE : FALSE );
	}

/* Get the permitted-action flags for an object */

static int getActionFlags( PKCS11_INFO *pkcs11Info,
						   const CK_OBJECT_HANDLE hObject,
						   const KEYMGMT_ITEM_TYPE itemType,
						   const CRYPT_ALGO_TYPE cryptAlgo )
	{
	const BOOLEAN checkSign = ( isSigAlgo( cryptAlgo ) || \
								( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
								  cryptAlgo <= CRYPT_ALGO_LAST_MAC ) ) ? \
							  TRUE : FALSE;
	const BOOLEAN checkCrypt = ( isCryptAlgo( cryptAlgo ) || \
								 ( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
								   cryptAlgo < CRYPT_ALGO_LAST_CONVENTIONAL ) ) ? \
							  TRUE : FALSE;
	const BOOLEAN checkWrap = isCryptAlgo( cryptAlgo );
	BOOLEAN cryptAllowed = FALSE, sigAllowed = FALSE;
	int actionFlags = 0;

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
	assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
			itemType == KEYMGMT_ITEM_PRIVATEKEY || \
			itemType == KEYMGMT_ITEM_SECRETKEY );
	assert( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
			cryptAlgo <= CRYPT_ALGO_LAST_MAC ); 

	/* Get the permitted actions for the object.  Some devices report bogus 
	   capabilities (for example encrypt for a MAC object) so we restrict 
	   the actions that we check for to try and weed out false positives.  
	   The kernel won't allow the setting of an invalid action anyway, but 
	   it's better to be safe here.
	   
	   We also have to provide special translation for the sign and sig-
	   check action flags, PKCS #11 treats the MAC operation as a member
	   of the signature family while cryptlib treats it as a member of the
	   hash family so if we get a sign/sigcheck permitted action for a MAC 
	   object we map it to a hash permitted action */
	if( ( checkCrypt && readFlag( pkcs11Info, hObject, CKA_ENCRYPT ) ) || \
		( checkWrap && readFlag( pkcs11Info, hObject, CKA_WRAP ) ) )
		{
		actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_ALL );
		cryptAllowed = TRUE;
		}
	if( ( checkCrypt && itemType != KEYMGMT_ITEM_PUBLICKEY && \
		  readFlag( pkcs11Info, hObject, CKA_DECRYPT ) ) || \
		( checkWrap && itemType == KEYMGMT_ITEM_PRIVATEKEY && \
		  readFlag( pkcs11Info, hObject, CKA_UNWRAP ) ) )
		{
		actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_ALL );
		cryptAllowed = TRUE;
		}
	if( checkSign && itemType != KEYMGMT_ITEM_PUBLICKEY && \
		readFlag( pkcs11Info, hObject, CKA_SIGN ) )
		{
		if( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
			cryptAlgo <= CRYPT_ALGO_LAST_MAC )
			actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_HASH, ACTION_PERM_ALL );
		else
			actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_ALL );
		sigAllowed = TRUE;
		}
	if( checkSign && readFlag( pkcs11Info, hObject, CKA_VERIFY ) )
		{
		if( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
			cryptAlgo <= CRYPT_ALGO_LAST_MAC )
			actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_HASH, ACTION_PERM_ALL );
		else
			actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_ALL );
		sigAllowed = TRUE;
		}
	if( cryptAlgo == CRYPT_ALGO_RSA )
		{
		/* If there are any restrictions on the key usage, we have to make it
		   internal-only because of RSA's signature/encryption duality */
		if( !( cryptAllowed && sigAllowed ) )
			actionFlags = MK_ACTION_PERM_NONE_EXTERNAL( actionFlags );
		}
	else
		if( isDlpAlgo( cryptAlgo ) )
			{
			/* Because of the special-case data formatting requirements for 
			   DLP algorithms, we make the usage internal-only */
			actionFlags = MK_ACTION_PERM_NONE_EXTERNAL( actionFlags );
			}

	return( actionFlags );
	}

/* Get cryptlib algorithm and capability info for a PKCS #11 object */

static int getMechanismInfo( const PKCS11_INFO *pkcs11Info, 
							 const CK_OBJECT_HANDLE hObject,
							 const void *capabilityInfoList, 
							 const BOOLEAN isPKC,
							 const CAPABILITY_INFO **capabilityInfoPtrPtr,
							 CRYPT_ALGO_TYPE *cryptAlgo )
	{
	CK_KEY_TYPE keyType;
	CK_ATTRIBUTE keyTypeTemplate = \
		{ CKA_KEY_TYPE, ( CK_VOID_PTR ) &keyType, sizeof( CK_KEY_TYPE ) };
	CK_RV status;
	const CAPABILITY_INFO *capabilityInfoPtr;
	const PKCS11_MECHANISM_INFO *mechanismInfoPtr;
	int mechanismInfoSize, i;

	assert( isReadPtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
	assert( capabilityInfoList != NULL );
	assert( isReadPtr( capabilityInfoPtrPtr, sizeof( CAPABILITY_INFO ) ) );
	assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );

	/* Clear return values */
	*capabilityInfoPtrPtr = NULL;
	*cryptAlgo = CRYPT_ALGO_NONE;

	/* Get the key type (equivalent to the cryptlib algoID) for this 
	   object */
	status = C_GetAttributeValue( pkcs11Info->hSession, hObject, 
								  &keyTypeTemplate, 1 );
	if( status != CKR_OK )
		{
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_FAILED );
		}

	/* Hack for PKCS #11's broken HMAC "support", PKCS #11 has no HMAC 
	   object types so if we find a generic secret key object we assume that 
	   it's an HMAC-SHA1 object, the most common type */
	if( keyType == CKK_GENERIC_SECRET )
		{
		*cryptAlgo = CRYPT_ALGO_HMAC_SHA1;
		capabilityInfoPtr = findCapabilityInfo( capabilityInfoList, 
												*cryptAlgo );
		if( capabilityInfoPtr == NULL )
			return( CRYPT_ERROR_NOTAVAIL );
		*capabilityInfoPtrPtr = capabilityInfoPtr;

		return( CRYPT_OK );
		}

	/* Get the equivalent cryptlib algorithm type and use that to get the
	   capability info for the algorithm */
	if( isPKC )
		mechanismInfoPtr = getMechanismInfoPKC( &mechanismInfoSize );
	else
		mechanismInfoPtr = getMechanismInfoConv( &mechanismInfoSize );
	for( i = 0; mechanismInfoPtr[ i ].keyType != keyType && \
				i < mechanismInfoSize; i++ );
	if( i >= mechanismInfoSize )
		retIntError();
	mechanismInfoPtr = &mechanismInfoPtr[ i ];
	*cryptAlgo = mechanismInfoPtr->cryptAlgo;
	capabilityInfoPtr = findCapabilityInfo( capabilityInfoList, *cryptAlgo );
	if( capabilityInfoPtr == NULL )
		return( CRYPT_ERROR_NOTAVAIL );
	*capabilityInfoPtrPtr = capabilityInfoPtr;
	
	return( CRYPT_OK );
	}

/* Add the components of an issuerAndSerialnumber to a certificate 
   template */

static int addIAndSToTemplate( CK_ATTRIBUTE *certTemplate, 
							   const void *iAndSPtr, const int iAndSLength, 
							   DYNBUF *iAndSDB, 
							   const CRYPT_HANDLE iCryptHandle )
	{
	STREAM stream;
	void *dataPtr = DUMMY_INIT_PTR;
	int length, cryptStatus;

	assert( isWritePtr( certTemplate, sizeof( CK_ATTRIBUTE ) * 2 ) );
	assert( ( iAndSPtr == NULL && iAndSLength == 0 && \
			  isWritePtr( iAndSDB, sizeof( DYNBUF ) ) && \
			  isHandleRangeValid( iCryptHandle ) ) || \
			( isReadPtr( iAndSPtr, iAndSLength ) && \
			  iAndSDB == NULL && iCryptHandle == CRYPT_UNUSED ) );

	/* Get the issuerAndSerialNumber from the certificate if necessary */
	if( iAndSDB != NULL )
		{
		cryptStatus = dynCreate( iAndSDB, iCryptHandle, 
								 CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
		if( cryptStatusError( cryptStatus ) )
			return( cryptStatus );
		}

	/* Parse the data and add it to the template */
	if( iAndSDB != NULL )
		sMemConnect( &stream, dynData( *iAndSDB ), dynLength( *iAndSDB ) );
	else
		sMemConnect( &stream, iAndSPtr, iAndSLength );
	readSequence( &stream, NULL );
	cryptStatus = getStreamObjectLength( &stream, &length );
	if( cryptStatusOK( cryptStatus ) )		/* Issuer DN */
		{
		certTemplate->ulValueLen = length;
		cryptStatus = sMemGetDataBlock( &stream, &dataPtr, length );
		}
	if( cryptStatusOK( cryptStatus ) )
		{
		certTemplate->pValue = dataPtr;
		cryptStatus = sSkip( &stream, length );
		}
	if( cryptStatusOK( cryptStatus ) )
		{
		certTemplate;	/* Move on to next entry */
		cryptStatus = getStreamObjectLength( &stream, &length );
		}
	if( cryptStatusOK( cryptStatus ) )		/* Serial number */
		{
		certTemplate->ulValueLen = length;
		cryptStatus = sMemGetDataBlock( &stream, &dataPtr, length );
		}
	if( cryptStatusOK( cryptStatus ) )
		{
		certTemplate->pValue = dataPtr;
		cryptStatus = sSkip( &stream, length );
		}
	sMemDisconnect( &stream );
	if( cryptStatusError( cryptStatus ) )
		{
		assert( DEBUG_WARN );
		if( iAndSDB != NULL )
			dynDestroy( iAndSDB );
		return( cryptStatus );
		}

⌨️ 快捷键说明

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