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

📄 key_rd.c

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

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PKC_CONTEXT		/* Indicate that we're working with PKC context */
#if defined( INC_ALL )
  #include "context.h"
  #include "pgp.h"
  #include "asn1.h"
  #include "asn1_ext.h"
  #include "misc_rw.h"
#elif defined( INC_CHILD )
  #include "context.h"
  #include "../envelope/pgp.h"
  #include "../misc/asn1.h"
  #include "../misc/asn1_ext.h"
  #include "../misc/misc_rw.h"
#else
  #include "context/context.h"
  #include "envelope/pgp.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
  #include "misc/misc_rw.h"
#endif /* Compiler-specific includes */

/* Although there is a fair amount of commonality between public and private-
   key functions, we keep them distinct to enforce red/black separation.

   The DLP algorithms split the key components over the information in the
   AlgorithmIdentifier and the actual public/private key components, with the
   (p, q, g) set classed as domain parameters and included in the
   AlgorithmIdentifier and y being the actual key.

	params = SEQ {
		p INTEGER,
		q INTEGER,				-- q for DSA
		g INTEGER,				-- g for DSA
		j INTEGER OPTIONAL,		-- X9.42 only
		validationParams [...]	-- X9.42 only
		}

	key = y INTEGER				-- g^x mod p

   For peculiar historical reasons (copying errors and the use of obsolete
   drafts as reference material) the X9.42 interpretation used in PKIX 
   reverses the second two parameters from FIPS 186 (so it uses p, g, q 
   instead of p, q, g), so when we read/write the parameter information we 
   have to switch the order in which we read the values if the algorithm 
   isn't DSA */

#define hasReversedParams( cryptAlgo ) \
		( ( cryptAlgo ) == CRYPT_ALGO_DH || \
		  ( cryptAlgo ) == CRYPT_ALGO_ELGAMAL )

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

/* Generate a key ID, which is the SHA-1 hash of the SubjectPublicKeyInfo.
   There are about half a dozen incompatible ways of generating X.509
   keyIdentifiers, the following is conformant with the PKIX specification
   ("use whatever you like as long as it's unique"), but differs slightly
   from one common method that hashes the SubjectPublicKey without the
   BIT STRING encapsulation.  The problem with this is that some DLP-based 
   algorithms use a single integer as the SubjectPublicKey, leading to
   potential key ID clashes */

static void calculateFlatKeyID( const void *keyInfo, const int keyInfoSize,
								BYTE *keyID )
	{
	HASHFUNCTION hashFunction;

	/* Hash the key info to get the key ID */
	getHashParameters( CRYPT_ALGO_SHA, &hashFunction, NULL );
	hashFunction( NULL, keyID, ( BYTE * ) keyInfo, keyInfoSize, HASH_ALL );
	}

