dbxpgp.c

来自「提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发」· C语言 代码 · 共 1,074 行 · 第 1/3 页

C
1,074
字号
		/* Build the packet header, which is hashed along with the key 
		   components to get the OpenPGP keyID:
			byte		ctb = 0x99
			byte[2]		length
			byte		version = 4
			byte[4]		key generation time 
			byte[]		key data

		   We can't add the length or key data yet since we have to parse
		   the key data to know how long it is, so we can only build the
		   static part of the header at this point */
		packetHeader[ 0 ] = 0x99;
		packetHeader[ 3 ] = PGP_VERSION_OPENPGP;

		/* Read the timestamp and validity period (for PGP 2.x keys) and 
		   make sure what's left will fit into the buffer */
		sread( stream, packetHeader + 4, 4 );
		if( value == PGP_VERSION_2 || value == PGP_VERSION_3 )
			{
			sSkip( stream, 2 );
			length -= 2;
			}
		pgpInfo->isOpenPGP = ( value == PGP_VERSION_OPENPGP ) ? TRUE : FALSE;
		if( length > MAX_PRIVATE_KEYSIZE )
			return( CRYPT_ERROR_BADDATA );

		/* Read the rest of the record into the memory buffer.  Note that we 
		   don't in theory need to do this for PGP 2.x keys since the only
		   information which takes part in the decryption process for private
		   keys is the MPI payload which we have a copy of anyway, however 
		   OpenPGP encrypts the entire private key data block so we keep a 
		   copy of the contents for all versions */
		status = sread( stream, keyData, length );
		if( cryptStatusError( status ) )
			return( status );
		*keyDataLength = length;
		}
	else
		/* If we're rereading a cached key from a memory stream it'll be a
		   private key */
		isPublicKey = FALSE;

	/* Read the public key components */
	sMemConnect( &keyStream, keyData, *keyDataLength );
	status = readPublicKeyComponents( &keyStream, pgpInfo, isPublicKey );
	if( cryptStatusError( status ) )
		{
		if( status == OK_SPECIAL )
			skipToKeyPacket( stream, endPos );
		return( status );
		}
	if( stream != NULL )
		{
		BYTE hash[ CRYPT_MAX_HASHSIZE ];
		const int length = ( int ) stell( &keyStream );

		/* Complete the packet header with the remaining information */
		packetHeader[ 1 ] =  ( ( 1 + 4 + length ) >> 8 ) & 0xFF;
		packetHeader[ 2 ] =  ( 1 + 4 + length ) & 0xFF;

		/* Hash the data needed to generate the OpenPGP keyID */
		getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
		hashFunction( hashInfo, NULL, packetHeader, 1 + 2 + 1 + 4, 
					  HASH_START );
		hashFunction( hashInfo, hash, keyData, length, HASH_END );
		memcpy( pgpInfo->keyID, hash + hashSize - PGP_KEYID_SIZE, 
				PGP_KEYID_SIZE );
		}

	/* If it's a private keyring, prepare to read the private key 
	   components */
	if( !isPublicKey )
		{
		int status;

		/* Handle decryption info for secret components if necessary */
		status = readSecretKeyDecryptionInfo( &keyStream, pgpInfo );
		if( cryptStatusError( status ) )
			{
			if( status == OK_SPECIAL )
				skipToKeyPacket( stream, endPos );
			return( status );
			}

		/* Remember where the private key data starts so we can process it 
		   later */
		pgpInfo->privKeyStart = ( int ) stell( &keyStream );
		}
	sMemDisconnect( &keyStream );

	/* If it's a full keyring stream, check for a keyID/userID match */
	if( stream != NULL )
		{
		status = readUserID( pgpInfo, stream, keyIDtype, keyID, keyIDlength,
							 flags );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If we're only reading the public key, or it's a check or label read, 
	   we're done */
	if( ( itemType != KEYMGMT_ITEM_PRIVATEKEY ) || \
		( flags & ( KEYMGMT_FLAG_CHECK_ONLY | KEYMGMT_FLAG_LABEL_ONLY ) ) )
		return( CRYPT_OK );

	/* Set up the key to decrypt the private-key fields if necessary */
	if( pgpInfo->cryptAlgo != CRYPT_ALGO_NONE )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;
		static const int cryptMode = CRYPT_MODE_CFB;
		int status;

		/* If no password is supplied, let the caller know they need a
		   password */
		if( password == NULL )
			return( CRYPT_ERROR_WRONGKEY );

		/* Convert the user password into an encryption context */
		setMessageCreateObjectInfo( &createInfo, pgpInfo->cryptAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
								  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
								  &createInfo, OBJECT_TYPE_CONTEXT );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( createInfo.cryptHandle, 
								  RESOURCE_IMESSAGE_SETATTRIBUTE, 
								  ( void * ) &cryptMode, CRYPT_CTXINFO_MODE );
		if( cryptStatusOK( status ) )
			status = pgpPasswordToKey( createInfo.cryptHandle, password,
									   passwordLength, pgpInfo->hashAlgo, 
									   pgpInfo->saltSize ? \
										pgpInfo->salt : NULL, 
									   pgpInfo->keySetupIterations );
		if( cryptStatusOK( status ) )
			{
			RESOURCE_DATA msgData;

			setResourceData( &msgData, pgpInfo->iv, PGP_IVSIZE );
			status = krnlSendMessage( createInfo.cryptHandle, 
									  RESOURCE_IMESSAGE_SETATTRIBUTE_S, 
									  &msgData, CRYPT_CTXINFO_IV );
			}
		if( cryptStatusError( status ) )
			return( status );
		iCryptContext = createInfo.cryptHandle;
		}

	/* Read the private-key fields */
	status = readCachedPrivateKeyComponents( pgpInfo, iCryptContext );
	if( pgpInfo->cryptAlgo != CRYPT_ALGO_NONE )
		krnlSendNotifier( iCryptContext, RESOURCE_IMESSAGE_DECREFCOUNT );
	return( status );
	}

