dbxpgp.c

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

C
1,074
字号

	/* If it's an RSA key, read the components and set up the usage based on
	   the algorithm type */
	if( value == PGP_ALGO_RSA || value == PGP_ALGO_RSA_ENCRYPT || \
		value == PGP_ALGO_RSA_SIGN )
		{
		CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;

		cryptInitComponents( rsaKeyPtr, isPublicKey ? \
							 CRYPT_KEYTYPE_PUBLIC : CRYPT_KEYTYPE_PRIVATE );
		status = rsaKeyPtr->nLen = pgpReadMPI( stream, rsaKeyPtr->n );
		if( !cryptStatusError( status ) )
			status = rsaKeyPtr->eLen = pgpReadMPI( stream, rsaKeyPtr->e );
		if( cryptStatusError( status ) )
			return( status );
		pgpInfo->pkcAlgo = CRYPT_ALGO_RSA;
		if( value != PGP_ALGO_RSA_SIGN )
			{
			actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_ENCRYPT, 
										   ACTION_PERM_NONE_EXTERNAL );
			if( !isPublicKey )
				actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_DECRYPT, 
											   ACTION_PERM_NONE_EXTERNAL );
			usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
			}
		if( value != PGP_ALGO_RSA_ENCRYPT )
			{
			actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGCHECK, 
										   ACTION_PERM_NONE_EXTERNAL );
			if( !isPublicKey )
				actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGN, 
											   ACTION_PERM_NONE_EXTERNAL );
			usageFlags |= KEYMGMT_FLAG_USAGE_SIGN;
			}
		pgpInfo->actionFlags = actionFlags;
		pgpInfo->usageFlags = usageFlags;
		return( CRYPT_OK );
		}

	/* It's a DLP key, read the components and set the appropriate usage */
	cryptInitComponents( dlpKeyPtr, isPublicKey ? \
						 CRYPT_KEYTYPE_PUBLIC : CRYPT_KEYTYPE_PRIVATE );
	status = dlpKeyPtr->pLen = pgpReadMPI( stream, dlpKeyPtr->p );
	if( !cryptStatusError( status ) )
		if( value == PGP_ALGO_DSA )
			status = dlpKeyPtr->qLen = pgpReadMPI( stream, dlpKeyPtr->q );
		else
			/* PGP Elgamal keys are PKCS #3 rather than FIPS 186-type DLP 
			   keys and don't have a q component so we use an all-zero 
			   value of 160 bits, the FIPS 186 standard size */
			dlpKeyPtr->qLen = 160;
	if( !cryptStatusError( status ) )
		status = dlpKeyPtr->gLen = pgpReadMPI( stream, dlpKeyPtr->g );
	if( !cryptStatusError( status ) )
		status = dlpKeyPtr->yLen = pgpReadMPI( stream, dlpKeyPtr->y );
	if( cryptStatusError( status ) )
		return( status );
	if( value == PGP_ALGO_DSA )
		{
		pgpInfo->pkcAlgo = CRYPT_ALGO_DSA;
		actionFlags = MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGCHECK, 
									  ACTION_PERM_NONE_EXTERNAL );
		if( !isPublicKey )
			actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_SIGN, 
										   ACTION_PERM_NONE_EXTERNAL );
		usageFlags = KEYMGMT_FLAG_USAGE_SIGN;
		}
	else
		{
		pgpInfo->pkcAlgo = CRYPT_ALGO_ELGAMAL;
		actionFlags = MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_ENCRYPT, 
									  ACTION_PERM_NONE_EXTERNAL );
		if( !isPublicKey )
			actionFlags |= MK_ACTION_PERM( RESOURCE_MESSAGE_CTX_DECRYPT, 
										   ACTION_PERM_NONE_EXTERNAL );
		usageFlags = KEYMGMT_FLAG_USAGE_CRYPT;
		}
	pgpInfo->actionFlags = actionFlags;
	pgpInfo->usageFlags = usageFlags;
	return( CRYPT_OK );
	}

/* Read private-key components.  This gets somewhat complicated because 
   PGP 2.x encrypted only the MPI data while OpenPGP encrypts the entire 
   private key record, so for PGP 2.x we read and then decrypt, for OpenPGP
   we decrypt and then read */