int calculateKeyID( CONTEXT_INFO *contextInfoPtr )
	{
	PKC_INFO *publicKey = contextInfoPtr->ctxPKC;
	STREAM stream;
	BYTE buffer[ ( CRYPT_MAX_PKCSIZE * 4 ) + 50 ];
	const CRYPT_ALGO_TYPE cryptAlgo = contextInfoPtr->capabilityInfo->cryptAlgo;
	int status;

	assert( publicKey->writePublicKeyFunction != NULL );

	/* If the public key info is present in pre-encoded form, calculate the
	   key ID directly from that */
	if( publicKey->publicKeyInfo != NULL )
		{
		int length;

		calculateFlatKeyID( publicKey->publicKeyInfo, 
							publicKey->publicKeyInfoSize, publicKey->keyID );
		if( cryptAlgo != CRYPT_ALGO_KEA && cryptAlgo != CRYPT_ALGO_RSA )
			return( CRYPT_OK );

		/* If it's an RSA context, we also need to remember the PGP key ID 
		   alongside the cryptlib one */
		if( cryptAlgo == CRYPT_ALGO_RSA )
			{
			sMemConnect( &stream, publicKey->publicKeyInfo,
						 publicKey->publicKeyInfoSize );
			readSequence( &stream, NULL );
			readUniversal( &stream );
			readBitStringHole( &stream, &length, DEFAULT_TAG );
			readSequence( &stream, NULL );
			readInteger( &stream, buffer, &length, CRYPT_MAX_PKCSIZE );
			assert( sGetStatus( &stream ) == CRYPT_OK );
			sMemDisconnect( &stream );

			if( length > PGP_KEYID_SIZE )
				memcpy( publicKey->pgpKeyID, 
						buffer + length - PGP_KEYID_SIZE, PGP_KEYID_SIZE );
			return( CRYPT_OK );
			}

#ifdef USE_KEA
		/* If it's a KEA context, we also need to remember the start and
		   length of the domain parameters and key agreement public value in
		   the encoded key data */
		sMemConnect( &stream, publicKey->publicKeyInfo,
					 publicKey->publicKeyInfoSize );
		readSequence( &stream, NULL );
		readSequence( &stream, NULL );
		readUniversal( &stream );
		readOctetStringHole( &stream, &length, DEFAULT_TAG );
		publicKey->domainParamPtr = sMemBufPtr( &stream );
		publicKey->domainParamSize = ( int ) length;
		sSkip( &stream, length );
		readBitStringHole( &stream, &length, DEFAULT_TAG );
		publicKey->publicValuePtr = sMemBufPtr( &stream );
		publicKey->publicValueSize = ( int ) length - 1;
		assert( sGetStatus( &stream ) == CRYPT_OK );
		sMemDisconnect( &stream );
#endif /* USE_KEA */

		return( CRYPT_OK );
		}

	/* Write the public key fields to a buffer and hash them to get the key
	   ID */
	sMemOpen( &stream, buffer, ( CRYPT_MAX_PKCSIZE * 4 ) + 50 );
	status = publicKey->writePublicKeyFunction( &stream, contextInfoPtr, 
												KEYFORMAT_CERT, "public" );
	calculateFlatKeyID( buffer, stell( &stream ), publicKey->keyID );
	sMemClose( &stream );

	/* If it's an RSA key, we need to calculate the PGP key ID alongside the
	   cryptlib one */
	if( cryptAlgo == CRYPT_ALGO_RSA )
		{
		const PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
		const int length = BN_bn2bin( &pkcInfo->rsaParam_n, buffer );

		if( length > PGP_KEYID_SIZE )
			memcpy( publicKey->pgpKeyID, 
					buffer + length - PGP_KEYID_SIZE, PGP_KEYID_SIZE );
		}

	/* If the OpenPGP ID is already set (from the key being loaded from a PGP
	   keyset), we're done */
	if( publicKey->openPgpKeyIDSet )
		return( status );

	/* Finally, set the OpenPGP key ID.  Since calculation of the OpenPGP ID 
	   requires the presence of data that isn't usually present in a non-
	   PGP key, we can't calculate a real OpenPGP ID for some keys but have 
	   to use the next-best thing, the first 64 bits of the key ID.  This 
	   shouldn't be a major problem because it's really only going to be 
	   used with private keys, public keys will be in PGP format and selected 
	   by user ID (for encryption) or PGP ID/genuine OpenPGP ID (signing) */
	if( publicKey->pgpCreationTime )
		{
		HASHFUNCTION hashFunction;
		HASHINFO hashInfo;
		BYTE hash[ CRYPT_MAX_HASHSIZE ], packetHeader[ 64 ];
		int hashSize, length;

		/* There's a creation time present, generate a real OpenPGP key ID:
			byte		ctb = 0x99
			byte[2]		length
			-- Key data --
			byte		version = 4
			byte[4]		key generation time 
			byte		algorithm
			byte[]		key data
		  We do this by writing the public key fields to a buffer and 
		  creating a separate PGP public key header, then hashing the two */
		sMemOpen( &stream, buffer, ( CRYPT_MAX_PKCSIZE * 4 ) + 50 );
		status = publicKey->writePublicKeyFunction( &stream, contextInfoPtr, 
													KEYFORMAT_PGP, "public" );
		length = stell( &stream );
		packetHeader[ 0 ] = 0x99;
		packetHeader[ 1 ] = ( length >> 8 ) & 0xFF;
		packetHeader[ 2 ] = length & 0xFF;

		/* Hash the data needed to generate the OpenPGP keyID */
		getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
		hashFunction( hashInfo, NULL, packetHeader, 1 + 2, HASH_START );
		hashFunction( hashInfo, hash, buffer, length, HASH_END );
		memcpy( publicKey->openPgpKeyID, 
				hash + hashSize - PGP_KEYID_SIZE, PGP_KEYID_SIZE );
		sMemClose( &stream );
		}
	else
		/* No creation time, fake it */
		memcpy( publicKey->openPgpKeyID, publicKey->keyID,
				PGP_KEYID_SIZE );
	publicKey->openPgpKeyIDSet = TRUE;

	return( status );
	}

