📄 decode.c
字号:
if( envelopeInfoPtr->iCryptContext != CRYPT_ERROR )
{
status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
IMESSAGE_CTX_DECRYPT, bufPtr,
bytesToCopy );
if( cryptStatusError( status ) )
return( status );
}
envelopeInfoPtr->bufPos += bytesToCopy;
if( !( envelopeInfoPtr->dataFlags & ENVDATA_NOLENGTHINFO ) )
envelopeInfoPtr->segmentSize -= bytesToCopy;
/* If the payload has a definite length and we've reached its end, set
the EOC flag to make sure that we don't go any further */
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED && \
envelopeInfoPtr->segmentSize <= 0 )
{
status = processDataEnd( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
ENSURES( bytesToCopy > 0 && bytesToCopy <= length );
ENSURES( sanityCheck( envelopeInfoPtr ) );
*bytesCopied = bytesToCopy;
return( CRYPT_OK );
}
/* Copy data into the de-enveloping envelope. Returns the number of bytes
copied */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int copyToDeenvelope( INOUT ENVELOPE_INFO *envelopeInfoPtr,
IN_BUFFER( length ) const BYTE *buffer,
IN_LENGTH const int length )
{
BYTE *bufPtr = ( BYTE * ) buffer;
int currentLength = length, bytesCopied, iterationCount;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isReadPtr( buffer, length ) );
/*///////////////////////////////////////////////////*/
assert( envelopeInfoPtr->segmentSize != CRYPT_UNUSED );
/*///////////////////////////////////////////////////*/
REQUIRES( sanityCheck( envelopeInfoPtr ) );
REQUIRES( length > 0 && length < MAX_INTLENGTH );
/* If we're trying to copy data into a full buffer, return a count of 0
bytes (the calling routine may convert this to an overflow error if
necessary) */
if( envelopeInfoPtr->bufPos >= envelopeInfoPtr->bufSize )
return( 0 );
/* If we're verifying a detached signature, just hash the data and exit.
We don't have to check whether hashing is active or not because it'll
always be active for detached data sicne this is the only thing
that's done with it */
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
{
int status;
REQUIRES( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE );
status = hashEnvelopeData( envelopeInfoPtr->actionList,
buffer, currentLength );
return( cryptStatusError( status ) ? status : currentLength );
}
/* Keep processing data until either we run out of input or we can't copy
in any more data. The code sequence within this loop acts as a simple
FSM so that if we exit at any point then the next call to this
function will resume where we left off */
iterationCount = 0;
do
{
int segmentCount, status;
/* If there's no segment information currently available we need to
process a segment header before we can handle any data. The use
of a loop is necessary to handle some broken implementations that
emit zero-length sub-segments, and as a corollary it also helps
avoid a pile of special-case code to manage PGP's strange way of
handling the last segment in indefinite-length encodings. We
limit the segment count to FAILSAFE_ITERATIONS_SMALL sub-segments
to make sure that we don't spend forever trying to process
extremely broken data */
for( segmentCount = 0; \
segmentCount < FAILSAFE_ITERATIONS_SMALL && \
envelopeInfoPtr->segmentSize <= 0; \
segmentCount++ )
{
SEGMENT_STATUS segmentStatus;
int bytesConsumed;
status = getNextSegment( envelopeInfoPtr, bufPtr, currentLength,
&bytesConsumed, &segmentStatus );
if( status == OK_SPECIAL )
{
/* If we've reached the end of the payload, we're done */
if( segmentStatus == SEGMENT_ENDOFDATA )
return( length - currentLength );
/* We got the length via some other mechanism because it's a
definite-length or non-segmenting encoding, no input was
consumed and we can exit */
ENSURES( segmentStatus == SEGMENT_FIXEDLENGTH );
break;
}
if( cryptStatusError( status ) )
return( status );
if( bytesConsumed <= 0 )
{
/* We don't have enough input data left to read the
information for the next segment, exit */
ENSURES( segmentStatus == SEGMENT_INSUFFICIENTDATA );
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( length - currentLength );
}
bufPtr += bytesConsumed;
currentLength -= bytesConsumed;
/* If we've reached the EOC or consumed all of the input data,
exit */
if( ( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS ) || \
currentLength <= 0 )
{
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( length - currentLength );
}
}
if( segmentCount >= FAILSAFE_ITERATIONS_SMALL )
{
/* We've processed FAILSAFE_ITERATIONS_SMALL consecutive sub-
segments in a row, there's something wrong with the input
data */
return( CRYPT_ERROR_BADDATA );
}
ENSURES( currentLength > 0 && currentLength <= length && \
currentLength < MAX_INTLENGTH );
/* Copy the data into the envelope, decrypting it as we go if
necessary. In theory we could also check to see whether any
more data can fit into the buffer before trying to copy it in
but since this would require knowledge of the internal buffer-
handling strategy used by copyData() we always call it and rely
on a bytesCopied value of zero to indicate that the tank is
full */
status = copyData( envelopeInfoPtr, bufPtr, currentLength,
&bytesCopied );
if( cryptStatusError( status ) )
return( status );
bufPtr += bytesCopied;
currentLength -= bytesCopied;
ENSURES( sanityCheck( envelopeInfoPtr ) );
ENSURES( currentLength >= 0 && currentLength <= length && \
currentLength < MAX_INTLENGTH );
assert( ( envelopeInfoPtr->segmentSize >= 0 ) || \
( ( envelopeInfoPtr->dataFlags & ENVDATA_NOSEGMENT ) && \
( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) && \
( envelopeInfoPtr->segmentSize == CRYPT_UNUSED ) ) );
}
while( currentLength > 0 && bytesCopied > 0 && \
iterationCount++ < FAILSAFE_ITERATIONS_LARGE );
ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( length - currentLength );
}
/****************************************************************************
* *
* Copy from Envelope *
* *
****************************************************************************/
/* Copy buffered out-of-band data from earlier processing to the output.
This is only required for PGP envelopes where we have to burrow down into
nested content in order to figure out what to do with it */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int copyOobData( INOUT ENVELOPE_INFO *envelopeInfoPtr,
OUT_BUFFER( maxLength, *length ) BYTE *buffer,
IN_LENGTH const int maxLength,
OUT_LENGTH_Z int *length,
const BOOLEAN retainInBuffer )
{
const int oobBytesToCopy = min( maxLength, envelopeInfoPtr->oobBufPos );
const int oobRemainder = envelopeInfoPtr->oobBufPos - oobBytesToCopy;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( buffer, maxLength ) );
assert( isWritePtr( length, sizeof( int ) ) );
REQUIRES( sanityCheck( envelopeInfoPtr ) );
REQUIRES( maxLength > 0 && maxLength < MAX_INTLENGTH );
ENSURES( oobBytesToCopy > 0 && \
oobBytesToCopy <= envelopeInfoPtr->oobBufPos );
memcpy( buffer, envelopeInfoPtr->oobBuffer, oobBytesToCopy );
*length = oobBytesToCopy;
/* If we're retaining the data in the OOB, we're done */
if( retainInBuffer )
{
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/* We're moving data out of the OOB buffer, adjust the OOB buffer
contents */
if( oobRemainder > 0 )
{
memmove( envelopeInfoPtr->oobBuffer,
envelopeInfoPtr->oobBuffer + oobBytesToCopy, oobRemainder );
}
envelopeInfoPtr->oobBufPos = oobRemainder;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/* Copy data from the envelope. Returns the number of bytes copied */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int copyFromDeenvelope( INOUT ENVELOPE_INFO *envelopeInfoPtr,
OUT_BUFFER( maxLength, *length ) BYTE *buffer,
IN_LENGTH const int maxLength,
OUT_LENGTH_Z int *length,
IN_FLAGS( ENVCOPY ) const int flags )
{
const BOOLEAN isLookaheadRead = ( flags & ENVCOPY_FLAG_OOBDATA ) ? \
TRUE : FALSE;
int bytesToCopy = maxLength, bytesCopied, oobBytesCopied = 0;
int remainder, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( buffer, maxLength ) );
assert( isWritePtr( length, sizeof( int ) ) );
/*///////////////////////////////////////////////////*/
assert( envelopeInfoPtr->segmentSize != CRYPT_UNUSED );
/*///////////////////////////////////////////////////*/
REQUIRES( sanityCheck( envelopeInfoPtr ) );
REQUIRES( maxLength > 0 && maxLength < MAX_INTLENGTH );
REQUIRES( !isLookaheadRead || \
( isLookaheadRead && \
( bytesToCopy > 0 && bytesToCopy <= OOB_BUFFER_SIZE ) ) );
REQUIRES( flags == ENVCOPY_FLAG_NONE || flags == ENVCOPY_FLAG_OOBDATA );
/* Clear return values */
memset( buffer, 0, min( bytesToCopy, 8 ) );
*length = 0;
/* If we're verifying a detached signature the data is communicated
out-of-band so there's nothing to copy out (the length is still set
to zero from the earlier code */
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
return( CRYPT_OK );
/* If there's buffered out-of-band data from an earlier lookahead read
present, insert it into the output stream */
if( envelopeInfoPtr->oobBufPos > 0 )
{
status = copyOobData( envelopeInfoPtr, buffer, bytesToCopy,
&oobBytesCopied, isLookaheadRead );
if( cryptStatusError( status ) )
return( status );
bytesToCopy -= oobBytesCopied;
buffer += oobBytesCopied;
if( bytesToCopy <= 0 )
{
*length = oobBytesCopied;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
}
ENSURES( bytesToCopy > 0 && bytesToCopy <= maxLength && \
bytesToCopy < MAX_INTLENGTH );
/* If we're using compression, expand the data from the buffer to the
output via the zStream */
#ifdef USE_COMPRESSION
if( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED )
{
const int originalInLength = bytesToCopy;
const int bytesIn = \
( envelopeInfoPtr->dataLeft > 0 && \
envelopeInfoPtr->dataLeft < envelopeInfoPtr->bufPos ) ? \
envelopeInfoPtr->dataLeft : envelopeInfoPtr->bufPos;
/* Decompress the data into the output buffer. Note that we use the
length value to determine the length of the output rather than
bytesToCopy since the ratio of bytes in the buffer to bytes of
output isn't 1:1 as it is for other content types.
When using PGP 2.x-compatible decompression we have to allow a
return status of Z_BUF_ERROR because it uses a compression format
from a pre-release version of InfoZip that doesn't include
header or trailer information so the decompression code can't
definitely tell that it's reached the end of its input data but
can only report that it can't go any further.
When we're trying to suck all remaining compressed data from the
zstream we may get a (rather misleadingly named) Z_BUF_ERROR if
there's both no internally buffered data left and no new input
available to produce any output. If this is the case we simply
treat it as a nothing-copied condition, since decompression will
continue when the user provides more input.
We can also get a Z_BUF_ERROR for some types of (non-fatal) error
situations, for example if we're flushing out data still present
in the zstream (avail_in == 0) and there's a problem such as the
compressor needing more data but there's none available, the zlib
code will report it as a Z_BUF_ERROR. In this case we convert it
into a (recoverable) underflow error, which isn't always accurate
but is more useful than the generic CRYPT_ERROR_FAILED */
envelopeInfoPtr->zStream.next_in = envelopeInfoPtr->buffer;
envelopeInfoPtr->zStream.avail_in = bytesIn;
envelopeInfoPtr->zStream.next_out = buffer;
envelopeInfoPtr->zStream.avail_out = bytesToCopy;
status = inflate( &envelopeInfoPtr->zStream, Z_SYNC_FLUSH );
if( status != Z_OK && status != Z_STREAM_END && \
!( status == Z_BUF_ERROR && \
envelopeInfoPtr->type == CRYPT_FORMAT_PGP ) && \
!( status == Z_BUF_ERROR && bytesIn == 0 ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -