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

📄 pnppki.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						cryptlib Plug-and-play PKI Routines					*
*						 Copyright Peter Gutmann 1999-2003					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "session.h"
  #include "cmp.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../session/session.h"
  #include "../session/cmp.h"
#else
  #include "crypt.h"
  #include "session/session.h"
  #include "session/cmp.h"
#endif /* Compiler-specific includes */

#ifdef USE_CMP

/* When we generate a new key, there are a variety of different key types
   (meaning key usages) that we can generate it for, constrained to some
   extent by what the underlying cert management protocol supports.  The
   following values identify the key type that we need to generate */

typedef enum {
	KEYTYPE_NONE,			/* No key type */
	KEYTYPE_ENCRYPTION,		/* Encryption key */
	KEYTYPE_SIGNATURE,		/* Signature key */
	KEYTYPE_BOTH,			/* Dual encryption/signature key */
	KEYTYPE_LAST			/* Last possible key type */
	} KEY_TYPE;

/* A structure to store key type-related information */

static const struct {
	const char *label;		/* Label for private key */
	const int actionPerms;	/* Context action perms */
	const int keyUsage;		/* Cert key usage */
	} keyInfo[] = {
	{ NULL, 0, 0 },
	{ "Encryption key", 
		MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL ),
		CRYPT_KEYUSAGE_KEYENCIPHERMENT },
	{ "Signature key", 
		MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_NONE_EXTERNAL ),
		CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ "Private key",
		MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_NONE_EXTERNAL ) | \
		MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_NONE_EXTERNAL ),
		CRYPT_KEYUSAGE_KEYENCIPHERMENT | CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ NULL, 0, 0 }
	};

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

/* Clean up an object if the PnP operation fails.  This is required when 
   working with devices since we need to explicitly delete anything that
   was created in the device as well as just deleting the cryptlib object */

static void cleanupObject( const CRYPT_CONTEXT iPrivateKey, 
						   const KEY_TYPE keyType )
	{
	CRYPT_DEVICE iCryptDevice;
	MESSAGE_KEYMGMT_INFO deletekeyInfo;
	int status;

	/* Delete the cryptlib object.  If it's a native object, we're done */
	krnlSendNotifier( iPrivateKey, IMESSAGE_DECREFCOUNT );
	status = krnlSendMessage( iPrivateKey, IMESSAGE_GETDEPENDENT,
							  &iCryptDevice, OBJECT_TYPE_DEVICE );
	if( cryptStatusError( status ) )
		return;

	/* Delete the key from the device.  We set the item type to delete to
	   public key since the device object will interpret this correctly
	   to mean that it should also delete the associated private key */
	setMessageKeymgmtInfo( &deletekeyInfo, CRYPT_KEYID_NAME, 
						   keyInfo[ keyType ].label,
						   strlen( keyInfo[ keyType ].label ), NULL, 0, 
						   KEYMGMT_FLAG_NONE );
	krnlSendMessage( iCryptDevice, IMESSAGE_KEY_DELETEKEY,
					 &deletekeyInfo, KEYMGMT_ITEM_PUBLICKEY );
	}

/* Check whether a network connection is still open, used when performing
   multiple transactions in a single session */

static BOOLEAN isConnectionOpen( SESSION_INFO *sessionInfoPtr )
	{
	int streamState;

	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONNSTATE, 
			&streamState, 0 );
	return( streamState );
	}

/* Check for the presence of a named object in a keyset/device */

