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

📄 pkcs11_rw.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
	CK_ATTRIBUTE dataTemplate = \
		{ CKA_VALUE, NULL_PTR, 0 };
	CK_RV status;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	BYTE buffer[ MAX_BUFFER_SIZE + 8 ], *bufPtr = buffer;
	int cryptStatus;

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
	assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );

	*iCryptCert = CRYPT_ERROR;

	/* Fetch the certificate data into local memory.  We can't use a dynBuf 
	   for this because it's a PKCS #11 attribute rather than a cryptlib 
	   attribute */
	status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
								  &dataTemplate, 1 );
	if( status == CKR_OK )
		{
		if( dataTemplate.ulValueLen > MAX_BUFFER_SIZE && \
			( bufPtr = clAlloc( "instantiateCert", \
					( size_t ) ( dataTemplate.ulValueLen ) ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		dataTemplate.pValue = bufPtr;
		status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
									  &dataTemplate, 1 );
		}
	if( status != CKR_OK )
		{
		if( bufPtr != buffer )
			clFree( "instantiateCert", bufPtr );
		return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_NOTFOUND ) );
		}

	/* Import the certificate as a cryptlib object */
	setMessageCreateObjectIndirectInfo( &createInfo, bufPtr, 
										dataTemplate.ulValueLen,
										CRYPT_CERTTYPE_CERTIFICATE );
	createInfo.arg1 = createContext ? CRYPT_CERTTYPE_CERTIFICATE : \
									  CRYPT_ICERTTYPE_DATAONLY;
	cryptStatus = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
								   IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
								   &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( bufPtr != buffer )
		clFree( "instantiateCert", bufPtr );
	if( cryptStatusOK( cryptStatus ) )
		*iCryptCert = createInfo.cryptHandle;
	return( cryptStatus );
	}

/* Get a certificate chain from a device */

static int getCertChain( PKCS11_INFO *pkcs11Info, 
						 const CRYPT_DEVICE iCertSource, 
						 const CK_OBJECT_HANDLE hCertificate, 
						 CRYPT_CERTIFICATE *iCryptCert, 
						 const BOOLEAN createContext )
	{
	CK_ATTRIBUTE idTemplate = \
		{ CKA_ID, NULL_PTR, 0 };
	CK_RV status;
	BYTE keyID[ MAX_BUFFER_SIZE + 8 ];

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
	assert( isHandleRangeValid( iCertSource ) );
	assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );

	/* Find the ID for this certificate */
	status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate, 
								  &idTemplate, 1 );
	if( status == CKR_OK && idTemplate.ulValueLen <= MAX_BUFFER_SIZE )
		{
		idTemplate.pValue = keyID;
		status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
									  &idTemplate, 1 );
		}
	if( status != CKR_OK || idTemplate.ulValueLen > MAX_BUFFER_SIZE )
		/* We couldn't get the ID to build the chain or it's too large to be
		   usable, we can at least still return the individual certificate */
		return( instantiateCert( pkcs11Info, hCertificate, iCryptCert, 
								 createContext ) );

	/* Create the certificate chain via an indirect import */
	return( iCryptImportCertIndirect( iCryptCert, iCertSource, 
							CRYPT_IKEYID_KEYID, keyID, idTemplate.ulValueLen, 
							createContext ? KEYMGMT_FLAG_DATAONLY_CERT : 0 ) );
	}

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

