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

📄 asn1objs.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						ASN.1 Object Management Routines					*
*						Copyright Peter Gutmann 1992-2001					*
*																			*
****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) || defined( INC_CHILD )
  #include "asn1.h"
  #include "asn1objs.h"
  #include "asn1oid.h"
#else
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1objs.h"
  #include "keymgmt/asn1oid.h"
#endif /* Compiler-specific includes */

/* Context-specific tags for the KEK record */

enum { CTAG_KK_DA };

/* Context-specific tags for the KeyTrans record */

enum { CTAG_KT_SKI };

/* Context-specific tags for the KeyAgree/Fortezza record */

enum { CTAG_KA_ORIG, CTAG_KA_UKM };

/* Context-specific tags for the RecipientInfo record.  KeyTrans has no tag
   (actually it has an implied 0 tag because of CMS misdesign, so the other
   tags start at 1).  To allow for addition of new RI types we permit (but
   ignore) objects tagged up to CTAG_RI_MAX */

enum { CTAG_RI_KEYAGREE = 1, CTAG_RI_KEK, CTAG_RI_PWRI, CTAG_RI_MAX = 9 };

/* Context-specific tags for the SignerInfo record */

enum { CTAG_SI_SKI };

/* CMS version numbers for various objects */

#define KEYTRANS_VERSION		0
#define PWRI_VERSION			0
#define KEYTRANS_EX_VERSION		2
#define KEK_VERSION				4
#define SIGNATURE_VERSION		1
#define SIGNATURE_EX_VERSION	3

/****************************************************************************
*																			*
*							Message Digest Routines							*
*																			*
****************************************************************************/

/* Determine the encoded size of a message digest value */

int sizeofMessageDigest( const CRYPT_ALGO hashAlgo, const int hashSize )
	{
	return( ( int ) sizeofObject( sizeofAlgoID( hashAlgo ) + \
								  ( int ) sizeofObject( hashSize ) ) );
	}

/* Write a message digest value */

int writeMessageDigest( STREAM *stream, const CRYPT_ALGO hashAlgo, 
						const void *hash, const int hashSize )
	{
	writeSequence( stream, sizeofAlgoID( hashAlgo ) + \
				   ( int ) sizeofObject( hashSize ) );
	writeAlgoID( stream, hashAlgo );
	return( writeOctetString( stream, hash, hashSize, DEFAULT_TAG ) );
	}

/* Read a message digest value */

int readMessageDigest( STREAM *stream, CRYPT_ALGO *hashAlgo, void *hash, 
					   int *hashSize )
	{
	readSequence( stream, NULL );
	readAlgoID( stream, hashAlgo );
	return( readOctetString( stream, hash, hashSize, CRYPT_MAX_HASHSIZE ) );
	}

/****************************************************************************
*																			*
*					Conventionally-Encrypted Key Routines					*
*																			*
****************************************************************************/

/* The OID for the PKCS #5 v2.0 key derivation function and the parameterised
   PWRI key wrap algorithm */

#define OID_PBKDF2	MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C" )
#define OID_PWRIKEK	MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x09" )

/* Write a PBKDF2 key derivation record */

