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

📄 pgp_denv.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					 cryptlib PGP De-enveloping Routines					*
*					 Copyright Peter Gutmann 1996-2008						*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "envelope.h"
  #include "pgp_rw.h"
#else
  #include "envelope/envelope.h"
  #include "misc/pgp_rw.h"
#endif /* Compiler-specific includes */

#ifdef USE_PGP

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

/* Sanity-check the envelope state */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN sanityCheck( const ENVELOPE_INFO *envelopeInfoPtr )
	{
	/* Make sure that general envelope state is in order */
	if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
		return( FALSE );
	if( envelopeInfoPtr->pgpDeenvState < PGP_DEENVSTATE_NONE || \
		envelopeInfoPtr->pgpDeenvState >= PGP_DEENVSTATE_LAST )
		return( FALSE );

	/* Make sure that the buffer position is within bounds */
	if( envelopeInfoPtr->buffer == NULL || \
		envelopeInfoPtr->bufPos < 0 || \
		envelopeInfoPtr->bufPos > envelopeInfoPtr->bufSize || \
		envelopeInfoPtr->bufSize < MIN_BUFFER_SIZE || \
		envelopeInfoPtr->bufSize >= MAX_INTLENGTH )
		return( FALSE );

	/* Make sure that the payload size is within bounds */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED && \
		( envelopeInfoPtr->payloadSize < 0 || \
		  envelopeInfoPtr->payloadSize >= MAX_INTLENGTH ) )
		return( FALSE );

	/* Make sure that the out-of-band buffer state is OK.  The oobDataLeft 
	   value is the general size of a data packet header plus the maximum 
	   possible length for the variable-length filename portion */
	if( envelopeInfoPtr->oobEventCount < 0 || \
		envelopeInfoPtr->oobEventCount > 10 || \
		envelopeInfoPtr->oobDataLeft < 0 || \
		envelopeInfoPtr->oobDataLeft >= 32 + 256 )
		return( FALSE );

	/* Make sure that the packet data information is within bounds */
	if( envelopeInfoPtr->segmentSize < 0 || \
		envelopeInfoPtr->segmentSize >= MAX_INTLENGTH || \
		envelopeInfoPtr->dataLeft < 0 || \
		envelopeInfoPtr->dataLeft >= MAX_INTLENGTH )
		return( FALSE );

	return( TRUE );
	}

/* Get information on a PGP data packet.  If the isIndefinite value is 
   present then an indefinite length (i.e. partial packet lengths) is 
   permitted, otherwise it isn't.  If the allowDummyPackets flag is set then
   we allow shorter-than-normal dummy packets (PGP_PACKET_MARKER), otherwise
   we enforce a sensible minimum packet size */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
