📄 pgp_deen.c
字号:
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 + -