static int writeKeyDerivationInfo( STREAM *stream, 
								   const CRYPT_CONTEXT iCryptContext )
	{
	RESOURCE_DATA msgData;
	BYTE salt[ CRYPT_MAX_HASHSIZE ];
	int keySetupIterations, derivationInfoSize, status;

	/* Get the key derivation information */
	status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
							  &keySetupIterations, 
							  CRYPT_CTXINFO_KEYING_ITERATIONS );
	if( status == CRYPT_ERROR_NOTFOUND )
		/* If the key wasn't derived from a password, don't go any further */
		return( CRYPT_OK );
	if( cryptStatusOK( status ) )
		{
		setResourceData( &msgData, salt, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( iCryptContext, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CTXINFO_KEYING_SALT );
		}
	if( cryptStatusError( status ) )
		return( status );
	derivationInfoSize = ( int ) sizeofObject( msgData.length ) + \
						 sizeofShortInteger( ( long ) keySetupIterations );

	/* Write the PBKDF2 information */
	writeConstructed( stream, sizeofOID( OID_PBKDF2 ) +
					  ( int ) sizeofObject( derivationInfoSize ), CTAG_KK_DA );
	writeOID( stream, OID_PBKDF2 );
	writeSequence( stream, derivationInfoSize );
	writeOctetString( stream, msgData.data, msgData.length, DEFAULT_TAG );
	writeShortInteger( stream, keySetupIterations, DEFAULT_TAG );
	zeroise( salt, CRYPT_MAX_HASHSIZE );

	return( sGetStatus( stream ) );
	}

/* Read a PBKDF2 key derivation record */

static int readKeyDerivationInfo( STREAM *stream, QUERY_INFO *queryInfo )
	{
	long endPos, value;
	int length, status;

	/* Read the outer wrapper and key derivation algorithm OID */
	readConstructed( stream, NULL, CTAG_KK_DA );
	status = readOID( stream, OID_PBKDF2 );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the PBKDF2 parameters, limiting the salt and iteration count to
	   sane values */
	readSequence( stream, &length );
	endPos = stell( stream ) + length;
	status = readOctetString( stream, queryInfo->salt, 
						&queryInfo->saltLength, CRYPT_MAX_HASHSIZE );
	if( cryptStatusError( status ) )
		return( status );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	if( value > MAX_KEYSETUP_ITERATIONS )
		return( CRYPT_ERROR_BADDATA );
	queryInfo->keySetupIterations = ( int ) value;
	queryInfo->keySetupAlgo = CRYPT_ALGO_HMAC_SHA;
	if( stell( stream ) < endPos )
		sseek( stream, endPos );

	return( sGetStatus( stream ) );
	}

/* Write a KEKRecipientInfo (= PasswordRecipientInfo) record */

int writeKEKInfo( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
				  const BYTE *encryptedKey, const int encryptedKeyLength )
	{
	STREAM localStream;
	BYTE derivationInfo[ CRYPT_MAX_HASHSIZE + 32 ], kekInfo[ 128 ];
	int derivationInfoSize, kekInfoSize, status;

	/* Determine the size of the derivation info and KEK info.  To save
	   evaluating it twice in a row and because it's short, we just write
	   it to local buffers */
	sMemOpen( &localStream, derivationInfo, CRYPT_MAX_HASHSIZE + 32 );
	status = writeKeyDerivationInfo( &localStream, iCryptContext );
	derivationInfoSize = ( int ) stell( &localStream );
	sMemDisconnect( &localStream );
	if( cryptStatusError( status ) )
		return( status );
	sMemOpen( &localStream, kekInfo, 128 );
#if 1	/* Post-June 2001 PWRI draft */
	writeSequence( &localStream, 
				   sizeofOID( OID_PWRIKEK ) + \
				   sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
										ALGOID_FLAG_NONE ) );
	writeOID( &localStream, OID_PWRIKEK );
#endif /* Post-June 2001 PWRI draft */
	status = writeContextAlgoID( &localStream, iCryptContext, CRYPT_ALGO_NONE,
								 ALGOID_FLAG_NONE );
	kekInfoSize = ( int ) stell( &localStream );
	sMemDisconnect( &localStream );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the algorithm identifiers and encrypted key */
	writeConstructed( stream, sizeofShortInteger( PWRI_VERSION ) +
					  derivationInfoSize + kekInfoSize + 
					  ( int ) sizeofObject( encryptedKeyLength ), 
					  CTAG_RI_PWRI );
	writeShortInteger( stream, PWRI_VERSION, DEFAULT_TAG );
	if( derivationInfoSize )
		swrite( stream, derivationInfo, derivationInfoSize );
	swrite( stream, kekInfo, kekInfoSize );
	writeOctetString( stream, encryptedKey, encryptedKeyLength, DEFAULT_TAG );

	return( sGetStatus( stream ) );
	}

