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

📄 pnppki.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 2 页
字号:
		status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
								  ( int * ) &keyInfo[ keyType ].keyUsage, 
								  CRYPT_CERTINFO_KEYUSAGE );
	if( cryptStatusOK( status ) && iSubjDNCert != CRYPT_UNUSED )
		status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
								  ( int * ) &iSubjDNCert,
								  CRYPT_CERTINFO_CERTIFICATE );
	if( cryptStatusOK( status ) && !isPKCS10 )
		status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CRT_SIGN,
								  NULL, iPrivateKey );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		return( status );
		}
	*iCertReq = createInfo.cryptHandle;

	return( CRYPT_OK );
	}

/* Update a keyset/device with a newly-created key and cert */

static int updateKeys( const CRYPT_HANDLE iCryptHandle,
					   const CRYPT_CONTEXT iPrivateKey,
					   const CRYPT_CERTIFICATE iCryptCert,
					   const char *password, const int passwordLength )
	{
	MESSAGE_KEYMGMT_INFO setkeyInfo;
	int value, status;

	/* Find out whether the storage object is a keyset or a device.  If it's
	   a device there's no need to add the private key since it'll have been
	   created inside the device */
	status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE, &value,
							  CRYPT_IATTRIBUTE_TYPE );
	if( cryptStatusError( status ) )
		return( status );

	/* Add the private key and certificate to the keyset/device */
	if( value == OBJECT_TYPE_KEYSET )
		{
		setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
							   ( void * ) password, passwordLength,
							   KEYMGMT_FLAG_NONE );
		setkeyInfo.cryptHandle = iPrivateKey;
		status = krnlSendMessage( iCryptHandle, IMESSAGE_KEY_SETKEY,
								  &setkeyInfo, KEYMGMT_ITEM_PRIVATEKEY );
		if( cryptStatusError( status ) )
			return( status );
		}
	setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
						   NULL, 0, KEYMGMT_FLAG_NONE );
	setkeyInfo.cryptHandle = iCryptCert;
	return( krnlSendMessage( iCryptHandle, IMESSAGE_KEY_SETKEY,
							 &setkeyInfo, KEYMGMT_ITEM_PUBLICKEY ) );
	}

/* Update the keyset/device with any required trusted certs up to the root.  
   This ensures that we can still build a full cert chain even if the 
   PKIBoot trusted certs aren't preserved */

