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

📄 pgp_denv.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
								  IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
								  OBJECT_TYPE_CONTEXT );
		if( cryptStatusError( status ) )
			{
			deleteContentList( envelopeInfoPtr->memPoolState, 
							   &contentListItem );
			return( status );
			}
		status = addAction( &envelopeInfoPtr->actionList, 
							envelopeInfoPtr->memPoolState, ACTION_HASH,
							createInfo.cryptHandle );
		if( cryptStatusError( status ) )
			{
			krnlSendNotifier( createInfo.cryptHandle, 
							  IMESSAGE_DECREFCOUNT );
			deleteContentList( envelopeInfoPtr->memPoolState, 
							   &contentListItem );
			return( status );
			}
		}
	appendContentListItem( envelopeInfoPtr, contentListItem );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Header Processing Routines						*
*																			*
****************************************************************************/

/* Process the header of a packet */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int processPacketHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr, 
								INOUT STREAM *stream, 
								INOUT_ENUM( PGP_DEENVSTATE ) \
									PGP_DEENV_STATE *state )
	{
	const int streamPos = stell( stream );
	PGP_PACKET_TYPE packetType;
	BOOLEAN isIndefinite;
	long packetLength;
	int value, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( state, sizeof( PGP_DEENV_STATE ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* Read the PGP packet type and figure out what we've got.  If we're at
	   the start of the data we allow noise packets like PGP_PACKET_MARKER
	   (with a length of 3), otherwise we only allow standard packets */
	status = getPacketInfo( stream, envelopeInfoPtr, &packetType, 
							&packetLength, &isIndefinite,
							( *state == PGP_DEENVSTATE_NONE ) ? 3 : 8 );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, ENVELOPE_ERRINFO,
				  "Invalid PGP packet header" ) );
		}

	/* Process as much of the header as we can and move on to the next state.  
	   Since PGP uses sequential discrete packets, if we encounter any of 
	   the non-payload packet types we stay in the initial "none" state 
	   because we don't know what's next */
	switch( packetType )
		{
		case PGP_PACKET_DATA:
			{
			int length;

			/* Skip the content-type, filename, and date */
			sSkip( stream, 1 );
			status = length = sgetc( stream );
			if( !cryptStatusError( status ) )
				status = sSkip( stream, length + 4 );
			if( cryptStatusError( status ) )
				{
				retExt( status,
						( status, ENVELOPE_ERRINFO,
						  "Invalid PGP data packet start" ) );
				}

			/* Remember that this is a pure data packet, record the content 
			   length (if we have the necessary information), and move on to 
			   the payload */
			envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
			if( !isIndefinite )
				{
				const long payloadSize = \
					packetLength - ( 1 + 1 + length + 4 );
				if( payloadSize < 1 || payloadSize > MAX_INTLENGTH )
					return( CRYPT_ERROR_BADDATA );
				envelopeInfoPtr->payloadSize = payloadSize;
				}
			*state = PGP_DEENVSTATE_DATA;
			break;
			}

		case PGP_PACKET_COPR:
			if( envelopeInfoPtr->usage != ACTION_NONE )
				return( CRYPT_ERROR_BADDATA );
			envelopeInfoPtr->usage = ACTION_COMPRESS;
#ifdef USE_COMPRESSION
			value = sgetc( stream );
			if( cryptStatusError( value ) )
				return( value );
			switch( value )
				{
				case PGP_ALGO_ZIP:
					/* PGP 2.x has a funny compression level based on DOS 
					   memory limits (13-bit windows) and no zlib header 
					   (because it uses very old InfoZIP code).  Setting the 
					   windowSize to a negative value has the undocumented 
					   effect of not reading zlib headers */
					if( inflateInit2( &envelopeInfoPtr->zStream, -13 ) != Z_OK )
						return( CRYPT_ERROR_MEMORY );
					break;

				case PGP_ALGO_ZLIB:
					/* Standard zlib compression */
					if( inflateInit( &envelopeInfoPtr->zStream ) != Z_OK )
						return( CRYPT_ERROR_MEMORY );
					break;

				default:
					return( CRYPT_ERROR_NOTAVAIL );
				}
			envelopeInfoPtr->flags |= ENVELOPE_ZSTREAMINITED;
			if( packetLength != CRYPT_UNUSED )
				{
				const long payloadSize = packetLength - 1;

				/* Most implementations use the PGP 2.x "keep going until 
				   you run out of data" non-length encoding that's neither
				   a definite- nor an indefinite length, but it's possible
				   that something somewhere will use a proper definite 
				   length so we accomodate this here */
				if( payloadSize < 1 || payloadSize > MAX_INTLENGTH )
					return( CRYPT_ERROR_BADDATA );
				envelopeInfoPtr->payloadSize = payloadSize;
				}
			else
				{
				/* Remember that we have no length information available for 
				   the payload */
				envelopeInfoPtr->dataFlags |= ENVDATA_NOLENGTHINFO;
				}
			*state = PGP_DEENVSTATE_DATA;
			break;
#else
			return( CRYPT_ERROR_NOTAVAIL );
#endif /* USE_COMPRESSION */

		case PGP_PACKET_SKE:
		case PGP_PACKET_PKE:
			/* Read the SKE/PKE packet */
			if( envelopeInfoPtr->usage != ACTION_NONE && \
				envelopeInfoPtr->usage != ACTION_CRYPT )
				return( CRYPT_ERROR_BADDATA );
			envelopeInfoPtr->usage = ACTION_CRYPT;
			sseek( stream, streamPos );	/* Reset to start of packet */
			status = addContentListItem( envelopeInfoPtr, stream, FALSE );
			if( cryptStatusError( status ) )
				{
				retExt( status,
						( status, ENVELOPE_ERRINFO,
						  "Invalid PGP %s packet", 
						  ( packetType == PGP_PACKET_SKE ) ? "SKE" : "PKE" ) );
				}
			break;

		case PGP_PACKET_SIGNATURE:
		case PGP_PACKET_SIGNATURE_ONEPASS:
			/* Try and guess whether this is a standalone signature.  This 
			   is rather difficult since unlike S/MIME there's no way to 
			   tell whether a PGP signature packet is part of other data or 
			   a standalone item.  The best that we can do is assume that if 
			   the caller added a hash action and we find a signature then 
			   it's a detached signature.  Unfortunately there's no way to 
			   tell whether a signature packet with no user-supplied hash is 
			   a standalone signature or the start of further signed data so 
			   we can't handle detached signatures where the user doesn't 
			   supply the hash */
			if( envelopeInfoPtr->usage == ACTION_SIGN && \
				envelopeInfoPtr->actionList != NULL && \
				envelopeInfoPtr->actionList->action == ACTION_HASH )
				{
				/* We can't have a detached signature packet as a one-pass 
				   signature */
				if( packetType == PGP_PACKET_SIGNATURE_ONEPASS )
					{
					retExt( CRYPT_ERROR_BADDATA,
							( CRYPT_ERROR_BADDATA, ENVELOPE_ERRINFO,
							  "PGP detached signature can't be a one-pass "
							  "signature packet" ) );
					}
				envelopeInfoPtr->flags |= ENVELOPE_DETACHED_SIG;
				}

			/* Read the signature/signature information packet.  We allow 
			   the usage to be set already if we find a signature packet 
			   since it could have been preceded by a one-pass signature 
			   packet or be a detached signature */
			if( envelopeInfoPtr->usage != ACTION_NONE && \
				!( packetType == PGP_PACKET_SIGNATURE && \
				   envelopeInfoPtr->usage == ACTION_SIGN ) )
				return( CRYPT_ERROR_BADDATA );
			envelopeInfoPtr->usage = ACTION_SIGN;
			sseek( stream, streamPos );	/* Reset to start of packet */
			status = addContentListItem( envelopeInfoPtr, stream, FALSE );
			if( cryptStatusError( status ) )
				{
				retExt( status,
						( status, ENVELOPE_ERRINFO,
						  "Invalid PGP %s signature packet",
						  ( packetType == PGP_PACKET_SIGNATURE_ONEPASS ) ? \
							"one-pass" : "" ) );
				}
			if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
				{
				/* If it's a one-pass signature there's no payload present 
				   so we can go straight to the postdata state */
				envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
				envelopeInfoPtr->payloadSize = 0;
				*state = PGP_DEENVSTATE_DONE;
				}
			else
				*state = PGP_DEENVSTATE_DATA;
			break;

		case PGP_PACKET_ENCR_MDC:
			/* The encrypted-data-with-MDC packet is preceded by a version 
			   number */
			status = value = sgetc( stream );
			if( !cryptStatusError( status ) && value != 1 )
				status = CRYPT_ERROR_BADDATA;
			if( !cryptStatusError( status ) )
				{
				/* Adjust the length for the version number and make sure 
				   that what's left is valid.  In theory this check isn't
				   necessary because getPacketInfo() has enforced a minimum
				   length, but we do it anyway just to be sure */
				packetLength--;
				if( packetLength <= 0 || packetLength > MAX_INTLENGTH )
					status = CRYPT_ERROR_BADDATA;
				}
			if( cryptStatusError( status ) )
				{
				retExt( status,
						( status, ENVELOPE_ERRINFO,
						  "Invalid MDC packet header" ) );
				}
			/* Fall through */

		case PGP_PACKET_ENCR:
			if( envelopeInfoPtr->usage != ACTION_NONE && \
				envelopeInfoPtr->usage != ACTION_CRYPT )
				return( CRYPT_ERROR_BADDATA );
			if( !isIndefinite )
				envelopeInfoPtr->payloadSize = packetLength;
			envelopeInfoPtr->usage = ACTION_CRYPT;
			*state = ( packetType == PGP_PACKET_ENCR_MDC ) ? \
					 PGP_DEENVSTATE_ENCR_MDC : PGP_DEENVSTATE_ENCR;
			break;

		case PGP_PACKET_MARKER:
			/* Obsolete marker packet, skip it */
			return( sSkip( stream, packetLength ) );
		
		default:
			/* Unrecognised/invalid packet type */
			retExt( CRYPT_ERROR_BADDATA,
					( CRYPT_ERROR_BADDATA, ENVELOPE_ERRINFO,
					  "Unrecognised PGP packet type %d", packetType ) );
		}

	ENSURES( sanityCheck( envelopeInfoPtr ) );

	return( CRYPT_OK );
	}

