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

📄 pkcs11.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
	CK_RV status;

	status = C_FindObjectsInit( pkcs11Info->hSession,
								( CK_ATTRIBUTE_PTR ) objectTemplate,
								templateCount );
	if( status == CKR_OK )
		{
		status = C_FindObjects( pkcs11Info->hSession, hObjectArray, 
								2, &ulObjectCount );
		if( C_FindObjectsFinal != NULL )
			C_FindObjectsFinal( pkcs11Info->hSession );
		}
	if( status != CKR_OK )
		return( mapError( pkcs11Info, status, CRYPT_ERROR_NOTFOUND ) );
	if( ulObjectCount <= 0 )
		return( CRYPT_ERROR_NOTFOUND );
	if( ulObjectCount > 1 && onlyOne )
		return( CRYPT_ERROR_DUPLICATE );
	if( hObject != NULL )
		*hObject = hObjectArray[ 0 ];

	return( CRYPT_OK );
	}

static int findObject( PKCS11_INFO *pkcs11Info, CK_OBJECT_HANDLE *hObject,
					   const CK_ATTRIBUTE *objectTemplate,
					   const CK_ULONG templateCount )
	{
	return( findDeviceObjects( pkcs11Info, hObject, 
							   objectTemplate, templateCount, TRUE ) );
	}

static int findObjectEx( PKCS11_INFO *pkcs11Info, CK_OBJECT_HANDLE *hObject,
						 const CK_ATTRIBUTE *objectTemplate,
						 const CK_ULONG templateCount )
	{
	return( findDeviceObjects( pkcs11Info, hObject, 
							   objectTemplate, templateCount, FALSE ) );
	}

/* Set up certificate information and load it into the device */