/* Create an encryption context from the PGP key info */

static int createKey( CRYPT_CONTEXT *iCryptContext, PGP_INFO *pgpInfo,
					  const KEYMGMT_ITEM_TYPE itemType, const int flags )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	RESOURCE_DATA msgData;
	char *userID = pgpInfo->userID;
	int userIDsize = min( strlen( userID ), CRYPT_MAX_TEXTSIZE );
	int status;

	/* If there's no user ID present, use a dummy value.  This isn't really
	   important, the only reason we're setting a label at all is to avoid 
	   having the key load code complain about the absence of a label */
	if( userIDsize == 0 )
		{
		userID = "PGP private key";
		userIDsize = 15;
		}

	/* Load the key into the encryption context */
	setMessageCreateObjectInfo( &createInfo, pgpInfo->pkcAlgo );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
							  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	setResourceData( &msgData, pgpInfo->userID, userIDsize );
	status = krnlSendMessage( createInfo.cryptHandle, 
							  RESOURCE_IMESSAGE_SETATTRIBUTE_S,
							  &msgData, CRYPT_CTXINFO_LABEL );
	if( cryptStatusOK( status ) )
		{
		setResourceData( &msgData, pgpInfo->keyID, PGP_KEYID_SIZE );
		krnlSendMessage( createInfo.cryptHandle, 
						 RESOURCE_IMESSAGE_SETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_OPENPGP_KEYID );
		}
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( createInfo.cryptHandle, 
								  RESOURCE_IMESSAGE_SETATTRIBUTE, 
								  &pgpInfo->actionFlags, 
								  CRYPT_IATTRIBUTE_ACTIONPERMS );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, 
						  RESOURCE_IMESSAGE_DECREFCOUNT );
		return( status );
		}
	if( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA )
		{
		CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;

		setResourceData( &msgData, rsaKeyPtr, sizeof( CRYPT_PKCINFO_RSA ) );
		status = krnlSendMessage( createInfo.cryptHandle, 
								  RESOURCE_IMESSAGE_SETATTRIBUTE_S, 
								  &msgData, CRYPT_CTXINFO_KEY_COMPONENTS );
		cryptDestroyComponents( rsaKeyPtr );
		}
	else
		{
		CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;

		setResourceData( &msgData, dlpKeyPtr, sizeof( CRYPT_PKCINFO_DLP ) );
		status = krnlSendMessage( createInfo.cryptHandle, 
								  RESOURCE_IMESSAGE_SETATTRIBUTE_S, 
								  &msgData, CRYPT_CTXINFO_KEY_COMPONENTS );
		cryptDestroyComponents( dlpKeyPtr );
		}
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, 
						  RESOURCE_IMESSAGE_DECREFCOUNT );
		return( ( status == CRYPT_ARGERROR_STR1 ) ? \
				CRYPT_ERROR_BADDATA : status );
		}
	*iCryptContext = createInfo.cryptHandle;

	return( CRYPT_OK );
	}