static int updateTrustedCerts( const CRYPT_HANDLE iCryptHandle,
							   const CRYPT_HANDLE iLeafCert )
	{
	CRYPT_CERTIFICATE iCertCursor = iLeafCert;
	int status;

	do
		{
		/* Get the trusted issuer cert for the current cert and send it to
		   the keyset/device */
		status = krnlSendMessage( iCertCursor, 
								  IMESSAGE_SETATTRIBUTE, &iCertCursor, 
								  CRYPT_IATTRIBUTE_CERT_TRUSTEDISSUER );
		if( cryptStatusOK( status ) )
			{
			MESSAGE_KEYMGMT_INFO setkeyInfo;

			setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
								   NULL, 0, KEYMGMT_FLAG_NONE );
			setkeyInfo.cryptHandle = iCertCursor;
			status = krnlSendMessage( iCryptHandle, IMESSAGE_KEY_SETKEY, 
									  &setkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
			}
		}
	while( cryptStatusOK( status ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							PnP PKI Session Management						*
*																			*
****************************************************************************/

/* Run a plug-and-play PKI session */

int pnpPkiSession( SESSION_INFO *sessionInfoPtr )
	{
	CRYPT_DEVICE iCryptDevice = SYSTEM_OBJECT_HANDLE;
	CRYPT_CONTEXT iPrivateKey1, iPrivateKey2 ;
	CRYPT_CERTIFICATE iCertReq, iCACert;
	const ATTRIBUTE_LIST *attributeListPtr;
	const ATTRIBUTE_LIST *passwordPtr = \
				findSessionAttribute( sessionInfoPtr->attributeList,
									  CRYPT_SESSINFO_PASSWORD );
	const KEY_TYPE keyType = ( sessionInfoPtr->type == CRYPT_SESSION_CMP ) ? \
							 KEYTYPE_SIGNATURE : KEYTYPE_BOTH;
	BOOLEAN isCAcert;
	int value, status;

	/* If we've been passed a device as the private-key storage location,
	   create the key in the device instead of as a local object */
	status = krnlSendMessage( sessionInfoPtr->privKeyset,
							  IMESSAGE_GETATTRIBUTE, &value,
							  CRYPT_IATTRIBUTE_TYPE );
	if( cryptStatusError( status ) )
		return( status );
	if( value == OBJECT_TYPE_DEVICE )
		iCryptDevice = sessionInfoPtr->privKeyset;

	/* Make sure that the named objects that are about to be created aren't 
	   already present in the keyset/device */
	if( isNamedObjectPresent( sessionInfoPtr->privKeyset, keyType ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_DUPLICATE,
				"%s is already present in keyset/device",
				( keyType == KEYTYPE_SIGNATURE ) ? "Signature key" : "Key" );
	if( sessionInfoPtr->type == CRYPT_SESSION_CMP )
		{
		if( isNamedObjectPresent( sessionInfoPtr->privKeyset, 
								  KEYTYPE_ENCRYPTION ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_DUPLICATE,
					"Encryption key is already present in keyset/device" );
		}

	/* Perform the PKIBoot exchange to get the initial trusted cert set.  We 
	   also set the retain-connection flag since we're going to follow this 
	   with another transaction */
	if( sessionInfoPtr->type == CRYPT_SESSION_CMP )
		sessionInfoPtr->sessionCMP->requestType = CRYPT_REQUESTTYPE_PKIBOOT;
	sessionInfoPtr->protocolFlags |= CMP_PFLAG_RETAINCONNECTION;
	status = sessionInfoPtr->transactFunction( sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );
	if( !isConnectionOpen( sessionInfoPtr ) )
		{
		/* If the connection was shut down by the other side, signal an 
		   error.  This is possibly a bit excessive since we could always 
		   try reactivating the session, but there's no good reason for the 
		   other side to simply close the connection and requiring it to 
		   remain open simplifies the implementation */
		krnlSendNotifier( sessionInfoPtr->iCertResponse, 
						  IMESSAGE_DECREFCOUNT );
		retExt( sessionInfoPtr, CRYPT_ERROR_READ,
				"Server closed connection after PKIBoot phase before any "
				"certificates could be issued" );
		}

	/* Get the CA/RA cert from the returned CTL and set it as the cert to 
	   use for authenticating server responses */
	attributeListPtr = \
			findSessionAttribute( sessionInfoPtr->attributeList,
								  CRYPT_SESSINFO_SERVER_FINGERPRINT );
	if( attributeListPtr == NULL )
		status = CRYPT_ERROR_NOTFOUND;
	else
		status = getCACert( &iCACert, sessionInfoPtr->iCertResponse, 
							attributeListPtr->value, 
							attributeListPtr->valueLength );
	krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_DECREFCOUNT );
	sessionInfoPtr->iCertResponse = CRYPT_ERROR;
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, status, 
				"Couldn't read CA/RA certificate from returned certificate "
				"trust list" );
	sessionInfoPtr->iAuthInContext = iCACert;

	/* Create a private key and a cert request for it */
	status = generateKey( &iPrivateKey1, sessionInfoPtr->ownerHandle,
						  iCryptDevice, keyType );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, status, "Couldn't create %s key",
				( keyType == KEYTYPE_SIGNATURE ) ? "signature" : "private" );
	status = createCertRequest( &iCertReq, iPrivateKey1, CRYPT_UNUSED, 
								keyType );
	if( cryptStatusError( status ) )
		{
		cleanupObject( iPrivateKey1, keyType );
		retExt( sessionInfoPtr, status,
				"Couldn't create %skey cert request",
				( keyType == KEYTYPE_SIGNATURE ) ? "signature " : "" );
		}

	/* Set up the request info and activate the session */
	if( sessionInfoPtr->type == CRYPT_SESSION_CMP )
		/* If it's CMP, start with an ir.  The second cert will be fetched 
		   with a cr */
		sessionInfoPtr->sessionCMP->requestType = CRYPT_REQUESTTYPE_INITIALISATION;
	sessionInfoPtr->iCertRequest = iCertReq;
	status = sessionInfoPtr->transactFunction( sessionInfoPtr );
	krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT );
	sessionInfoPtr->iCertRequest = CRYPT_ERROR;
	if( cryptStatusError( status ) )
		{
		cleanupObject( iPrivateKey1, keyType );
		return( status );
		}

	/* Check whether we've been issued a standalone CA cert rather than a 
	   standard signature cert to be followed by an encryption cert */
	status = krnlSendMessage( sessionInfoPtr->iCertResponse, 
							  IMESSAGE_GETATTRIBUTE, &isCAcert,
							  CRYPT_CERTINFO_CA );
	if( cryptStatusError( status ) )
		isCAcert = FALSE;

	/* If the connection was shut down by the other side and we're 
	   performing a multi-part operation that requires it to remain open, 
	   signal an error.  This is possibly a bit excessive since we could 
	   always try reactivating the session, but there's no good reason for 
	   the other side to simply close the connection and requiring it to 
	   remain open simplifies the implementation */
	if( sessionInfoPtr->type == CRYPT_SESSION_CMP && \
		!isConnectionOpen( sessionInfoPtr ) && !isCAcert )
		{
		cleanupObject( iPrivateKey1, keyType );
		krnlSendNotifier( sessionInfoPtr->iCertResponse, 
						  IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iCertResponse = CRYPT_ERROR;
		retExt( sessionInfoPtr, CRYPT_ERROR_READ,
				"Server closed connection before second (encryption) "
				"certificate could be issued" );
		}

	/* We've got the first cert, update the keyset/device */
	status = updateKeys( sessionInfoPtr->privKeyset, iPrivateKey1,
						 sessionInfoPtr->iCertResponse, 
						 passwordPtr->value, passwordPtr->valueLength );
	if( cryptStatusOK( status ) )
		{
		CRYPT_CERTIFICATE iNewCert;

		/* Recreate the cert as a data-only cert and attach it to the 
		   signing key so that we can use it to authenticate a request for 
		   an encryption key.  We need to recreate the cert because we're 
		   about to attach it to the private-key context for further 
		   operations, and attaching a cert with a public-key context 
		   already attached isn't possible.  Even if we're not getting a
		   second cert, we still need the current cert attached so that we 
		   can use it as the base cert for the trusted cert update that
		   we perform before we exit */
		status = recreateCert( &iNewCert, sessionInfoPtr->iCertResponse, 
							   TRUE );
		if( cryptStatusOK( status ) )
			krnlSendMessage( iPrivateKey1, IMESSAGE_SETDEPENDENT, &iNewCert, 
							 SETDEP_OPTION_NOINCREF );
		}
	krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_DECREFCOUNT );
	sessionInfoPtr->iCertResponse = CRYPT_ERROR;
	if( cryptStatusError( status ) )
		{
		cleanupObject( iPrivateKey1, keyType );
		retExt( sessionInfoPtr, ( status == CRYPT_ARGERROR_NUM1 ) ? \
				CRYPT_ERROR_INVALID : status,
				"Couldn't update keyset/device with %skey/certificate",
				isCAcert ? "CA " : \
				( keyType == KEYTYPE_SIGNATURE ) ? "signature " : "" );
		}

	/* If it's a combined encryption/signature key or a standalone CA key, 
	   we're done.  See the comment at the end for the trusted-certs update
	   process */
	if( keyType == KEYTYPE_BOTH || isCAcert )
		{
		updateTrustedCerts( sessionInfoPtr->privKeyset, iPrivateKey1 );
		krnlSendNotifier( iPrivateKey1, IMESSAGE_DECREFCOUNT );
		return( CRYPT_OK );
		}

	/* We're running a CMP session from this point on.  Create the second, 
	   encryption private key and a cert request for it */
	status = generateKey( &iPrivateKey2, sessionInfoPtr->ownerHandle,
						  iCryptDevice, KEYTYPE_ENCRYPTION );
	if( status == OK_SPECIAL )
		{
		/* Encryption isn't available via this device, exit without going
		   through the second phase of the exchange, leaving only the
		   signature key and certs set up */
		updateTrustedCerts( sessionInfoPtr->privKeyset, iPrivateKey1 );
		krnlSendNotifier( iPrivateKey1, IMESSAGE_DECREFCOUNT );
		return( CRYPT_OK );
		}
	if( cryptStatusError( status ) )
		{
		cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
		retExt( sessionInfoPtr, status, "Couldn't create encryption key" );
		}
	status = createCertRequest( &iCertReq, iPrivateKey2, iPrivateKey1,
								KEYTYPE_ENCRYPTION );
	if( cryptStatusError( status ) )
		{
		cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
		cleanupObject( iPrivateKey2, KEYTYPE_ENCRYPTION );
		retExt( sessionInfoPtr, status,
				"Couldn't create encryption key cert request" );
		}

	/* Set up the request info and activate the session.  This request is 
	   slightly different to the previous one since we now have a signature 
	   cert that we can use to authenticate the request (in fact we have to
	   use this since we can't authenticate the message with an encryption-
	   only key).  In addition since this is the last transaction we turn 
	   off the retain-connection flag */
	sessionInfoPtr->protocolFlags &= ~CMP_PFLAG_RETAINCONNECTION;
	sessionInfoPtr->sessionCMP->requestType = CRYPT_REQUESTTYPE_CERTIFICATE;
	sessionInfoPtr->iCertRequest = iCertReq;
	sessionInfoPtr->privateKey = iPrivateKey2;
	sessionInfoPtr->iAuthOutContext = iPrivateKey1;
	status = sessionInfoPtr->transactFunction( sessionInfoPtr );
	sessionInfoPtr->privateKey = CRYPT_ERROR;
	sessionInfoPtr->iAuthOutContext = CRYPT_ERROR;
	krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT );
	sessionInfoPtr->iCertRequest = CRYPT_ERROR;
	if( cryptStatusError( status ) )
		{
		cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
		cleanupObject( iPrivateKey2, KEYTYPE_ENCRYPTION );
		return( status );
		}

	/* We've got the second cert, update the keyset/device */
	status = updateKeys( sessionInfoPtr->privKeyset, iPrivateKey2,
						 sessionInfoPtr->iCertResponse, 
						 passwordPtr->value, passwordPtr->valueLength );
	krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_DECREFCOUNT );
	sessionInfoPtr->iCertResponse = CRYPT_ERROR;
	if( cryptStatusError( status ) )
		{
		cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
		cleanupObject( iPrivateKey2, KEYTYPE_ENCRYPTION );
		retExt( sessionInfoPtr, status,
				"Couldn't update keyset/device with encryption "
				"key/certificate" );
		}

	/* Finally, update the keyset/device with any required trusted certs up 
	   to the root.  This ensures that we can still build a full cert chain 
	   even if the PKIBoot trusted certs aren't preserved.  We don't check 
	   for errors from this function since it's not worth aborting the 
	   process for some minor CA cert update problem, the user keys and certs
	   will still function without them */
	updateTrustedCerts( sessionInfoPtr->privKeyset, iPrivateKey1 );

	/* Both keys were certified and the keys and certs sent to the keyset/
	   device, we're done */
	krnlSendNotifier( iPrivateKey1, IMESSAGE_DECREFCOUNT );
	krnlSendNotifier( iPrivateKey2, IMESSAGE_DECREFCOUNT );
	return( CRYPT_OK );
	}
#endif /* USE_CMP */

⌨️ 快捷键说明

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