static int getPacketInfo( INOUT STREAM *stream, 
						  INOUT ENVELOPE_INFO *envelopeInfoPtr,
						  OUT_ENUM_OPT( PGP_PACKET ) PGP_PACKET_TYPE *packetType, 
						  OUT_LENGTH_Z long *length, 
						  OUT_OPT_BOOL BOOLEAN *isIndefinite,
						  IN_LENGTH_SHORT int minPacketSize )
	{
	int ctb, version, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( isWritePtr( packetType, sizeof( PGP_PACKET_TYPE ) ) );
	assert( isWritePtr( length, sizeof( long ) ) );
	assert( isIndefinite == NULL || \
			isWritePtr( isIndefinite, sizeof( BOOLEAN ) ) );

	ENSURES( minPacketSize > 0 && minPacketSize < MAX_INTLENGTH_SHORT );

	/* Clear return values */
	*packetType = PGP_PACKET_NONE;
	*length = 0;
	if( isIndefinite != NULL )
		*isIndefinite = FALSE;

	/* Read the packet header and extract information from the CTB.  The 
	   assignment of version numbers is a bit complicated since it's 
	   possible to use PGP 2.x packet headers to wrap up OpenPGP packets, 
	   and in fact a number of apps mix version numbers.  We treat the 
	   version to report as the highest one that we find */
	if( isIndefinite != NULL )
		status = pgpReadPacketHeaderI( stream, &ctb, length, minPacketSize );
	else
		status = pgpReadPacketHeader( stream, &ctb, length, minPacketSize );
	if( cryptStatusError( status ) )
		{
		if( status != OK_SPECIAL )
			return( status );
		ENSURES( isIndefinite != NULL );

		/* Remember that the packet uses an indefinite-length encoding */
		envelopeInfoPtr->dataFlags &= ~ENVDATA_NOSEGMENT;
		*isIndefinite = TRUE;
		}
	version = pgpGetPacketVersion( ctb );
	if( version > envelopeInfoPtr->version )
		envelopeInfoPtr->version = version;
	*packetType = pgpGetPacketType( ctb );

	/* Extract and return the packet type */
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Read Key Exchange/Signature Packets					*
*																			*
****************************************************************************/

/* Add information about an object to an envelope's content information list */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int addContentListItem( INOUT ENVELOPE_INFO *envelopeInfoPtr,
							   INOUT_OPT STREAM *stream,
							   const BOOLEAN isContinuedSignature )
	{
	QUERY_INFO queryInfo;
	CONTENT_LIST *contentListItem;
	void *object = NULL;
	int objectSize = 0, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( ( stream == NULL && \
			  envelopeInfoPtr->actionList == NULL && \
			  envelopeInfoPtr->contentList == NULL ) || \
			isWritePtr( stream, sizeof( STREAM ) ) );

	REQUIRES( ( stream == NULL && \
				envelopeInfoPtr->actionList == NULL && \
				envelopeInfoPtr->contentList == NULL ) || \
			  ( stream != NULL ) );

	/* Make sure that there's room to add another list item */
	if( !moreContentItemsPossible( envelopeInfoPtr->contentList ) )
		return( CRYPT_ERROR_OVERFLOW );

	/* PGP 2.x password-encrypted data is detected by the absence of any
	   other keying object rather than by finding a concrete object type so
	   if we're passed a null stream we add a password pseudo-object */
	if( stream == NULL )
		{
		CONTENT_ENCR_INFO *encrInfo;

		status = createContentListItem( &contentListItem, 
										envelopeInfoPtr->memPoolState,
										CRYPT_FORMAT_PGP, NULL, 0, FALSE );
		if( cryptStatusError( status ) )
			return( status );
		encrInfo = &contentListItem->clEncrInfo;
		contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
		encrInfo->cryptAlgo = CRYPT_ALGO_IDEA;
		encrInfo->cryptMode = CRYPT_MODE_CFB;
		encrInfo->keySetupAlgo = CRYPT_ALGO_MD5;
		appendContentListItem( envelopeInfoPtr, contentListItem );
		return( CRYPT_OK );
		}

	/* Find the size of the object, allocate a buffer for it if necessary,
	   and copy it across.  This call verifies that all of the object data 
	   is present in the stream so in theory we don't have to check the 
	   following reads, but we check them anyway just to be sure */
	status = queryPgpObject( stream, &queryInfo );
	if( cryptStatusError( status ) )
		return( status );
	if( queryInfo.type == CRYPT_OBJECT_SIGNATURE && \
		queryInfo.dataStart <= 0 )
		{
		ENSURES( !isContinuedSignature );

		/* It's a one-pass signature packet, the signature information 
		   follows in another packet that will be added later */
		status = sSkip( stream, ( int ) queryInfo.size );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		{
		objectSize = ( int ) queryInfo.size;
		if( ( object = clAlloc( "addContentListItem", objectSize ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		status = sread( stream, object, objectSize );
		if( cryptStatusError( status ) )
			{
			clFree( "addContentListItem", object );
			return( status );
			}
		}

	/* If it's the rest of the signature data from a one-pass signature,
	   locate the first half of the signature info and complete the
	   information.  In theory this could get ugly because there could be
	   multiple one-pass signature packets present but PGP handles multiple 
	   signatures by nesting them so this isn't a problem */
	if( isContinuedSignature )
		{
		int iterationCount;
		
		for( contentListItem = envelopeInfoPtr->contentList, \
				iterationCount = 0;
			 contentListItem != NULL && \
				contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE && \
				iterationCount < FAILSAFE_ITERATIONS_MED;
			 contentListItem = contentListItem->next, iterationCount++ );
		ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
		ENSURES( contentListItem != NULL && \
				 contentListItem->object == NULL && \
				 contentListItem->objectSize == 0 );

		/* Consistency check, make sure that the hash algorithm and key ID 
		   that we've been working with match what's in the signature */
		if( contentListItem->clSigInfo.hashAlgo != queryInfo.hashAlgo || \
			contentListItem->keyIDsize != queryInfo.keyIDlength || \
			memcmp( contentListItem->keyID, queryInfo.keyID, 
					queryInfo.keyIDlength ) )
			{
			clFree( "addContentListItem", object );
			return( CRYPT_ERROR_BADDATA );
			}

		/* We've got the right content list entry, point it to the newly-
		   acquired signature data */
		contentListItem->object = object;
		contentListItem->objectSize = objectSize;
		}
	else
		{
		/* Allocate memory for the new content list item and copy information
		   on the item across */
		status = createContentListItem( &contentListItem, 
							envelopeInfoPtr->memPoolState, 
							CRYPT_FORMAT_PGP, object, objectSize,
							( queryInfo.type == CRYPT_OBJECT_SIGNATURE ) ? \
								TRUE : FALSE );
		if( cryptStatusError( status ) )
			{
			if( object != NULL )
				clFree( "addContentListItem", object );
			return( status );
			}
		}
	if( queryInfo.type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
		queryInfo.type == CRYPT_OBJECT_SIGNATURE )
		{
		/* Remember details of the enveloping info that we require to 
		   continue */
		if( queryInfo.type == CRYPT_OBJECT_PKCENCRYPTED_KEY )
			{
			CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;

			contentListItem->envInfo = CRYPT_ENVINFO_PRIVATEKEY;
			encrInfo->cryptAlgo = queryInfo.cryptAlgo;
			}
		else
			{
			CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;

			contentListItem->envInfo = CRYPT_ENVINFO_SIGNATURE;
			sigInfo->hashAlgo = queryInfo.hashAlgo;
			if( queryInfo.attributeStart > 0 )
				{
				REQUIRES( rangeCheck( queryInfo.attributeStart, 
									  queryInfo.attributeLength, 
									  objectSize ) );
				sigInfo->extraData = \
								( BYTE * ) contentListItem->object + \
										   queryInfo.attributeStart;
				sigInfo->extraDataLength = queryInfo.attributeLength;
				}
			if( queryInfo.unauthAttributeStart > 0 )
				{
				REQUIRES( rangeCheck( queryInfo.unauthAttributeStart, 
									  queryInfo.unauthAttributeLength, 
									  objectSize ) );
				sigInfo->extraData2 = \
								( BYTE * ) contentListItem->object + \
										   queryInfo.unauthAttributeStart;
				sigInfo->extraData2Length = queryInfo.unauthAttributeLength;
				}
			}
		REQUIRES( queryInfo.keyIDlength > 0 && \
				  queryInfo.keyIDlength <= CRYPT_MAX_HASHSIZE );
		memcpy( contentListItem->keyID, queryInfo.keyID, 
				queryInfo.keyIDlength );
		contentListItem->keyIDsize = queryInfo.keyIDlength;
		if( queryInfo.iAndSStart > 0 )
			{
			REQUIRES( rangeCheck( queryInfo.iAndSStart, 
								  queryInfo.iAndSLength, objectSize ) );
			contentListItem->issuerAndSerialNumber = \
				( BYTE * ) contentListItem->object + queryInfo.iAndSStart;
			contentListItem->issuerAndSerialNumberSize = queryInfo.iAndSLength;
			}
		}
	if( queryInfo.type == CRYPT_OBJECT_ENCRYPTED_KEY )
		{
		CONTENT_ENCR_INFO *encrInfo = &contentListItem->clEncrInfo;

		/* Remember details of the enveloping info that we require to 
		   continue */
		if( queryInfo.keySetupAlgo != CRYPT_ALGO_NONE )
			{
			contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
			encrInfo->keySetupAlgo = queryInfo.keySetupAlgo;
			encrInfo->keySetupIterations = queryInfo.keySetupIterations;
			REQUIRES( queryInfo.saltLength > 0 && \
					  queryInfo.saltLength <= CRYPT_MAX_IVSIZE );
			memcpy( encrInfo->saltOrIV, queryInfo.salt, 
					queryInfo.saltLength );
			encrInfo->saltOrIVsize = queryInfo.saltLength;
			}
		else
			contentListItem->envInfo = CRYPT_ENVINFO_KEY;
		encrInfo->cryptAlgo = queryInfo.cryptAlgo;
		encrInfo->cryptMode = CRYPT_MODE_CFB;
		}
	if( queryInfo.dataStart > 0 )
		{
		REQUIRES( rangeCheck( queryInfo.dataStart, queryInfo.dataLength, 
							  objectSize ) );
		contentListItem->payload = \
			( BYTE * ) contentListItem->object + queryInfo.dataStart;
		contentListItem->payloadSize = queryInfo.dataLength;
		}
	if( queryInfo.version > envelopeInfoPtr->version )
		envelopeInfoPtr->version = queryInfo.version;

	/* If we're completing the read of the data in a one-pass signature
	   packet, we're done */
	if( isContinuedSignature )
		return( CRYPT_OK );

	/* If it's signed data, create a hash action to process it.  Because PGP 
	   only applies one level of signing per packet nesting level we don't 
	   have to worry that this will add redundant hash actions as there'll 
	   only ever be one */
	if( queryInfo.type == CRYPT_OBJECT_SIGNATURE )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;

		REQUIRES( moreActionsPossible( envelopeInfoPtr->actionList ) );

		/* Append a new hash action to the action list */
		setMessageCreateObjectInfo( &createInfo,
									contentListItem->clSigInfo.hashAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,

⌨️ 快捷键说明

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