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

📄 pkcs12.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*						  cryptlib PKCS #12 Routines						*
*						Copyright Peter Gutmann 1997-2002					*
*																			*
****************************************************************************/

/* This code is based on breakms.c, which breaks the encryption of several of
   MS's extremely broken PKCS #12 implementations.  Because of the security
   problems associated with key files produced by MS software and the fact
   that this format is commonly used to spray private keys around without any
   regard to their sensitivity, cryptlib doesn't support it.  As one vendor 
   who shall remain anonymous put it, "We don't want to put our keys anywhere 
   where MS software can get to them" */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "keyset.h"
  #include "asn1.h"
  #include "asn1_ext.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "keyset.h"
  #include "../misc/asn1.h"
  #include "../misc/asn1_ext.h"
#else
  #include "crypt.h"
  #include "keyset/keyset.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */

#ifdef USE_PKCS12

/* A PKCS #12 file can in theory contain multiple key and cert objects,
   however nothing seems to use this capability, both because there are half
   a dozen different interpretations as to how it's supposed to work, both in
   terms of how to interpret the format and what to do with things like 
   MACing, which can only use a single key even if there are multiple
   different encryption keys used for the data, and because the complete
   abscence of key indexing information means that there's no easy way to 
   sort out which key is used for what.  The code is written to handle 
   multiple personalities like PKCS #15 and PGP, but is restricted to using 
   only a single personality */

#define MAX_PKCS12_OBJECTS		1

/* The minimum number of keying iterations to use when deriving a key wrap
   key from a password */

#define MIN_KEYING_ITERATIONS	1000

/* Parameters for PKCS #12's homebrew password-derivation mechanism.  The ID
   values function as diversifiers when generating the same keying material
   from a given password and in effect function as an extension of the salt */

#define KEYWRAP_ID_IV			1
#define KEYWRAP_ID_MACKEY		2
#define KEYWRAP_ID_WRAPKEY		3
#define KEYWRAP_SALTSIZE		8

/* The following structure contains the information for one personality, 
   which covers one or more of a private key, public key, and cert.  We also
   need to store a MAC context for use when we write the data to disk, this 
   is supposedly optional but most apps will reject the keyset (or even 
   crash) if it's not present */

typedef struct {
	/* General information */
	int index;						/* Unique value for this personality */
	char label[ CRYPT_MAX_TEXTSIZE ];/* PKCS #12 object label */
	int labelLength;

	/* Key wrap and MAC information */
	BYTE wrapSalt[ CRYPT_MAX_HASHSIZE ];
	int wrapSaltSize;				/* Salt for key wrap key */
	int wrapIterations;				/* Number of iters.to derive key wrap key */
	CRYPT_CONTEXT iMacContext;		/* MAC context */
	BYTE macSalt[ CRYPT_MAX_HASHSIZE ];
	int macSaltSize;				/* Salt for MAC key */
	int macIterations;				/* Number of iters.to derive MAC key */

	/* Key/cert object data */
	void *privKeyData, *certData;	/* Encoded object data */
	int privKeyDataSize, certDataSize;
	} PKCS12_INFO;

/* OID information for a PKCS #12 file */

static const FAR_BSS OID_SELECTION dataOIDselection[] = {
    { OID_CMS_DATA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_OK },
    { NULL, 0, 0, 0 }
    };

static const FAR_BSS OID_SELECTION keyDataOIDselection[] = {
	{ OID_CMS_ENCRYPTEDDATA, 0, 2, TRUE },				/* Encr.priv.key */
	{ OID_CMS_DATA, CRYPT_UNUSED, CRYPT_UNUSED, FALSE },/* Non-encr priv.key */
	{ NULL, 0, 0, 0 }
	};

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Free object entries */