static int updateCertificate( PKCS11_INFO *pkcs11Info, 
							  const CRYPT_HANDLE iCryptHandle,
							  const BOOLEAN isLeafCert )
	{
	static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
	static const CK_OBJECT_CLASS privkeyClass = CKO_PRIVATE_KEY;
	static const CK_OBJECT_CLASS pubkeyClass = CKO_PUBLIC_KEY;
	static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
	static const CK_BBOOL bTrue = TRUE;
	CK_ATTRIBUTE certTemplate[] = {
		{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
		{ CKA_CERTIFICATE_TYPE, ( CK_VOID_PTR ) &certType, sizeof( CK_CERTIFICATE_TYPE ) },
		{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
		{ CKA_ID, NULL_PTR, 0 },
		{ CKA_SUBJECT, NULL_PTR, 0 },
		{ CKA_ISSUER, NULL_PTR, 0 },
		{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
		{ CKA_VALUE, NULL_PTR, 0 },
		};
	CK_ATTRIBUTE keyTemplate[] = {
		{ CKA_CLASS, ( CK_VOID_PTR ) &privkeyClass, sizeof( CK_OBJECT_CLASS ) },
		{ CKA_ID, NULL_PTR, 0 }
		};
	CK_OBJECT_HANDLE hObject;
	CK_RV status;
	RESOURCE_DATA msgData;
	STREAM stream;
	DYNBUF subjectDB, iAndSDB, certDB;
	BYTE keyID[ CRYPT_MAX_HASHSIZE ];
	int length, cryptStatus;

	/* Get the keyID from the cert */
	setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_IATTRIBUTE_KEYID );
	if( cryptStatusError( cryptStatus ) )
		return( CRYPT_ARGERROR_NUM1 );
	certTemplate[ 3 ].pValue = msgData.data;
	certTemplate[ 3 ].ulValueLen = msgData.length;

	/* If it's a leaf cert, use the keyID to locate the corresponding public 
	   or private key object.  This is used as a check to ensure that the 
	   certificate corresponds to a key in the device.  In theory this would 
	   allow us to read the label from the key so that we can reuse it for 
	   the cert, but there doesn't seem to be any good reason for this and 
	   it could lead to problems with multiple certs with the same labels so 
	   we don't do it */
	if( isLeafCert )
		{
		keyTemplate[ 1 ].pValue = certTemplate[ 3 ].pValue;
		keyTemplate[ 1 ].ulValueLen = certTemplate[ 3 ].ulValueLen;
		cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
		if( cryptStatusError( cryptStatus ) )
			{
			/* Couldn't find a private key with this ID, try for a public key */
			keyTemplate[ 0 ].pValue = ( CK_VOID_PTR ) &pubkeyClass;
			cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
			}
		if( cryptStatusError( cryptStatus ) )
			return( CRYPT_ARGERROR_NUM1 );
		}

	/* Get the subjectName from the cert */
	cryptStatus = dynCreate( &subjectDB, iCryptHandle, 
							 CRYPT_IATTRIBUTE_SUBJECT );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	certTemplate[ 4 ].pValue = dynData( subjectDB );
	certTemplate[ 4 ].ulValueLen = dynLength( subjectDB );

	/* Get the issuerAndSerialNumber from the cert */
	cryptStatus = dynCreate( &iAndSDB, iCryptHandle, 
							 CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
	if( cryptStatusError( cryptStatus ) )
		{
		dynDestroy( &subjectDB );
		return( cryptStatus );
		}
	sMemConnect( &stream, dynData( iAndSDB ), dynLength( iAndSDB ) );
	readSequence( &stream, NULL );
	certTemplate[ 5 ].pValue = sMemBufPtr( &stream );
	readSequence( &stream, &length );		/* Issuer DN */
	certTemplate[ 5 ].ulValueLen = ( int ) sizeofObject( length );
	sSkip( &stream, length );
	certTemplate[ 6 ].pValue = sMemBufPtr( &stream );
	readGenericHole( &stream, &length, BER_INTEGER );/* Serial number */
	certTemplate[ 6 ].ulValueLen = ( int ) sizeofObject( length );
	assert( sStatusOK( &stream ) );
	sMemDisconnect( &stream );

	/* Get the certificate data */
	cryptStatus = dynCreate( &certDB, iCryptHandle, 
							 CRYPT_CERTFORMAT_CERTIFICATE );
	if( cryptStatusError( cryptStatus ) )
		{
		dynDestroy( &subjectDB );
		dynDestroy( &iAndSDB );
		return( cryptStatus );
		}
	certTemplate[ 7 ].pValue = dynData( certDB );
	certTemplate[ 7 ].ulValueLen = dynLength( certDB );

	/* We've finally got everything available, try and update the device with
	   the certificate data.  In theory we should also set CKA_PRIVATE = FALSE
	   but the Dallas iButton driver doesn't allow this so we have to rely on
	   drivers doing the right thing with the default setting */
	status = C_CreateObject( pkcs11Info->hSession,
							 ( CK_ATTRIBUTE_PTR ) certTemplate, 8, 
							 &hObject );
	if( status != CKR_OK )
		cryptStatus = mapError( pkcs11Info, status, CRYPT_ERROR_FAILED );

	/* Clean up */
	dynDestroy( &subjectDB );
	dynDestroy( &iAndSDB );
	dynDestroy( &certDB );
	return( cryptStatus );
	}

/* Update a device using the certs in a cert chain */

static int updateCertChain( PKCS11_INFO *pkcs11Info, 
							const CRYPT_CERTIFICATE iCryptCert )
	{
	static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
	static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
	CK_ATTRIBUTE certTemplate[] = {
		{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
		{ CKA_CERTIFICATE_TYPE, ( CK_VOID_PTR ) &certType, sizeof( CK_CERTIFICATE_TYPE ) },
		{ CKA_ISSUER, NULL_PTR, 0 },
		{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
		};
	BOOLEAN isLeafCert = TRUE, seenNonDuplicate = FALSE;
	int value, cryptStatus;

	/* If we've been passed a standalone cert, check whether it's implicitly
	   trusted, which allows to be added without the presence of a 
	   corresponding public/private key in the device */
	cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE, &value, 
								   CRYPT_CERTINFO_CERTTYPE );
	if( cryptStatusError( cryptStatus ) )
		return( ( cryptStatus == CRYPT_ARGERROR_OBJECT ) ? \
				CRYPT_ARGERROR_NUM1 : cryptStatus );
	if( value == CRYPT_CERTTYPE_CERTIFICATE )
		{
		cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
									   &value, 
									   CRYPT_CERTINFO_TRUSTED_IMPLICIT );
		if( cryptStatusError( cryptStatus ) )
			return( CRYPT_ARGERROR_NUM1 );

		/* If the cert is implicitly trusted we indicate that it's 
		   (effectively) a non-leaf cert so that it can be added even if 
		   there's no corresponding key already in the device */
		if( value )
			isLeafCert = FALSE;
		}

	/* Add each cert in the chain to the device */
	do
		{
		CK_OBJECT_HANDLE hObject;
		STREAM stream;
		DYNBUF iAndSDB;
		int length;

		/* If the cert is already present, don't do anything */
		cryptStatus = dynCreate( &iAndSDB, iCryptCert, 
								 CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
		if( cryptStatusError( cryptStatus ) )
			return( cryptStatus );
		sMemConnect( &stream, dynData( iAndSDB ), dynLength( iAndSDB ) );
		readSequence( &stream, NULL );
		certTemplate[ 2 ].pValue = sMemBufPtr( &stream );
		readSequence( &stream, &length );		/* Issuer DN */
		certTemplate[ 2 ].ulValueLen = ( int ) sizeofObject( length );
		sSkip( &stream, length );
		certTemplate[ 3 ].pValue = sMemBufPtr( &stream );
		readGenericHole( &stream, &length, BER_INTEGER );/* Serial number */
		certTemplate[ 3 ].ulValueLen = ( int ) sizeofObject( length );
		assert( sStatusOK( &stream ) );
		sMemDisconnect( &stream );
		cryptStatus = findObject( pkcs11Info, &hObject, certTemplate, 4 );
		dynDestroy( &iAndSDB );
		if( cryptStatusOK( cryptStatus ) )
			/* The cert is already present, we don't need to add it again */
			continue;

		/* Write the new cert */
		cryptStatus = updateCertificate( pkcs11Info, iCryptCert, isLeafCert );
		if( cryptStatusError( cryptStatus ) )
			return( cryptStatus );
		isLeafCert = FALSE;
		seenNonDuplicate = TRUE;
		}
	while( krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, 
							MESSAGE_VALUE_CURSORNEXT,
							CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
	
	return( seenNonDuplicate ? CRYPT_OK : CRYPT_ERROR_DUPLICATE );
	}

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

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

static int getCapabilities( DEVICE_INFO *deviceInfo );
static void freeCapabilities( 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 )
	{
	PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;

	/* Log out and close the session with the device */
	if( deviceInfo->flags & DEVICE_LOGGEDIN )
		C_Logout( pkcs11Info->hSession );
	C_CloseSession( pkcs11Info->hSession );
	pkcs11Info->hSession = 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_SLOT_INFO slotInfo;
	CK_TOKEN_INFO tokenInfo;
	CK_RV status;
	PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
	char *labelPtr;
	int tokenSlot = DEFAULT_SLOT, i, labelLength, cryptStatus;

	/* Get information on all available slots */
	memset( slotList, 0, sizeof( slotList ) );
	status = C_GetSlotList( TRUE, slotList, &slotCount );
	if( status != CKR_OK )
		return( mapError( pkcs11Info, status, CRYPT_ERROR_OPEN ) );
	if( slotCount <= 0 )
		/* There are token slots present but no tokens in the slots */
		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 ] == ':' )
			break;
	if( i < nameLength - 1 )
		{
		const char *tokenName = name + i + 2;	/* Skip '::' */
		const int tokenNameLength = nameLength - ( i + 2 );

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

		/* Some tokens don't implement named slots, so we also allow them to 
		   be specified using slot counts */
		if( tokenNameLength == 1 && isDigit( *tokenName ) )
			{
			tokenSlot = *tokenName - '0';
			if( tokenSlot < 0 || tokenSlot > 9 )

⌨️ 快捷键说明

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