/****************************************************************************
*																			*
*								Read Public Keys							*
*																			*
****************************************************************************/

/* Read X.509 SubjectPublicKeyInfo public keys */

static int readRsaSubjectPublicKey( STREAM *stream, CONTEXT_INFO *contextInfoPtr,
									int *actionFlags )
	{
	PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
	int status;

	/* Read the SubjectPublicKeyInfo header field and parameter data if
	   there's any present.  We read the outer wrapper in generic form since
	   it may be context-specific-tagged if it's coming from a keyset (RSA
	   public keys is the one place where PKCS #15 keys differ from X.509
	   ones) or something odd from CRMF */
	readGenericHole( stream, NULL, DEFAULT_TAG );
	status = readAlgoID( stream, NULL );
	if( cryptStatusError( status ) )
		return( status );

	/* Set the maximum permitted actions.  More restrictive permissions may 
	   be set by higher-level code if required.  In particular if the key is
	   a pure public key (rather than merely the public portions of a 
	   private key), the actions will be restricted at that point to encrypt 
	   and sig-check only */
	*actionFlags = MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, ACTION_PERM_ALL ) | \
				   MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, ACTION_PERM_ALL ) | \
				   MK_ACTION_PERM( MESSAGE_CTX_SIGN, ACTION_PERM_ALL ) | \
				   MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_ALL );

	/* Read the BITSTRING encapsulation and the public key fields */
	readBitStringHole( stream, NULL, DEFAULT_TAG );
	readSequence( stream, NULL );
	readBignum( stream, &rsaKey->rsaParam_n );
	return( readBignum( stream, &rsaKey->rsaParam_e ) );
	}

static int readDlpSubjectPublicKey( STREAM *stream, CONTEXT_INFO *contextInfoPtr,
									int *actionFlags )
	{
	PKC_INFO *dlpKey = contextInfoPtr->ctxPKC;
	CRYPT_ALGO_TYPE cryptAlgo;
	int extraLength, status;

	/* Read the SubjectPublicKeyInfo header field and parameter data if
	   there's any present */
	readGenericHole( stream, NULL, DEFAULT_TAG );
	status = readAlgoIDex( stream, &cryptAlgo, NULL, &extraLength );
	if( cryptStatusOK( status ) && extraLength )
		{
		assert( contextInfoPtr->capabilityInfo->cryptAlgo == cryptAlgo );

		/* Read the header and key parameters */
		readSequence( stream, NULL );
		readBignum( stream, &dlpKey->dlpParam_p );
		if( hasReversedParams( cryptAlgo ) )
			{
			readBignum( stream, &dlpKey->dlpParam_g );
			status = readBignum( stream, &dlpKey->dlpParam_q );
			}
		else
			{
			readBignum( stream, &dlpKey->dlpParam_q );
			status = readBignum( stream, &dlpKey->dlpParam_g );
			}
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Set the maximum permitted actions.  Because of the special-case data 
	   formatting requirements for DLP algorithms, we make the usage 
	   internal-only.  If the key is a pure public key (rather than merely 
	   the public portions of a  private key), the actions will be 
	   restricted by higher-level code to sig-check only */
	if( cryptAlgo == CRYPT_ALGO_DSA )
		*actionFlags = MK_ACTION_PERM( MESSAGE_CTX_SIGN, \
									   ACTION_PERM_NONE_EXTERNAL ) | \
					   MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, \
									   ACTION_PERM_NONE_EXTERNAL );
	else
		*actionFlags = MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, \
									   ACTION_PERM_NONE_EXTERNAL ) | \
					   MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, \
									   ACTION_PERM_NONE_EXTERNAL );

	/* Read the BITSTRING encapsulation and the public key fields */
	readBitStringHole( stream, NULL, DEFAULT_TAG );
	return( readBignum( stream, &dlpKey->dlpParam_y ) );
	}

#ifdef USE_SSH1

/* Read SSHv1 public keys:

⌨️ 快捷键说明

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