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

📄 pgp_denv.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
	if( envelopeInfoPtr->dataLeft == PGP_MDC_PACKET_SIZE )
		{
		BYTE buffer[ PGP_MDC_PACKET_SIZE + 8 ];
		int length;

		assert( DEBUG_WARN );

		status = envelopeInfoPtr->copyFromEnvelopeFunction( envelopeInfoPtr, 
										buffer, PGP_MDC_PACKET_SIZE, &length,
										ENVCOPY_FLAG_NONE );
		if( cryptStatusError( status ) )
			return( status );
		if( length < PGP_MDC_PACKET_SIZE || \
			buffer[ 0 ] != 0xD0 || buffer[ 1 ] != 0x14 )
			return( CRYPT_ERROR_BADDATA );

		/* Hash the trailer bytes (the start of the MDC packet) and wrap up 
		   the hashing */
		status = envelopeInfoPtr->processExtraData( envelopeInfoPtr, 
													buffer + 2,
													PGP_MDC_PACKET_SIZE - 2 );
		if( cryptStatusOK( status ) )
			status = envelopeInfoPtr->processExtraData( envelopeInfoPtr, 
														"", 0 );
		if( cryptStatusError( status ) )
			return( status );
		}

	ENSURES( sanityCheck( envelopeInfoPtr ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Process Envelope Preamble/Postamble					*
*																			*
****************************************************************************/

/* Process the non-data portions of a PGP message.  This is a complex event-
   driven state machine, but instead of reading along a (hypothetical
   Turing-machine) tape someone has taken the tape and cut it into bits and
   keeps feeding them to us and saying "See what you can do with this" (and
   occasionally "Where's the bloody spoons?").  Since PGP uses sequential
   discrete packets rather than the nested objects encountered in the ASN.1-
   encoded data format the parsing code is made slightly simpler because
   (for example) the PKC info is just an unconnected sequence of packets
   rather than a SEQUENCE or SET OF as for cryptlib and PKCS #7/CMS.  OTOH 
   since there's no indication of what's next we have to perform a complex
   lookahead to see what actions we have to take once we get to the payload.
   The end result is that teh code is actually vastly more complex than the
   CMS equivalent */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int processPreamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	PGP_DEENV_STATE state = envelopeInfoPtr->pgpDeenvState;
	STREAM stream;
	int remainder, streamPos = 0, iterationCount = 0, status = CRYPT_OK;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If we've finished processing the start of the message, header, don't
	   do anything */
	if( state == PGP_DEENVSTATE_DONE )
		return( CRYPT_OK );

	sMemConnect( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufPos );

	/* Keep consuming information until we run out of input or reach the
	   plaintext data packet */
	while( state != PGP_DEENVSTATE_DONE && \
		   iterationCount++ < FAILSAFE_ITERATIONS_MED )
		{
		/* Read the PGP packet type and figure out what we've got */
		if( state == PGP_DEENVSTATE_NONE )
			{
			status = processPacketHeader( envelopeInfoPtr, &stream, &state );
			if( cryptStatusError( status ) )
				break;

			/* Remember how far we got */
			streamPos = stell( &stream );
			}

		/* Process the start of an encrypted data packet */
		if( state == PGP_DEENVSTATE_ENCR || \
			state == PGP_DEENVSTATE_ENCR_MDC )
			{
			status = processEncryptedPacket( envelopeInfoPtr, &stream, state );
			if( cryptStatusError( status ) )
				{
				/* If it's a resource-needed status then it's not an 
				   error */
				if( status == CRYPT_ENVELOPE_RESOURCE )
					break;

				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid PGP encrypted data packet header", 
								40 );
				break;
				}

			/* Remember where we are and move on to the next state */
			streamPos = stell( &stream );
			state = PGP_DEENVSTATE_DATA;
			}

		/* Process the start of a data packet */
		if( state == PGP_DEENVSTATE_DATA )
			{
			const int originalDataFlags = envelopeInfoPtr->dataFlags;

			/* Synchronise the data stream processing to the start of the
			   encapsulated data.  This is made somewhat complex by PGP's
			   awkward packet format (see the comment for 
			   processPacketDataHeader()) which, unlike CMS:

				[ Hdr [ Encaps [ Octet String ] ] ]

			   has:
						   [ Hdr | Octet String ]
				  [ Keyex ][ Hdr | Octet String ]
				[ Onepass ][ Hdr | Octet String ][ Signature ]
				   [ Copr ][ Hdr | Octet String ]

			   This means that if we're not processing a data packet then 
			   the content isn't the payload but a futher set of discrete 
			   packets that we don't want to touch.  To work around this we 
			   temporarily set the ENVDATA_NOLENGTHINFO flag to indicate 
			   that it's a blob to be processed as an opaque unit, at the 
			   same time temporarily clearing any other flags that might 
			   mess up the opaque-blob handling */
			if( envelopeInfoPtr->usage != ACTION_NONE )
				envelopeInfoPtr->dataFlags = ENVDATA_NOLENGTHINFO;
			status = envelopeInfoPtr->syncDeenvelopeData( envelopeInfoPtr,
														  &stream );
			envelopeInfoPtr->dataFlags = originalDataFlags;
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Couldn't synchronise envelope state prior "
								"to data payload processing", 68 );
				break;
				}
			streamPos = 0;

			/* Move on to the next state.  For plain data we're done,
			   however for other content types we have to either process or
			   strip out the junk that PGP puts at the start of the 
			   content */
			if( envelopeInfoPtr->usage != ACTION_NONE )
				{
				envelopeInfoPtr->oobEventCount = 1;
				state = PGP_DEENVSTATE_DATA_HEADER;
				}
			else
				state = PGP_DEENVSTATE_DONE;
			
			ENSURES( checkActions( envelopeInfoPtr ) );
			}

		/* Burrow down into the encapsulated data to see what's next */
		if( state == PGP_DEENVSTATE_DATA_HEADER )
			{
			/* If there's no out-of-band data left to remove at the start of
			   the payload, we're done.  This out-of-band data handling 
			   sometimes requires two passes, the first time through 
			   oobEventCount is nonzero because it's been set in the 
			   preceding PGP_DEENVSTATE_DATA state and we fall through to 
			   processPacketDataHeader() which decrements the oobEventCount
			   to zero.  However processPacketDataHeader() may need to read 
			   out-of-band data in which case on the second time around 
			   oobDataLeft will be nonzero, resulting in a second call to
			   processPacketDataHeader() to clear the remaining out-of-band
			   data */
			if( envelopeInfoPtr->oobEventCount <= 0 && \
				envelopeInfoPtr->oobDataLeft <= 0 )
				{
				state = PGP_DEENVSTATE_DONE;
				break;
				}

			/* Process the encapsulated data header */
			status = processPacketDataHeader( envelopeInfoPtr, &state );
			if( cryptStatusError( status ) )
				{
				setErrorString( ENVELOPE_ERRINFO, 
								"Invalid PGP encapsulated content header", 
								39 );
				break;
				}
			}
		}
	sMemDisconnect( &stream );
	if( iterationCount >= FAILSAFE_ITERATIONS_MED )
		{
		/* Technically this would be an overflow but that's a recoverable
		   error so we make it a BADDATA, which is really what it is */
		return( CRYPT_ERROR_BADDATA );
		}
	envelopeInfoPtr->pgpDeenvState = state;

	ENSURES( streamPos >= 0 && streamPos < MAX_INTLENGTH && \
			 envelopeInfoPtr->bufPos - streamPos >= 0 );

	/* Consume the input that we've processed so far by moving everything 
	   past the current position down to the start of the envelope buffer */
	remainder = envelopeInfoPtr->bufPos - streamPos;
	REQUIRES( remainder >= 0 && remainder < MAX_INTLENGTH && \
			  streamPos + remainder <= envelopeInfoPtr->bufSize );
	if( remainder > 0 && streamPos > 0 )
		{
		memmove( envelopeInfoPtr->buffer, envelopeInfoPtr->buffer + streamPos,
				 remainder );
		}
	envelopeInfoPtr->bufPos = remainder;
	ENSURES( sanityCheck( envelopeInfoPtr ) );
	if( cryptStatusError( status ) )
		return( status );

	/* If all went OK but we're still not out of the header information,
	   return an underflow error */
	return( ( state != PGP_DEENVSTATE_DONE ) ? \
			CRYPT_ERROR_UNDERFLOW : CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int processPostamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	CONTENT_LIST *contentListPtr;
	const BOOLEAN hasMDC = \
			( envelopeInfoPtr->usage == ACTION_CRYPT && \
			  ( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE ) ) ? \
			TRUE : FALSE;
	int iterationCount, status = CRYPT_OK;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	
	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If that's all there is, return */
	if( envelopeInfoPtr->usage != ACTION_SIGN && !hasMDC )
		return( CRYPT_OK );

	/* If there's an MDC packet present complete the hashing and make sure
	   that the integrity check matches */
	if( hasMDC )
		{
		status = processMDC( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			{
			retExt( status,
					( status, ENVELOPE_ERRINFO,
					  "Invalid MDC packet data" ) );
			}
		
		return( CRYPT_OK );
		}

	/* Find the signature information in the content list.  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 */
	for( contentListPtr = envelopeInfoPtr->contentList, iterationCount = 0;
		 contentListPtr != NULL && \
			contentListPtr->envInfo != CRYPT_ENVINFO_SIGNATURE && \
			iterationCount < FAILSAFE_ITERATIONS_MED;
		 contentListPtr = contentListPtr->next, iterationCount++ );
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
	ENSURES( contentListPtr != NULL );

	/* PGP 2.x prepended (!!) signatures to the signed data, OpenPGP fixed 
	   this by splitting the signature into a header with signature info and 
	   a trailer with the actual signature.  If we're processing a PGP 2.x
	   signature we'll already have the signature data present so we only 
	   check for signature data if it's not already available */
	if( contentListPtr->object == NULL )
		{
		STREAM stream;
		long packetLength;
		PGP_PACKET_TYPE packetType;

		/* Make sure that there's enough data left in the stream to do 
		   something with.  We require a minimum of 44 bytes, the size
		   of the DSA signature payload, in the stream */
		if( envelopeInfoPtr->bufPos - \
				envelopeInfoPtr->dataLeft < PGP_MAX_HEADER_SIZE + 44 )
			return( CRYPT_ERROR_UNDERFLOW );

		REQUIRES( moreContentItemsPossible( envelopeInfoPtr->contentList ) );

		/* Read the signature packet at the end of the payload */
		sMemConnect( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
					 envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft );
		status = getPacketInfo( &stream, envelopeInfoPtr, &packetType, 
								&packetLength, NULL, 8 );
		if( cryptStatusOK( status ) && packetType != PGP_PACKET_SIGNATURE )
			status = CRYPT_ERROR_BADDATA;
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			retExt( status,
					( status, ENVELOPE_ERRINFO,
					  "Invalid PGP signature packet header" ) );
			}
		sseek( &stream, 0 );
		status = addContentListItem( envelopeInfoPtr, &stream, TRUE );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			{
			retExt( status,
					( status, ENVELOPE_ERRINFO,
					  "Invalid PGP signature packet" ) );
			}
		}

	/* When we reach this point there may still be unhashed data left in the 
	   buffer (it won't have been hashed yet because the hashing is performed 
	   when the data is copied out, after unwrapping and whatnot) so we hash 
	   it before we exit.  Since we don't wrap up the hashing as we do with
	   any other format (PGP hashes in all sorts of odds and ends after 
	   hashing the message body) we have to manually turn off hashing here */
	if( envelopeInfoPtr->dataLeft > 0 )
		{
		status = envelopeInfoPtr->processExtraData( envelopeInfoPtr,
						envelopeInfoPtr->buffer, envelopeInfoPtr->dataLeft );
		}
	envelopeInfoPtr->dataFlags &= ~ENVDATA_HASHACTIONSACTIVE;
	if( cryptStatusError( status ) )
		return( status );

	ENSURES( sanityCheck( envelopeInfoPtr ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Envelope Access Routines						*
*																			*
****************************************************************************/

STDC_NONNULL_ARG( ( 1 ) ) \
void initPGPDeenveloping( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
	
	REQUIRES_V( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE );

	/* Set the access method pointers */
	envelopeInfoPtr->processPreambleFunction = processPreamble;
	envelopeInfoPtr->processPostambleFunction = processPostamble;
	envelopeInfoPtr->checkAlgo = pgpCheckAlgo;

	/* Set up the processing state information */
	envelopeInfoPtr->pgpDeenvState = PGP_DEENVSTATE_NONE;

	/* Turn off segmentation of the envelope payload.  PGP has a single 
	   length at the start of the data and doesn't segment the payload */
	envelopeInfoPtr->dataFlags |= ENVDATA_NOSEGMENT;
	}
#endif /* USE_PGP */

⌨️ 快捷键说明

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