/* Read a KEKRecipientInfo (= PasswordRecipientInfo) record */

int readKEKInfo( STREAM *stream, QUERY_INFO *queryInfo )
	{
	long value;
	int status;

	/* Clear return value */
	memset( queryInfo, 0, sizeof( QUERY_INFO ) );

	/* Read the header */
	readConstructed( stream, NULL, CTAG_RI_PWRI );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	if( value != PWRI_VERSION )
		return( CRYPT_ERROR_BADDATA );

	/* Read the optional KEK derivation info and KEK algorithm info */
	if( peekTag( stream ) == MAKE_CTAG( CTAG_KK_DA ) )
		status = readKeyDerivationInfo( stream, queryInfo );
	if( cryptStatusOK( status ) )
		{
		const long position = stell( stream );

		/* Because of the last-minute change in the PWRI format before the 
		   RFC was published, older versions of cryptlib generate a slightly
		   different KEK algorithm info format.  To handle this, we read
		   part of the AlgorithmIdentifier and, if it's the newer format,
		   skip the extra level of wrapping */
		readSequence( stream, NULL );
		status = readOID( stream, OID_PWRIKEK );
		if( cryptStatusError( status ) )
			{
			/* It's the original format, clear the stream error state caused 
			   by the failed PWRI KEK OID read and try again */
			sClearError( stream );
			sseek( stream, position );
			}
		status = readContextAlgoID( stream, NULL, queryInfo, DEFAULT_TAG );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Finally, read the start of the encrypted key.  We never read the data
	   itself since it's passed directly to the decrypt function */
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		{
		queryInfo->dataStart = sMemBufPtr( stream );
		if( queryInfo->dataLength < bitsToBytes( MIN_KEYSIZE_BITS ) )
			/* We shouldn't be using a key this short, we can't actually 
			   load it anyway but a CRYPT_ERROR_BADDATA at this point 
			   provides more meaningful information to the caller */
			status = CRYPT_ERROR_BADDATA;
		}

	return( status );
	}

/****************************************************************************
*																			*
*						Public-key Encrypted Key Routines					*
*																			*
****************************************************************************/

/* Write a KeyTransRecipientInfo record */

int writeKeyTransInfo( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
					   const BYTE *buffer, const int length,
					   const void *auxInfo, const int auxInfoLength,
					   const RECIPIENT_TYPE recipientType )
	{
	const int dataLength = \
				sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
									 ALGOID_FLAG_ALGOID_ONLY ) + \
				( int ) sizeofObject( length );

	if( recipientType == RECIPIENT_CRYPTLIB )
		{
		RESOURCE_DATA msgData;
		BYTE keyID[ CRYPT_MAX_HASHSIZE ];

		setResourceData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
		krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE_S, 
						 &msgData, CRYPT_IATTRIBUTE_KEYID );
		writeSequence( stream, sizeofShortInteger( KEYTRANS_EX_VERSION ) +
					   ( int ) sizeofObject( msgData.length ) + dataLength );
		writeShortInteger( stream, KEYTRANS_EX_VERSION, DEFAULT_TAG );
		writeOctetString( stream, msgData.data, msgData.length, CTAG_KT_SKI );
		}
	else
		{
		writeSequence( stream, sizeofShortInteger( KEYTRANS_VERSION ) +
					   auxInfoLength + dataLength );
		writeShortInteger( stream, KEYTRANS_VERSION, DEFAULT_TAG );
		swrite( stream, auxInfo, auxInfoLength );
		}
	writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE,
						ALGOID_FLAG_ALGOID_ONLY );
	writeOctetString( stream, buffer, length, DEFAULT_TAG );

	return( sGetStatus( stream ) );
	}

/* Read a KeyTransRecipientInfo record */