static void pkcs12freeEntry( PKCS12_INFO *pkcs12info )
	{
	if( pkcs12info->iMacContext != CRYPT_ERROR )
		krnlSendNotifier( pkcs12info->iMacContext, IMESSAGE_DECREFCOUNT );
	if( pkcs12info->privKeyData != NULL )
		{
		zeroise( pkcs12info->privKeyData, pkcs12info->privKeyDataSize );
		clFree( "pkcs12freeEntry", pkcs12info->privKeyData );
		}
	if( pkcs12info->certData != NULL )
		{
		zeroise( pkcs12info->certData, pkcs12info->certDataSize );
		clFree( "pkcs12freeEntry", pkcs12info->certData );
		}
	zeroise( pkcs12info, sizeof( PKCS12_INFO ) );
	}

static void pkcs12Free( PKCS12_INFO *pkcs12info )
	{
	int i;

	for( i = 0; i < MAX_PKCS12_OBJECTS; i++ )
		pkcs12freeEntry( &pkcs12info[ i ] );
	}

/* Create key wrap and MAC contexts from a password */

static int createKeyWrapContext( CRYPT_CONTEXT *iCryptContext,
								 const CRYPT_USER cryptOwner,
								 const char *password,
								 const int passwordLength,
								 PKCS12_INFO *pkcs12info )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	MECHANISM_DERIVE_INFO deriveInfo;
	BYTE key[ CRYPT_MAX_KEYSIZE ], iv[ CRYPT_MAX_IVSIZE ];
	BYTE saltData[ 1 + KEYWRAP_SALTSIZE ];
	int status;

	/* Derive the encryption key and IV from the password */
	getNonce( pkcs12info->wrapSalt, KEYWRAP_SALTSIZE );
	pkcs12info->wrapSaltSize = KEYWRAP_SALTSIZE;
	saltData[ 0 ] = KEYWRAP_ID_WRAPKEY;
	memcpy( saltData + 1, pkcs12info->wrapSalt, KEYWRAP_SALTSIZE );
	krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE,
					 &pkcs12info->wrapIterations,
					 CRYPT_OPTION_KEYING_ITERATIONS );
	if( pkcs12info->wrapIterations < MIN_KEYING_ITERATIONS )
		pkcs12info->wrapIterations = MIN_KEYING_ITERATIONS;
	setMechanismDeriveInfo( &deriveInfo, key, 20, password, passwordLength,
							CRYPT_ALGO_SHA, saltData, KEYWRAP_SALTSIZE + 1,
							pkcs12info->wrapIterations );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
							  &deriveInfo, MECHANISM_PKCS12 );
	if( cryptStatusOK( status ) )
		{
		setMechanismDeriveInfo( &deriveInfo, iv, 20, password, passwordLength,
								CRYPT_ALGO_SHA, saltData, KEYWRAP_SALTSIZE + 1,
								pkcs12info->wrapIterations );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
								  &deriveInfo, MECHANISM_PKCS12 );
		}
	clearMechanismInfo( &deriveInfo );
	if( cryptStatusError( status ) )
		{
		zeroise( key, CRYPT_MAX_KEYSIZE );
		zeroise( iv, CRYPT_MAX_KEYSIZE );
		return( status );
		}

	/* Create an encryption context and load the key and IV into it.
	   Because PKCS #12 is restricted to an oddball subset of algorithms and
	   modes, we hardcode in the use of 3DES to make sure that we get 
	   something which is safe to use */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_3DES );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusOK( status ) )
		{
		RESOURCE_DATA msgData;

		setResourceData( &msgData, key, 16 );
		status = krnlSendMessage( createInfo.cryptHandle,
								  IMESSAGE_SETATTRIBUTE_S, &msgData,
								  CRYPT_CTXINFO_KEY );
		if( cryptStatusOK( status ) )
			{
			int ivSize;

			krnlSendMessage( createInfo.cryptHandle, IMESSAGE_GETATTRIBUTE, 
							 &ivSize, CRYPT_CTXINFO_IVSIZE );
			setResourceData( &msgData, iv, ivSize );
			status = krnlSendMessage( createInfo.cryptHandle,
									  IMESSAGE_SETATTRIBUTE_S, &msgData, 
									  CRYPT_CTXINFO_IV );
			}
		if( cryptStatusError( status ) )
			krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		else
			*iCryptContext = createInfo.cryptHandle;
		}

	/* Clean up */
	zeroise( key, CRYPT_MAX_KEYSIZE );
	zeroise( iv, CRYPT_MAX_IVSIZE );
	return( status );
	}