static int readCachedPrivateKeyComponents( PGP_INFO *pgpInfo, 
										   const CRYPT_CONTEXT iCryptContext )
	{
	STREAM stream;
	BYTE keyBuffer[ MAX_PRIVATE_KEYSIZE ];
	WORD checkSum, packetChecksum;
	const int keyDataLength = pgpInfo->cachedKeyLength - pgpInfo->privKeyStart;
	int status;

	/* Take a local copy of the private key data for the OpenPGP case where
	   we need to decrypt the entire record */
	memcpy( keyBuffer, pgpInfo->cachedKey + pgpInfo->privKeyStart, 
			keyDataLength );

	/* If it's OpenPGP, decrypt the private key record */
	if( pgpInfo->isOpenPGP && pgpInfo->cryptAlgo != CRYPT_ALGO_NONE )
		{
		status = krnlSendMessage( iCryptContext, 
								  RESOURCE_IMESSAGE_CTX_DECRYPT,
								  keyBuffer, keyDataLength );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Read the private key components and checksum */
	sMemConnect( &stream, keyBuffer, keyDataLength );
	if( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA )
		{
		CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;

		status = rsaKeyPtr->dLen = pgpReadMPI( &stream, rsaKeyPtr->d );
		if( !cryptStatusError( status ) )
			status = rsaKeyPtr->pLen = pgpReadMPI( &stream, rsaKeyPtr->p );
		if( !cryptStatusError( status ) )
			status = rsaKeyPtr->qLen = pgpReadMPI( &stream, rsaKeyPtr->q );
		if( !cryptStatusError( status ) )
			status = rsaKeyPtr->uLen = pgpReadMPI( &stream, rsaKeyPtr->u );
		if( cryptStatusError( status ) )
			return( status );
		packetChecksum = ( sgetc( &stream ) << 8 ) | sgetc( &stream );
		}
	else
		{
		CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;

		status = dlpKeyPtr->xLen = pgpReadMPI( &stream, dlpKeyPtr->x );
		if( cryptStatusError( status ) )
			return( status );
		packetChecksum = ( sgetc( &stream ) << 8 ) | sgetc( &stream );
		}

	/* If it's PGP 2.x, decrypt the individual key fields */
	if( !pgpInfo->isOpenPGP && pgpInfo->cryptAlgo != CRYPT_ALGO_NONE )
		if( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA )
			{
			CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;

			krnlSendMessage( iCryptContext, 
							 RESOURCE_IMESSAGE_CTX_DECRYPT,
							 rsaKeyPtr->d, bitsToBytes( rsaKeyPtr->dLen ) );
			krnlSendMessage( iCryptContext, 
							 RESOURCE_IMESSAGE_CTX_DECRYPT,
							 rsaKeyPtr->p, bitsToBytes( rsaKeyPtr->pLen ) );
			krnlSendMessage( iCryptContext, 
							 RESOURCE_IMESSAGE_CTX_DECRYPT,
							 rsaKeyPtr->q, bitsToBytes( rsaKeyPtr->qLen ) );
			krnlSendMessage( iCryptContext, 
							 RESOURCE_IMESSAGE_CTX_DECRYPT,
							 rsaKeyPtr->u, bitsToBytes( rsaKeyPtr->uLen ) );
			}
		else
			{
			CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;

			krnlSendMessage( iCryptContext, 
							 RESOURCE_IMESSAGE_CTX_DECRYPT,
							 dlpKeyPtr->x, bitsToBytes( dlpKeyPtr->xLen ) );
			}

	/* Make sure all was OK */
	if( pgpInfo->pkcAlgo == CRYPT_ALGO_RSA )
		{
		CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;

		checkSum = pgpChecksumMPI( rsaKeyPtr->d, rsaKeyPtr->dLen );
		checkSum += pgpChecksumMPI( rsaKeyPtr->p, rsaKeyPtr->pLen );
		checkSum += pgpChecksumMPI( rsaKeyPtr->q, rsaKeyPtr->qLen );
		checkSum += pgpChecksumMPI( rsaKeyPtr->u, rsaKeyPtr->uLen );
		}
	else
		{
		CRYPT_PKCINFO_DLP *dlpKeyPtr = &pgpInfo->key.dlpKey;

		checkSum = pgpChecksumMPI( dlpKeyPtr->x, dlpKeyPtr->xLen );
		}
	if( checkSum != packetChecksum )
		return( ( pgpInfo->cryptAlgo != CRYPT_ALGO_NONE ) ? \
				CRYPT_ERROR_WRONGKEY : CRYPT_ERROR_BADDATA );
	
	return( CRYPT_OK );
	}

/* Read a PGP user ID.  This is somewhat more complex than a simple read 
   because OpenPGP introduced subkey packets which follow the main key and
   are (implicitly) connected to the user ID for the main key, so we have to
   keep track of whether we've already read a user ID for a main key and
   associated it with any following subkeys if necessary */

static int readUserID( PGP_INFO *pgpInfo, STREAM *stream,
					   const CRYPT_KEYID_TYPE keyIDtype, 
					   const void *keyID, const int keyIDlength,
					   const int flags )
	{
	BOOLEAN gotUserID = FALSE, foundKey = FALSE;

	/* If we're searching by key ID, check whether this is the packet we
	   want.  If it is, all we need to do is keep reading until we find a
	   user ID */
	if( ( keyIDtype == CRYPT_IKEYID_KEYID || \
		  keyIDtype == CRYPT_IKEYID_PGPKEYID ) && \
		matchKeyID( pgpInfo, keyID, keyIDlength,
					( keyIDtype == CRYPT_IKEYID_PGPKEYID ) ? TRUE : FALSE ) )
		foundKey = TRUE;

	/* Read the userID packet(s).  We also make sure we get at least one 
	   userID if we've already got a match based on a key ID */
	while( !foundKey || !gotUserID )
		{
		int ctb, length, i;

		/* Skip keyring trust and signature packets.  Packet type 61 is 
		   something odd created by GPG which might be a DSA self-signature */
		ctb = sgetc( stream );
		while( getCTB( ctb ) == PGP_PACKET_TRUST || \
			   getCTB( ctb ) == PGP_PACKET_SIGNATURE || \
			   getCTB( ctb ) == 61 )
			{
			/* Skip the packet */
			length = ( int ) pgpGetLength( stream, ctb );
			sSkip( stream, length );
			ctb = sgetc( stream );
			}

		/* We've reached the end of the current collection of key packets, 
		   exit */
		if( getCTB( ctb ) != PGP_PACKET_USERID )
			{
			sungetc( stream );

			/* If we matched the key based on its key ID and we get here then
			   either there's no user ID present or it's been carried over
			   from an earlier key */
			if( foundKey )
				{
				/* If there's no user ID present (ie this isn't a subkey with 
				   the user ID carried carried over from the main key), 
				   return a generic label */
				if( !pgpInfo->userIDset )
					strcpy( pgpInfo->userID, 
							"PGP private key (no user ID found)" );
				return( CRYPT_OK );
				}

			/* If there's a previously-read user ID present and we're
			   matching by user ID but haven't found a match in the current 
			   key packets, try a match with the previously-read ID */
			if( pgpInfo->userIDset && \
				( keyIDtype == CRYPT_KEYID_NAME || \
				  keyIDtype == CRYPT_KEYID_EMAIL ) && \
				matchSubstring( ( char * ) keyID, keyIDlength, 
								pgpInfo->userID, strlen( pgpInfo->userID ),
								pgpInfo->usageFlags, flags ) )
					return( CRYPT_OK );

			return( OK_SPECIAL );
			}

		/* Read the userID */
		length = ( int ) pgpGetLength( stream, ctb );
		for( i = 0; i < length && i < PGP_MAX_USERIDSIZE - 1; i++ )
			pgpInfo->userID[ i ] = sgetc( stream );
		pgpInfo->userID[ i ] = '\0';
		pgpInfo->userIDset = TRUE;
		if( i > length )
			sSkip( stream, i - length );/* Skip excessively long userID */
		gotUserID = TRUE;

		/* Check if it's the one we want.  If it's a key with subkeys and no 
		   usage type is explicitly specified, this will always return the 
		   main key.  This is the best solution since the main key is always 
		   a signing key which is more likely to be what the user wants.  
		   Encryption keys will typically only be accessed via envelopes, 
		   and the enveloping code can specify a preference of an 
		   encryption-capable key, while signing keys will be read directly 
		   and pushed into the envelope */
		if( ( keyIDtype == CRYPT_KEYID_NAME || \
			  keyIDtype == CRYPT_KEYID_EMAIL ) && \
			matchSubstring( ( char * ) keyID, keyIDlength, 
							pgpInfo->userID, strlen( pgpInfo->userID ),
							pgpInfo->usageFlags, flags ) )
			foundKey = TRUE;
		}
	
	return( CRYPT_OK );
	}

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

/* Read a key and check whether it matches the required user ID */

static int readKey( PGP_INFO *pgpInfo, STREAM *stream,
					const KEYMGMT_ITEM_TYPE itemType,
					const CRYPT_KEYID_TYPE keyIDtype, 
					const void *keyID, const int keyIDlength, 
					const char *password, const int passwordLength, 
					void *keyData, int *keyDataLength, const int flags )
	{
	CRYPT_CONTEXT iCryptContext;
	CRYPT_PKCINFO_RSA *rsaKeyPtr = &pgpInfo->key.rsaKey;
	HASHFUNCTION hashFunction;
	STREAM keyStream;
	BYTE hashInfo[ MAX_HASHINFO_SIZE ];
	BYTE packetHeader[ 64 ];
	BOOLEAN isPublicKey = TRUE;
	long endPos;
	int hashSize, length, value, status;

	/* If we're reading a non-cached key packet, skip the keyring headers and
	   read the key data into memory */
	if( stream != NULL )
		{
		int ctb, status;

		/* Skip CTB, packet length, and version byte.  If we're reading a new
		   primary key, we clear the userID */
		ctb = sgetc( stream );
		switch( getCTB( ctb ) )
			{
			case PGP_PACKET_SECKEY:
				pgpInfo->userIDset = FALSE;
				/* Fall through */
			case PGP_PACKET_SECKEY_SUB:
				isPublicKey = FALSE;
				break;

			case PGP_PACKET_PUBKEY:
				pgpInfo->userIDset = FALSE;
				/* Fall through */
			case PGP_PACKET_PUBKEY_SUB:
				break;

			default:
				return( cryptStatusError( ctb ) ? \
						CRYPT_ERROR_NOTFOUND : CRYPT_ERROR_BADDATA );
			}
		length = ( int ) pgpGetLength( stream, ctb );
		endPos = ( int ) stell( stream ) + length;
		value = sgetc( stream );
		if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
			value != PGP_VERSION_OPENPGP )
			{
			/* Unknown version number, skip this packet */
			skipToKeyPacket( stream, endPos );
			return( OK_SPECIAL );
			}
		length -= 1 + 4;

⌨️ 快捷键说明

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