int readKeyTransInfo( STREAM *stream, QUERY_INFO *queryInfo )
	{
	long value;
	int status;

	/* Clear return value */
	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
	queryInfo->formatType = CRYPT_FORMAT_CRYPTLIB;

	/* Read the header and version number */
	readSequence( stream, NULL );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	if( value < 0 || value > KEYTRANS_EX_VERSION )
		return( CRYPT_ERROR_BADDATA );

	/* Read the key ID and PKC algorithm information */
	if( value != KEYTRANS_EX_VERSION )
		{
		queryInfo->formatType = CRYPT_FORMAT_CMS;
		queryInfo->iAndSStart = sMemBufPtr( stream );
		queryInfo->iAndSLength = getObjectLength( queryInfo->iAndSStart, 
												  sMemDataLeft( stream ) );
		status = readUniversal( stream );
		}
	else
		status = readOctetStringTag( stream, queryInfo->keyID, 
						&queryInfo->keyIDlength, CRYPT_MAX_HASHSIZE, 
						MAKE_CTAG_PRIMITIVE( CTAG_KT_SKI ) );
	if( cryptStatusOK( status ) )
		status = readAlgoID( stream, &queryInfo->cryptAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* Finally, read the start of the encrypted key.  We never read the data
	   itself since it's passed directly to the PKC decrypt function */
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		queryInfo->dataStart = sMemBufPtr( stream );

	return( status );
	}

/****************************************************************************
*																			*
*								Key Agreement Routines						*
*																			*
****************************************************************************/

/* Write a KeyAgreeRecipientInfo (=FortezzaRecipientInfo) record */

int writeKeyAgreeInfo( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
					   const void *wrappedKey, const int wrappedKeyLength,
					   const void *ukm, const int ukmLength,
					   const void *auxInfo, const int auxInfoLength )
	{
	RESOURCE_DATA msgData;
	BYTE rKeyID[ 1024 ];
	int rKeyIDlength, recipientKeyInfoSize, status;

	/* Get the recipients key ID and determine how large the recipient key 
	   info will be */
	setResourceData( &msgData, rKeyID, 1024 );
	status = krnlSendMessage( iCryptContext, 
							  RESOURCE_MESSAGE_GETATTRIBUTE_S, &msgData, 
							  CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
	if( cryptStatusError( status ) )
		return( status );
	rKeyIDlength = msgData.length;
	recipientKeyInfoSize = ( int ) ( \
							sizeofObject( sizeofObject( rKeyIDlength ) ) + \
							sizeofObject( wrappedKeyLength ) );

	/* Write the FortezzaRecipientInfo header and version number */
	writeConstructed( stream, sizeofShortInteger( 3 ) + 
					  ( int ) sizeofObject( sizeofObject( auxInfoLength ) ) +
					  ( int ) sizeofObject( sizeofObject( ukmLength ) ) +
					  sizeofOID( ALGOID_FORTEZZA_KEYWRAP ) +
					  ( int ) sizeofObject( sizeofObject( recipientKeyInfoSize ) ),
					  CTAG_RI_KEYAGREE );
	writeShortInteger( stream, 3, DEFAULT_TAG );
	
	/* Write the originator's keyIdentifier, UKM, and Fortezza key wrap OID */
	writeConstructed( stream, ( int ) sizeofObject( auxInfoLength ), 
					  CTAG_KA_ORIG );
	writeOctetString( stream, auxInfo, auxInfoLength, 0 );
	writeConstructed( stream, ( int ) sizeofObject( ukmLength ), 
					  CTAG_KA_UKM );
	writeOctetString( stream, ukm, ukmLength, DEFAULT_TAG );
	swrite( stream, ALGOID_FORTEZZA_KEYWRAP, 
			sizeofOID( ALGOID_FORTEZZA_KEYWRAP ) );

	/* Write the recipient keying info */

⌨️ 快捷键说明

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