static BOOLEAN isNamedObjectPresent( const CRYPT_HANDLE iCryptHandle,
									 const KEY_TYPE keyType )
	{
	MESSAGE_KEYMGMT_INFO getkeyInfo;
	const char *keyLabel = keyInfo[ keyType ].label;
	int status;

	setMessageKeymgmtInfo( &getkeyInfo, CRYPT_KEYID_NAME, keyLabel, 
						   strlen( keyLabel ), NULL, 0,
						   KEYMGMT_FLAG_CHECK_ONLY );
	status = krnlSendMessage( iCryptHandle, IMESSAGE_KEY_GETKEY, 
							  &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
	if( cryptStatusError( status ) )
		{
		setMessageKeymgmtInfo( &getkeyInfo, CRYPT_KEYID_NAME, keyLabel, 
							   strlen( keyLabel ), NULL, 0,
							   KEYMGMT_FLAG_CHECK_ONLY );
		status = krnlSendMessage( iCryptHandle, IMESSAGE_KEY_GETKEY, 
								  &getkeyInfo, KEYMGMT_ITEM_PRIVATEKEY );
		}
	return( cryptStatusOK( status ) ? TRUE : FALSE );
	}

/* Recreate a cert from an existing cert, either converting a standard cert
   to a data-only cert or vice versa.  This is easier than trying to 
   disconnect and re-connect certificate and context objects directly */

static int recreateCert( CRYPT_CERTIFICATE *iNewCert,
						 const CRYPT_CERTIFICATE iCryptCert,
						 const BOOLEAN isDataOnlyCert )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	RESOURCE_DATA msgData;
	BYTE buffer[ 2048 ], *bufPtr = buffer;
	int status;

	*iNewCert = CRYPT_ERROR;

	/* Recreate a cert by exporting the current cert and re-importing it in 
	   the required format */
	setMessageData( &msgData, NULL, 0 );
	status = krnlSendMessage( iCryptCert, IMESSAGE_CRT_EXPORT, &msgData,
							  CRYPT_CERTFORMAT_CERTIFICATE );
	if( cryptStatusOK( status ) )
		{
		if( msgData.length > 2048 && \
			( bufPtr = clDynAlloc( "recreateCert", msgData.length ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		msgData.data = bufPtr;
		status = krnlSendMessage( iCryptCert, IMESSAGE_CRT_EXPORT, &msgData,
								  CRYPT_CERTFORMAT_CERTIFICATE );
		}
	if( cryptStatusOK( status ) )
		{
		setMessageCreateObjectIndirectInfo( &createInfo, msgData.data,
											msgData.length,
											isDataOnlyCert ? \
												CERTFORMAT_DATAONLY : \
												CRYPT_CERTTYPE_CERTIFICATE );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
								  &createInfo, OBJECT_TYPE_CERTIFICATE );
		}
	if( bufPtr != buffer )
		clFree( "recreateCert", bufPtr );
	if( cryptStatusOK( status ) )
		*iNewCert = createInfo.cryptHandle;
	return( status );
	}

/* Get the identified CA/RA cert from a CTL */

static int getCACert( CRYPT_CERTIFICATE *iNewCert, 
					  const CRYPT_CERTIFICATE iCTL, const void *certID, 
					  const int certIDlength )
	{
	int status;

	assert( certIDlength == 0 || certIDlength == KEYID_SIZE );

	*iNewCert = CRYPT_ERROR;

	/* Step through the cert trust list checking each cert in turn to see
	   if it's the identified CA/RA cert.  Some CAs may only send a single 
	   cert in the CTL and not explicitly identify it, so if there's no cert
	   ID present we just use the first cert */
	status = krnlSendMessage( iCTL, IMESSAGE_SETATTRIBUTE,
							  MESSAGE_VALUE_CURSORFIRST,
							  CRYPT_CERTINFO_CURRENT_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );
	if( certIDlength > 0 )
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, ( void * ) certID, KEYID_SIZE );
		do
			{
			status = krnlSendMessage( iCTL, IMESSAGE_COMPARE, &msgData, 
									  MESSAGE_COMPARE_FINGERPRINT );
			}
		while( cryptStatusError( status ) && \
			   krnlSendMessage( iCTL, IMESSAGE_SETATTRIBUTE,
								MESSAGE_VALUE_CURSORNEXT,
								CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
		if( cryptStatusError( status ) )
			return( CRYPT_ERROR_NOTFOUND );
		}

	/* We've found the identified cert, convert it from the data-only form
	   in the CTL to a full cert that can be used to verify returned data */
	return( recreateCert( iNewCert, iCTL, FALSE ) );
	}

/****************************************************************************
*																			*
*						Cert Creation/Update Routines						*
*																			*
****************************************************************************/

/* Generate a new key of the appropriate type */

static int generateKey( CRYPT_CONTEXT *iPrivateKey,
						const CRYPT_USER iCryptUser,
						const CRYPT_DEVICE iCryptDevice,
						const KEY_TYPE keyType )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	RESOURCE_DATA msgData;
	int value, status;

	/* Clear return value */
	*iPrivateKey = CRYPT_ERROR;

	/* Create a new key using the default algorithm and of the default 
	   size */
	krnlSendMessage( iCryptUser, IMESSAGE_GETATTRIBUTE, &value, 
					 CRYPT_OPTION_PKC_ALGO );
	setMessageCreateObjectInfo( &createInfo, value );
	status = krnlSendMessage( iCryptDevice, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	krnlSendMessage( iCryptUser, IMESSAGE_GETATTRIBUTE, &value, 
					 CRYPT_OPTION_PKC_KEYSIZE );
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
					 ( int * ) &value, CRYPT_CTXINFO_KEYSIZE );
	setMessageData( &msgData, ( void * ) keyInfo[ keyType ].label, 
					strlen( keyInfo[ keyType ].label ) );
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE_S,
					 &msgData, CRYPT_CTXINFO_LABEL );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		return( status );
		}

	/* Generate the key */
	status = krnlSendMessage( createInfo.cryptHandle,
							  IMESSAGE_CTX_GENKEY, NULL, FALSE );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( createInfo.cryptHandle,
								  IMESSAGE_SETATTRIBUTE,
								  ( int * ) &keyInfo[ keyType ].actionPerms,
								  CRYPT_IATTRIBUTE_ACTIONPERMS );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		return( status );
		}
	*iPrivateKey = createInfo.cryptHandle;

	return( CRYPT_OK );
	}

/* Create a cert request for a key.  If a cert with a subject DN template is
   provided, we copy this into the request, otherwise we create a minimal 
   key-only request */

static int createCertRequest( CRYPT_CERTIFICATE *iCertReq, 
							  const CRYPT_CONTEXT iPrivateKey,
							  const CRYPT_CERTIFICATE iSubjDNCert,
							  const KEY_TYPE keyType )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	const BOOLEAN isPKCS10 = ( keyType == KEYTYPE_BOTH );
	int status;

⌨️ 快捷键说明

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