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