📄 denv_pgp.c
字号:
/****************************************************************************
* *
* cryptlib PGP De-enveloping Routines *
* Copyright Peter Gutmann 1996-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "envelope.h"
#include "pgp.h"
#include "misc_rw.h"
#include "objinfo.h"
#elif defined( INC_CHILD )
#include "envelope.h"
#include "pgp.h"
#include "../misc/misc_rw.h"
#include "../misc/objinfo.h"
#else
#include "envelope/envelope.h"
#include "envelope/pgp.h"
#include "misc/misc_rw.h"
#include "misc/objinfo.h"
#endif /* Compiler-specific includes */
#ifdef USE_PGP
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Get information on a PGP data packet */
static int getPacketInfo( STREAM *stream, ENVELOPE_INFO *envelopeInfoPtr,
long *length )
{
int ctb, status;
/* Read the packet header and extract information from the CTB. Note
that the assignment of version numbers is speculative only, since
it's possible to use PGP 2.x packet headers to wrap up OpenPGP
packets */
status = pgpReadPacketHeader( stream, &ctb, length );
if( cryptStatusError( status ) )
return( status );
if( ( ctb & PGP_CTB_OPENPGP ) == PGP_CTB_OPENPGP )
envelopeInfoPtr->version = PGP_VERSION_OPENPGP;
else
envelopeInfoPtr->version = PGP_VERSION_2;
/* Extract and return the packet type */
return( ( ( ctb & PGP_CTB_OPENPGP ) == PGP_CTB_OPENPGP ) ? \
( ctb & 0x3F ) : ( ( ctb >> 2 ) & 0x0F ) );
}
/****************************************************************************
* *
* Read Key Exchange/Signature Packets *
* *
****************************************************************************/
/* Add information about an object to an envelope's content information list */
static int addContentListItem( STREAM *stream,
ENVELOPE_INFO *envelopeInfoPtr,
const BOOLEAN isContinuedSignature )
{
QUERY_INFO queryInfo;
CONTENT_LIST *contentListItem;
void *object = NULL, *originalObjectPtr;
int status;
/* 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;
contentListItem = createContentListItem( envelopeInfoPtr->memPoolState,
CRYPT_FORMAT_PGP, NULL, 0,
FALSE );
if( contentListItem == NULL )
return( CRYPT_ERROR_MEMORY );
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 */
originalObjectPtr = sMemBufPtr( stream );
status = queryPgpObject( stream, &queryInfo );
if( cryptStatusError( status ) )
return( status );
if( queryInfo.type == CRYPT_OBJECT_SIGNATURE && \
queryInfo.dataStart == NULL )
{
/* It's a one-pass signature packet, the signature information
follows in another packet that will be added later */
sSkip( stream, ( int ) queryInfo.size );
queryInfo.size = 0;
}
else
{
if( ( object = clAlloc( "addContentListItem", \
( size_t ) queryInfo.size ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
sread( stream, object, ( int ) queryInfo.size );
}
/* 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( isContinuedSignature )
{
for( contentListItem = envelopeInfoPtr->contentList;
contentListItem != NULL && \
contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE;
contentListItem = contentListItem->next );
assert( contentListItem->object == NULL && \
contentListItem->objectSize == 0 );
contentListItem->object = object;
contentListItem->objectSize = ( int ) queryInfo.size;
}
else
{
/* Allocate memory for the new content list item and copy information
on the item across */
contentListItem = createContentListItem( envelopeInfoPtr->memPoolState,
CRYPT_FORMAT_PGP, object,
( int ) queryInfo.size,
queryInfo.type == CRYPT_OBJECT_SIGNATURE );
if( contentListItem == NULL )
{
if( object != NULL )
clFree( "addContentListItem", object );
return( CRYPT_ERROR_MEMORY );
}
}
if( queryInfo.type == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
queryInfo.type == CRYPT_OBJECT_SIGNATURE )
{
/* Remember details of the enveloping info that we require to
continue. Note that if we're processing a one-pass signature
packet followed by signature data, the keyID and algorithm info
in the signature packet takes precendence in case of
inconsistencies between the two */
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 != NULL )
{
sigInfo->extraData = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfo.attributeStart - ( BYTE * ) originalObjectPtr );
sigInfo->extraDataLength = queryInfo.attributeLength;
}
if( queryInfo.unauthAttributeStart != NULL )
{
sigInfo->extraData2 = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfo.unauthAttributeStart - ( BYTE * ) originalObjectPtr );
sigInfo->extraData2Length = queryInfo.unauthAttributeLength;
}
}
memcpy( contentListItem->keyID, queryInfo.keyID,
queryInfo.keyIDlength );
contentListItem->keyIDsize = queryInfo.keyIDlength;
if( queryInfo.iAndSStart != NULL )
{
contentListItem->issuerAndSerialNumber = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfo.iAndSStart - ( BYTE * ) originalObjectPtr );
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;
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 != NULL )
{
contentListItem->payload = \
( BYTE * ) contentListItem->object + \
( ( BYTE * ) queryInfo.dataStart - ( BYTE * ) originalObjectPtr );
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 */
if( queryInfo.type == CRYPT_OBJECT_SIGNATURE )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
/* Append a new hash action to the action list */
setMessageCreateObjectInfo( &createInfo,
contentListItem->clSigInfo.hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) && \
addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->memPoolState, ACTION_HASH,
createInfo.cryptHandle ) == NULL )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
status = CRYPT_ERROR_MEMORY;
}
if( cryptStatusError( status ) )
{
deleteContentList( envelopeInfoPtr->memPoolState,
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;
streamPos = stell( &stream );
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -