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

📄 pgp_deen.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
		   of the signature data.  For DSA we record the start of the (r,s)
		   record, PGP 2.x shouldn't do DSA signing, but there's bound to be
		   some mutant version out there which does this */
		sSkip( stream, 2 );
		offset = ( int ) stell( stream ) - offset;
		status = pgpReadMPI( stream, NULL );
		if( cryptStatusError( status ) )
			return( status );
		contentListItem->payload = \
							( BYTE * ) contentListItem->object + offset;
		contentListItem->payloadSize = bitsToBytes( status ) + 2;
		if( contentListItem->cryptAlgo == CRYPT_ALGO_DSA )
			{
			status = pgpReadMPI( stream, NULL );
			if( cryptStatusError( status ) )
				return( status );
			contentListItem->payloadSize += bitsToBytes( status ) + 2;
			if( contentListItem->payloadSize < 20 || \
				contentListItem->payloadSize > 44 )
				return( CRYPT_ERROR_BADDATA );
			}
		else
			if( contentListItem->payloadSize < 56 || \
				contentListItem->payloadSize > CRYPT_MAX_PKCSIZE )
				return( CRYPT_ERROR_BADDATA );

		return( CRYPT_OK );
		}

	/* It's an OpenPGP packet, remember the extra data to be hashed (this
	   starts at the version byte, which we've already read so we add a -1
	   offset) and read the signature and hash algorithms */
	contentListItem->extraData = ( BYTE * ) contentListItem->object + \
								 ( ( int ) ( stell( stream ) - 1 ) - offset );
	contentListItem->extraDataLength = 1 + 1 + 1 + 1 + 2;
	sgetc( stream );	/* Skip signature type */
	switch( sgetc( stream ) )
		{
		case PGP_ALGO_RSA:
		case PGP_ALGO_RSA_SIGN:
			contentListItem->cryptAlgo = CRYPT_ALGO_RSA;
			break;

		case PGP_ALGO_DSA:
			contentListItem->cryptAlgo = CRYPT_ALGO_DSA;
			break;

		default:
			return( CRYPT_ERROR_NOTAVAIL );
		}
	if( ( contentListItem->hashAlgo = \
					readHashAlgorithmID( stream ) ) == CRYPT_ALGO_NONE )
		return( CRYPT_ERROR_NOTAVAIL );

	/* Process the authenticated attributes */
	value = ( sgetc( stream ) << 8 ) | sgetc( stream );
	if( value < 0 || value > 2048 )
		return( CRYPT_ERROR_BADDATA );
	if( sMemDataLeft( stream ) < value )
		return( CRYPT_ERROR_UNDERFLOW );
	contentListItem->extraDataLength += value;
	if( value )
		{
		status = processSignatureSubpackets( stream, contentListItem,
											 value, offset, TRUE );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Skip the unauthenticated attributes */
	value = ( sgetc( stream ) << 8 ) | sgetc( stream );
	if( value < 0 || value > 2048 )
		return( CRYPT_ERROR_BADDATA );
	if( sMemDataLeft( stream ) < value )
		return( CRYPT_ERROR_UNDERFLOW );
	if( value )
		{
		status = processSignatureSubpackets( stream, contentListItem,
											 value, offset, FALSE );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Skip the hash check and read the signature, recording the start of the
	   signature data */
	sSkip( stream, 2 );
	offset = ( int ) stell( stream ) - offset;
	status = pgpReadMPI( stream, NULL );
	if( cryptStatusError( status ) )
		return( status );
	contentListItem->payload = ( BYTE * ) contentListItem->object + offset;
	contentListItem->payloadSize = bitsToBytes( status ) + 2;
	if( contentListItem->cryptAlgo == CRYPT_ALGO_DSA )
		{
		status = pgpReadMPI( stream, NULL );
		if( cryptStatusError( status ) )
			return( status );
		contentListItem->payloadSize += bitsToBytes( status ) + 2;
		if( contentListItem->payloadSize < 20 || \
			contentListItem->payloadSize > 44 )
			return( CRYPT_ERROR_BADDATA );
		}
	else
		if( contentListItem->payloadSize < 56 || \
			contentListItem->payloadSize > CRYPT_MAX_PKCSIZE )
			return( CRYPT_ERROR_BADDATA );

	return( CRYPT_OK );
	}

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

static int addContentListItem( STREAM *stream,
							   ENVELOPE_INFO *envelopeInfoPtr,
							   const int packetType, const int length )
	{
	CONTENT_LIST *contentListItem;
	void *object = NULL;
	int status = CRYPT_OK;

	/* Make sure there's enough data left to read the entire item */
	if( stream != NULL && sMemDataLeft( stream ) < length )
		return( CRYPT_ERROR_UNDERFLOW );

	/* Find the size of the object, allocate a buffer for it if necessary,
	   and copy it across */
	if( packetType == PGP_PACKET_PKE || packetType == PGP_PACKET_SIGNATURE || \
		packetType == PGP_PACKET_SIGNATURE_SPECIAL )
		{
		const long position = stell( stream );

		if( !length || \
			length > ( packetType == PGP_PACKET_SIGNATURE ? 2048 : 1024 ) )
			return( CRYPT_ERROR_BADDATA );
		if( ( object = malloc( length ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		status = sread( stream, object, length );
		if( cryptStatusError( status ) )
			return( status );
		sseek( stream, position );
		}

	/* 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, however PGP handles
	   multiple signatures by nesting them so this isn't a problem */
	if( packetType == PGP_PACKET_SIGNATURE_SPECIAL )
		{
		for( contentListItem = envelopeInfoPtr->contentList;
			 contentListItem != NULL && \
				contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE;
			 contentListItem = contentListItem->next );
		}
	else
		{
		/* Allocate memory for the new content list item and copy information
		   on the item across */
		contentListItem = createContentListItem( CRYPT_FORMAT_PGP, object,
												 length );
		if( contentListItem == NULL )
			{
			if( object != NULL )
				free( object );
			return( CRYPT_ERROR_MEMORY );
			}
		}

	/* 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 )
		{
		contentListItem->envInfo = CRYPT_ENVINFO_PASSWORD;
		contentListItem->cryptAlgo = CRYPT_ALGO_IDEA;
		contentListItem->cryptMode = CRYPT_MODE_CFB;
		contentListItem->hashAlgo = CRYPT_ALGO_MD5;
		appendContentListItem( envelopeInfoPtr, contentListItem );
		return( CRYPT_OK );
		}

	/* Read the packet contents */
	switch( packetType )
		{
		case PGP_PACKET_SKE:
			status = readSKEPacket( stream, contentListItem );
			break;

		case PGP_PACKET_PKE:
			status = readPKEPacket( stream, contentListItem );
			break;

		case PGP_PACKET_SIGNATURE:
			status = readSigPacket( stream, contentListItem );
			break;

		case PGP_PACKET_SIGNATURE_ONEPASS:
			/* First half of a one-pass signature */
			status = readOnepassSigPacket( stream, contentListItem );
			break;

		case PGP_PACKET_SIGNATURE_SPECIAL:
			/* Remainder of a one-pass signature, completing the data which
			   was read earlier */
			contentListItem->object = object;
			contentListItem->objectSize = length;
			status = readSigPacket( stream, contentListItem );
			break;

		default:
			assert( NOTREACHED );
			status = CRYPT_ERROR_BADDATA;
		}
	if( cryptStatusError( status ) )
		{
		if( packetType == PGP_PACKET_SIGNATURE_SPECIAL )
			{
			/* The content list entry contains previous data which we want
			   to keep around, so we only delete the information we've just
			   added */
			contentListItem->object = NULL;
			contentListItem->objectSize = 0;
			free( object );
			}
		else
			deleteContentList( contentListItem );
		return( status );
		}

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

	/* If it's signed data, create a hash action to process it */
	if( packetType == PGP_PACKET_SIGNATURE || \
		packetType == PGP_PACKET_SIGNATURE_ONEPASS )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;

		/* Append a new hash action to the action list */
		setMessageCreateObjectInfo( &createInfo,
									contentListItem->hashAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
								  &createInfo, OBJECT_TYPE_CONTEXT );
		if( cryptStatusOK( status ) && \
			addAction( &envelopeInfoPtr->actionList, ACTION_HASH,
					   createInfo.cryptHandle ) == NULL )
			status = CRYPT_ERROR_MEMORY;
		if( cryptStatusError( status ) )
			{
			deleteContentList( contentListItem );
			return( status );
			}
		}
	appendContentListItem( envelopeInfoPtr, contentListItem );

	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 somewhat 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.  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 */

static int processPreamble( ENVELOPE_INFO *envelopeInfoPtr )
	{
	PGP_DEENV_STATE state = envelopeInfoPtr->pgpDeenvState;
	STREAM stream;
	int packetType, length, streamPos = 0, status = CRYPT_OK;
	long packetLength;

	/* 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 )
		{
		/* Read the PGP packet type and figure out what we've got */
		if( state == PGP_DEENVSTATE_NONE )
			{
			int value;

			packetType = getPacketInfo( &stream, envelopeInfoPtr, &packetLength );
			if( cryptStatusError( packetType ) )
				return( packetType );

			/* Process as much of the header as we can and move on to the next
			   state.  Since PGP uses sequential discrete packets, for any
			   of the non-payload packet types we stay in the "none" state
			   because we don't know what's next */
			switch( packetType )
				{
				case PGP_PACKET_DATA:
					/* Skip the content-type, filename, and date */
					sSkip( &stream, 1 );
					length = sgetc( &stream );
					if( !cryptStatusError( length ) )
						sSkip( &stream, length + 4 );
					status = sGetStatus( &stream );
					if( cryptStatusError( status ) )
						break;

					/* Remember where we are and move on to the next state */
					envelopeInfoPtr->payloadSize = packetLength - \
												   ( 1 + 1 + length + 4 );
					if( envelopeInfoPtr->payloadSize < 1 )
						{
						status = CRYPT_ERROR_BADDATA;
						break;
						}
					state = PGP_DEENVSTATE_DATA;
					break;

				case PGP_PACKET_COPR:
					value = sgetc( &stream );
					if( envelopeInfoPtr->usage != ACTION_NONE )
						{
						status = CRYPT_ERROR_BADDATA;
						break;
						}
					envelopeInfoPtr->usage = ACTION_COMPRESS;
#ifdef NO_COMPRESSION
					status = CRYPT_ERROR_BADDATA;
#else
					if( value == 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 )
							envelopeInfoPtr->zStreamInited = TRUE;
						else
							status = CRYPT_ERROR_MEMORY;
						}
					else
						if( value == PGP_ALGO_ZLIB )
							{
							/* Standard zlib compression */
							if( inflateInit( &envelopeInfoPtr->zStream ) == Z_OK )
								envelopeInfoPtr->zStreamInited = TRUE;
							else
								status = CRYPT_ERROR_MEMORY;
							}
						else
							{
							status = ( value < 0 ) ? \
									 value : CRYPT_ERROR_NOTAVAIL;
							break;
							}
#endif /* NO_COMPRESSION */
					state = PGP_DEENVSTATE_DATA;
					break;

				case PGP_PACKET_SKE:
				case PGP_PACKET_PKE:
					/* Read the SKE/PKE packet */
					if( envelopeInfoPtr->usage != ACTION_NONE && \
						envelopeInfoPtr->usage != ACTION_CRYPT )
						{
						status = CRYPT_ERROR_BADDATA;
						break;
						}
					envelopeInfoPtr->usage = ACTION_CRYPT;
					status = addContentListItem( &stream, envelopeInfoPtr,
												 packetType, packetLength );
					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 standalone.  The best we can do is
					   assume that if the caller added a hash action and we
					   find a signature, 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 sig packet as a one-pass
						   sig */
						if( packetType == PGP_PACKET_SIGNATURE_ONEPASS )
							{
							status = CRYPT_ERROR_BADDATA;
							break;
							}
						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 ) )
						{
						status = CRYPT_ERROR_BADDATA;
						break;
						}
					envelopeInfoPtr->usage = ACTION_SIGN;
					status = addContentListItem( &stream, envelopeInfoPtr,
												 packetType, packetLength );
					if( cryptStatusError( status ) )
						break;
					if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
						{
						/* If it's a one-pass sig, there's no payload
						   present, we can go straight to the postdata
						   state */

⌨️ 快捷键说明

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