static int createMacContext( PKCS12_INFO *pkcs12info, 
							 const CRYPT_USER cryptOwner, 
							 const char *password, const int passwordLength )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	MECHANISM_DERIVE_INFO deriveInfo;
	BYTE key[ CRYPT_MAX_KEYSIZE ], saltData[ 1 + KEYWRAP_SALTSIZE ];
	int status;

	/* Derive the MAC key from the password */
	getNonce( pkcs12info->macSalt, KEYWRAP_SALTSIZE );
	pkcs12info->macSaltSize = KEYWRAP_SALTSIZE;
	saltData[ 0 ] = KEYWRAP_ID_MACKEY;
	memcpy( saltData + 1, pkcs12info->macSalt, KEYWRAP_SALTSIZE );
	krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE,
					 &pkcs12info->macIterations,
					 CRYPT_OPTION_KEYING_ITERATIONS );
	if( pkcs12info->macIterations < MIN_KEYING_ITERATIONS )
		pkcs12info->macIterations = MIN_KEYING_ITERATIONS;
	setMechanismDeriveInfo( &deriveInfo, key, 20, password, passwordLength,
							CRYPT_ALGO_SHA, saltData, KEYWRAP_SALTSIZE + 1,
							pkcs12info->macIterations );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
							  &deriveInfo, MECHANISM_PKCS12 );
	clearMechanismInfo( &deriveInfo );
	if( cryptStatusError( status ) )
		{
		zeroise( key, CRYPT_MAX_KEYSIZE );
		return( status );
		}

	/* Create a MAC context and load the key into it */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusOK( status ) )
		{
		RESOURCE_DATA msgData;

		setResourceData( &msgData, key, 20 );
		status = krnlSendMessage( createInfo.cryptHandle,
								  IMESSAGE_SETATTRIBUTE_S, &msgData,
								  CRYPT_CTXINFO_KEY );
		if( cryptStatusError( status ) )
			krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		else
			pkcs12info->iMacContext = createInfo.cryptHandle;
		}

	/* Clean up */
	zeroise( key, CRYPT_MAX_KEYSIZE );
	return( status );
	}

/****************************************************************************
*																			*
*									Read a Key								*
*																			*
****************************************************************************/

/* Get a key from a PKCS #12 file.  If this code were complete it would use
   the same method as the one used by the PKCS #15 code where we scan the
   file when we open it (stripping out unnecessary junk on the way) and
   simply fetch the appropriate key from the preprocessed data when 
   getItemFunction() is called */

static int getItemFunction( KEYSET_INFO *keysetInfo,
							CRYPT_HANDLE *iCryptHandle,
							const KEYMGMT_ITEM_TYPE itemType,
							const CRYPT_KEYID_TYPE keyIDtype,
							const void *keyID,  const int keyIDlength,
							void *auxInfo, int *auxInfoLength,
							const int flags )
	{
	return( CRYPT_ERROR_NOTAVAIL );	/* Make sure that we always fail */
	}

/****************************************************************************
*																			*
*									Write a Key								*
*																			*
****************************************************************************/

/* Write the PKCS #12 mangling of a CMS wrapper */

static void writeNonCMSheader( STREAM *stream, const BYTE *oid,
							   const int length, const int attrDataLength )
	{
	writeSequence( stream, ( int ) \

⌨️ 快捷键说明

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