/* PGP doesn't provide any indication of what the content of the packet's 
   encrypted payload is so we have to burrow down into the encrypted data to 
   see whether the payload needs any further processing.  To do this we look 
   ahead into the data to see whether we need to strip the header (for a 
   plain data packet) or inform the user that there's a nested content type.  
   This process is complicated by the fact that there are various ways of 
   representing the length information for both outer and inner packets and 
   the fact that the payload can consist of more than one packet, but we're 
   really only interested in the first one in most cases.  The calculation 
   of the encapsulated payload length is as follows:

	+---+---+............................................
	|len|hdr|											: Encrypted data
	+---+---+............................................
			:											:
			+---+---+-------------------------------+---+
			|len|hdr|			Payload				| ? | Inner content
			+---+---+-------------------------------+---+

   Definite payload length:
		Payload = (inner) length - (inner) hdr.

   Unknown length (only allowed for compressed data): 
		Payload = (leave as is since by definition the compressed data 
				   extends to EOF).

   Indefinite payload length: 
		Payload = to EOC, handled by decode.c routines */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int processPacketDataHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr,
									OUT_ENUM_OPT( PGP_DEENVSTATE ) \
										PGP_DEENV_STATE *state )
	{
	static const MAP_TABLE typeMapTbl[] = {
		{ PGP_PACKET_COPR, CRYPT_CONTENT_COMPRESSEDDATA },
		{ PGP_PACKET_ENCR, CRYPT_CONTENT_ENCRYPTEDDATA },
		{ PGP_PACKET_ENCR_MDC, CRYPT_CONTENT_ENCRYPTEDDATA },
		{ PGP_PACKET_SKE, CRYPT_CONTENT_ENCRYPTEDDATA },
		{ PGP_PACKET_PKE, CRYPT_CONTENT_ENVELOPEDDATA },
		{ PGP_PACKET_SIGNATURE, CRYPT_CONTENT_SIGNEDDATA },
		{ PGP_PACKET_SIGNATURE_ONEPASS, CRYPT_CONTENT_SIGNEDDATA },
		{ CRYPT_ERROR, CRYPT_ERROR }, { CRYPT_ERROR, CRYPT_ERROR }
		};
	STREAM headerStream;
	BYTE buffer[ 32 + 256 + 8 ];	/* Max.data packet header size */
	PGP_PACKET_TYPE packetType;
	long packetLength;
	int value, length, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	assert( isWritePtr( state, sizeof( PGP_DEENV_STATE ) ) );
	
	REQUIRES( sanityCheck( envelopeInfoPtr ) );
	REQUIRES( envelopeInfoPtr->oobDataLeft < 32 + 256 );

	/* If we're down to stripping raw header data, remove it from the buffer
	   and exit */
	if( envelopeInfoPtr->oobEventCount <= 0 )
		{
		status = envelopeInfoPtr->copyFromEnvelopeFunction( envelopeInfoPtr,
										buffer, envelopeInfoPtr->oobDataLeft, 
										&length, ENVCOPY_FLAG_NONE );
		if( cryptStatusError( status ) )
			return( status );
		if( length < envelopeInfoPtr->oobDataLeft )
			return( CRYPT_ERROR_UNDERFLOW );

		/* We've successfully stripped all of the out-of-band data, clear the
		   data counter.  If it's compressed data (which doesn't have a 1:1 
		   correspondence between input and output and which has an unknown-
		   length encoding so there's no length information to adjust), 
		   exit */
		envelopeInfoPtr->oobDataLeft = 0;
		if( envelopeInfoPtr->usage == ACTION_COMPRESS )
			{
			*state = PGP_DEENVSTATE_DONE;

			ENSURES( sanityCheck( envelopeInfoPtr ) );

			return( CRYPT_OK );
			}

		/* Adjust the current data count by what we've removed.  The reason 

⌨️ 快捷键说明

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