#define addTemplateValue( certTemplatePtr, valueType, valuePtr, valueLen ) \
		{ \
		( certTemplatePtr ).type = valueType; \
		( certTemplatePtr ).pValue = valuePtr; \
		( certTemplatePtr ).ulValueLen = valueLen; \
		}

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_DATE startDate, endDate;
	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 },
		/* Optional fields, filled in if required */
		{ CKA_NONE, NULL_PTR, 0 },	/*  8 */
		{ CKA_NONE, NULL_PTR, 0 },	/*  9 */
		{ CKA_NONE, NULL_PTR, 0 },	/* 10 */
		{ CKA_NONE, NULL_PTR, 0 },	/* 11 */
		};
	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;
	MESSAGE_DATA msgData;
	DYNBUF subjectDB, iAndSDB, certDB;
	BYTE keyID[ CRYPT_MAX_HASHSIZE + 8 ];
	BOOLEAN hasURL = FALSE;
	time_t theTime;
	char label[ CRYPT_MAX_TEXTSIZE + 8 ], uri[ MAX_URL_SIZE + 8 ];
	int templateCount = 8, cryptStatus;

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
	assert( isHandleRangeValid( iCryptHandle ) );

	/* Get the keyID from the certificate */
	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 certificate, 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 certificate, but there doesn't seem to be any good reason for 
	   this and it could lead to problems with multiple certificates 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 and issuerAndSerialNumber from the certificate */
	cryptStatus = dynCreate( &subjectDB, iCryptHandle, 
							 CRYPT_IATTRIBUTE_SUBJECT );
	if( cryptStatusError( cryptStatus ) )
		return( cryptStatus );
	certTemplate[ 4 ].pValue = dynData( subjectDB );
	certTemplate[ 4 ].ulValueLen = dynLength( subjectDB );
	cryptStatus = addIAndSToTemplate( &certTemplate[ 5 ], NULL, 0, 
									  &iAndSDB, iCryptHandle );
	if( cryptStatusError( cryptStatus ) )
		{
		dynDestroy( &subjectDB );
		return( cryptStatus );
		}

	/* Get the validFrom and validTo dates.  These aren't currently used for
	   anything, but can be used in the future to handle superceded 
	   certificates in the same way that it's done for PKCS #15 keysets */
	setMessageData( &msgData, &theTime, sizeof( time_t ) );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_CERTINFO_VALIDFROM );
	if( cryptStatusOK( cryptStatus ) )
		{
		convertDate( &startDate, theTime );
		setMessageData( &msgData, &theTime, sizeof( time_t ) );
		cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
									   &msgData, CRYPT_CERTINFO_VALIDTO );
		}
	if( cryptStatusOK( cryptStatus ) )
		convertDate( &endDate, theTime );
	else
		{
		dynDestroy( &subjectDB );
		dynDestroy( &iAndSDB );
		return( cryptStatus );
		}

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

	/* Get the certificate holder name (label) from the certificate if 
	  available */
	setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE  );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_IATTRIBUTE_HOLDERNAME );
	if( cryptStatusOK( cryptStatus ) )
		{
		/* We've found a holder name, use it as the certificate object 
		   label */
		addTemplateValue( certTemplate[ templateCount ], 
						  CKA_LABEL, msgData.data, msgData.length );
		templateCount++;
		}

	/* Add the certificate dates.  These have to be located between the 
	   label and URI so that we can selectively back out the attributes that 
	   don't work for this driver, see the comments further down for more 
	   details */
	addTemplateValue( certTemplate[ templateCount ], 
					  CKA_START_DATE, ( CK_VOID_PTR ) &startDate, sizeof( CK_DATE ) );
	templateCount++;
	addTemplateValue( certTemplate[ templateCount ], 
					  CKA_END_DATE, ( CK_VOID_PTR ) &endDate, sizeof( CK_DATE ) );
	templateCount++;

	/* Get the URI from the certificate if available */
	setMessageData( &msgData, uri, MAX_URL_SIZE );
	cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								   &msgData, CRYPT_IATTRIBUTE_HOLDERURI );
	if( cryptStatusOK( cryptStatus ) )
		{
		/* We've found a holder URI, use it as the certificate object URL */
		addTemplateValue( certTemplate[ templateCount ], 
						  CKA_URL, msgData.data, msgData.length );
		templateCount++;
		hasURL = TRUE;
		}

	/* Reset the status value, which may contain error values due to not 
	   finding various object attributes above */
	cryptStatus = CRYPT_OK;

	/* 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, templateCount, 
							 &hObject );
	if( hasURL && ( status == CKR_TEMPLATE_INCONSISTENT || \
					status == CKR_ATTRIBUTE_TYPE_INVALID ) )
		{
		/* Support for the PKCS #11 v2.20 attribute CKA_URL is pretty hit-
		   and-miss, some drivers from ca.2000 support it but others from 
		   ca.2007 still don't, so if we get a CKR_ATTRIBUTE_TYPE_INVALID 
		   return code we try again without the CKA_URL */
		templateCount--;
		status = C_CreateObject( pkcs11Info->hSession,
								 ( CK_ATTRIBUTE_PTR ) certTemplate, 
								 templateCount, &hObject );
		}
	if( status == CKR_TEMPLATE_INCONSISTENT )
		{
		/* Even support for dates is hit-and-miss so if we're still getting
		   CKR_ATTRIBUTE_TYPE_INVALID we try again without the 
		   CKA_START_DATE/CKA_END_DATE */
		templateCount -= 2;
		status = C_CreateObject( pkcs11Info->hSession,
								 ( CK_ATTRIBUTE_PTR ) certTemplate, 
								 templateCount, &hObject );
		}
	if( status != CKR_OK )
		cryptStatus = pkcs11MapError( pkcs11Info, status, 
									  CRYPT_ERROR_FAILED );
	assert( hObject != CK_OBJECT_NONE );

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

/* Update a device using the certificates in a certificate 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, iterationCount = 0, cryptStatus;

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
	assert( isHandleRangeValid( iCryptCert ) );

	/* If we've been passed a standalone certificate, 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 certificate is implicitly trusted we indicate that it's 
		   (effectively) a non-leaf certificate so that it can be added even 
		   if there's no corresponding key already in the device */
		if( value )

⌨️ 快捷键说明

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