/* Get a public or private key from a file or memory buffer and return it in
   an encryption context */

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 )
	{
	STREAM *stream = &keysetInfo->keysetFile.stream;
	PGP_INFO *pgpInfo = ( PGP_INFO * ) keysetInfo->keyData;
	BOOLEAN cachedKeyPresent = FALSE;
	int status = CRYPT_OK;

	assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
			itemType == KEYMGMT_ITEM_PRIVATEKEY );
	assert( keyIDtype == CRYPT_KEYID_NAME || \
			keyIDtype == CRYPT_KEYID_EMAIL || \
			keyIDtype == CRYPT_IKEYID_KEYID || \
			keyIDtype == CRYPT_IKEYID_PGPKEYID );

	/* If the key we're looking for matches the cached key, reread it from 
	   cache */
	if( pgpInfo->cachedKeyPresent && keyID != NULL && \
		pgpInfo->cachedKeyIDlength == keyIDlength && \
		!memcmp( pgpInfo->cachedKeyID, keyID, keyIDlength ) )
		cachedKeyPresent = TRUE;

	/* We're about to overwrite the cached key, mark it as absent */
	pgpInfo->cachedKeyPresent = FALSE;
	memset( pgpInfo->cachedKeyID, 0, CRYPT_MAX_TEXTSIZE );
	pgpInfo->cachedKeyIDlength = 0;

	/* Try and find the required key in the file */
	do
		status = readKey( pgpInfo, ( cachedKeyPresent ) ? NULL : \
						  &keysetInfo->keysetFile.stream, itemType, 
						  keyIDtype, keyID, keyIDlength, auxInfo, 
						  *auxInfoLength, pgpInfo->cachedKey, 
						  &pgpInfo->cachedKeyLength, flags );
	while( stream != NULL && status == OK_SPECIAL );

	/* If the read succeeded, remember the key ID information */
	if( status == CRYPT_OK || status == CRYPT_ERROR_WRONGKEY )
		{
		/* Remember that we have a cached key present, and save the key 
		   ID if there's one being used */
		pgpInfo->cachedKeyPresent = TRUE;
		if( keyID != NULL )
			{
			pgpInfo->cachedKeyIDlength = min( keyIDlength, CRYPT_MAX_TEXTSIZE );
			memcpy( pgpInfo->cachedKeyID, keyID, pgpInfo->cachedKeyIDlength );
			}
		}

	/* If it's just a check or label read, we're done */
	if( flags & KEYMGMT_FLAG_CHECK_ONLY )
		return( status );
	if( flags & KEYMGMT_FLAG_LABEL_ONLY )
		{
		const int userIDsize = min( strlen( pgpInfo->userID ), 
									CRYPT_MAX_TEXTSIZE );
		if( userIDsize == 0 )
			{
			/* No userID present, return a generic label */
			*auxInfoLength = 15;
			if( auxInfo != NULL )
				memcpy( auxInfo, "PGP private key", 15 );
			}
		else
			{
			*auxInfoLength = userIDsize;
			if( auxInfo != NULL )
				memcpy( auxInfo, pgpInfo->userID, userIDsize );
			}
		return( CRYPT_OK );
		}

	/* Import the key data into a context */
	if( cryptStatusOK( status ) )
		status = createKey( iCryptHandle, pgpInfo, itemType, flags );

	return( status );
	}

/* PGP keyrings can be arbitrarily large so we don't try to do any
   preprocessing, all we do at this point is allocate the key info */

static int initFunction( KEYSET_INFO *keysetInfo, const char *name,
						 const char *arg1, const CRYPT_KEYOPT_TYPE options )
	{
	assert( name == NULL ); assert( arg1 == NULL ); 

	/* Allocate memory for the key info */
	if( ( keysetInfo->keyData = malloc( sizeof( PGP_INFO ) ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	memset( keysetInfo->keyData, 0, sizeof( PGP_INFO ) );
	keysetInfo->keyDataSize = sizeof( PGP_INFO );

	return( CRYPT_OK );
	}

static void shutdownFunction( KEYSET_INFO *keysetInfo )
	{
	if( keysetInfo->keyData != NULL )
		{
		zeroise( keysetInfo->keyData, sizeof( PGP_INFO ) );
		free( keysetInfo->keyData );
		keysetInfo->keyData = NULL;
		}
	}

int setAccessMethodPGP( KEYSET_INFO *keysetInfo )
	{
	/* Set the access method pointers */
	keysetInfo->initFunction = initFunction;
	keysetInfo->shutdownFunction = shutdownFunction;
	keysetInfo->getItemFunction = getItemFunction;

	return( CRYPT_OK );
	}

⌨️ 快捷键说明

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