📄 env_dec.c
字号:
/****************************************************************************
* *
* cryptlib Datagram Decoding Routines *
* Copyright Peter Gutmann 1996-2003 *
* *
****************************************************************************/
#include <string.h>
#if defined( INC_ALL )
#include "envelope.h"
#include "asn1_rw.h"
#elif defined( INC_CHILD )
#include "envelope.h"
#include "../misc/asn1_rw.h"
#else
#include "envelope/envelope.h"
#include "misc/asn1_rw.h"
#endif /* Compiler-specific includes */
/* .... NO! ... ... MNO! ...
..... MNO!! ...................... MNNOO! ...
..... MMNO! ......................... MNNOO!! .
.... MNOONNOO! MMMMMMMMMMPPPOII! MNNO!!!! .
... !O! NNO! MMMMMMMMMMMMMPPPOOOII!! NO! ....
...... ! MMMMMMMMMMMMMPPPPOOOOIII! ! ...
........ MMMMMMMMMMMMPPPPPOOOOOOII!! .....
........ MMMMMOOOOOOPPPPPPPPOOOOMII! ...
....... MMMMM.. OPPMMP .,OMI! ....
...... MMMM:: o.,OPMP,.o ::I!! ...
.... NNM:::.,,OOPM!P,.::::!! ....
.. MMNNNNNOOOOPMO!!IIPPO!!O! .....
... MMMMMNNNNOO:!!:!!IPPPPOO! ....
.. MMMMMNNOOMMNNIIIPPPOO!! ......
...... MMMONNMMNNNIIIOO!..........
....... MN MOMMMNNNIIIIIO! OO ..........
......... MNO! IiiiiiiiiiiiI OOOO ...........
...... NNN.MNO! . O!!!!!!!!!O . OONO NO! ........
.... MNNNNNO! ...OOOOOOOOOOO . MMNNON!........
...... MNNNNO! .. PPPPPPPPP .. MMNON!........
...... OO! ................. ON! .......
................................
Be very careful when modifying this code, the data manipulation it
performs is somewhat tricky */
/****************************************************************************
* *
* Header Processing Routines *
* *
****************************************************************************/
/* Handle the EOC and PKCS #5 block padding if necessary:
pad
+-------+-------+-------+
| | | |
+-------+-------+-------+
^ ^
| |
padPtr bPos */
static int processEOC( ENVELOPE_INFO *envelopeInfoPtr )
{
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( envelopeInfoPtr->bufPos >= 0 && \
envelopeInfoPtr->bufPos <= envelopeInfoPtr->bufSize );
/* If we're using a block cipher, undo the PKCS #5 padding which is
present at the end of the block */
if( envelopeInfoPtr->blockSize > 1 )
{
const BYTE *padPtr = envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos - 1;
const int padSize = *padPtr;
int i;
/* Make sure that the padding size is valid */
if( padSize < 1 || padSize > envelopeInfoPtr->blockSize || \
padSize > envelopeInfoPtr->bufPos )
return( CRYPT_ERROR_BADDATA );
/* Check the padding data */
envelopeInfoPtr->bufPos -= padSize;
padPtr -= padSize - 1;
for( i = 0; i < padSize - 1; i++ )
if( padPtr[ i ] != padSize )
return( CRYPT_ERROR_BADDATA );
assert( envelopeInfoPtr->bufPos >= 0 );
}
/* Remember that we've reached the end of the payload and where the
payload ends ("This was the end of the river all right") */
envelopeInfoPtr->dataFlags |= ENVDATA_ENDOFCONTENTS;
envelopeInfoPtr->dataLeft = envelopeInfoPtr->bufPos;
return( CRYPT_OK );
}
/* Decode the header for the next segment in the buffer. Returns the number
of bytes consumed, or an underflow error if more data is required */
static int getNextSegment( ENVELOPE_INFO *envelopeInfoPtr, const BYTE *buffer,
const int length )
{
SEGHDR_STATE state = envelopeInfoPtr->segHdrState;
long segmentLength = envelopeInfoPtr->segHdrSegLength;
int count = envelopeInfoPtr->segHdrCount, bufPos;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( length > 0 );
assert( isReadPtr( buffer, length ) );
/* If we've already processed the entire payload, don't do anything.
This can happen when we're using the definite encoding form, since
the EOC flag is set elsewhere as soon as the entire payload has been
copied to the buffer */
if( envelopeInfoPtr->dataFlags & ENVDATA_ENDOFCONTENTS )
return( OK_SPECIAL );
/* If we're using the definite encoding form, there's a single segment
equal in length to the entire payload */
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
{
envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;
return( OK_SPECIAL );
}
/* If we're using the indefinite form but it's an envelope type that
doesn't segment data, the length is implicitly defined as "until we
run out of input" */
if( envelopeInfoPtr->dataFlags & ENVDATA_NOSEGMENT )
{
envelopeInfoPtr->segmentSize = CRYPT_UNUSED;
return( OK_SPECIAL );
}
/* If we're starting a new sub-segment read and there's enough data
present that we can try and use the ASN.1 read routines, try and get
the sub-segment info using the ASN.1 routines */
if( state == SEGHDRSTATE_NONE && length >= 2 )
{
STREAM stream;
int bytesRead, status;
assert( envelopeInfoPtr->segHdrSegLength == 0L && \
envelopeInfoPtr->segHdrCount == 0 );
/* Get the sub-segment info */
sMemConnect( &stream, buffer, length );
status = checkEOC( &stream );
if( status == FALSE )
{
/* It's a new sub-segment, get its length */
status = readLongGenericHole( &stream, &segmentLength,
BER_OCTETSTRING );
if( cryptStatusOK( status ) && segmentLength == CRYPT_UNUSED )
/* If it's an (invalid) indefinite-length encoding, we can't
do anything with it */
status = CRYPT_ERROR_BADDATA;
}
else
/* If we've seen the EOC, wrap up the processing */
if( status == TRUE )
{
status = processEOC( envelopeInfoPtr );
segmentLength = 0;
}
bytesRead = stell( &stream );
sMemDisconnect( &stream );
/* If the read was successful (i.e. we didn't run out of input),
return the info to the caller */
if( status != CRYPT_ERROR_UNDERFLOW )
{
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->segmentSize = segmentLength;
return( bytesRead );
}
}
/* We couldn't read the current sub-segment info using the ASN.1
routines due to lack of input data, fall back to the FSM-based read,
which is interruptible. This read processes each data byte until
we've either parsed the entire header or run out of input. It is
however not quite as tolerant as the ASN.1 code in terms of accepting
odd non-DER encodings */
for( bufPos = 0; bufPos < length && state != SEGHDRSTATE_DONE; bufPos++ )
{
SEGHDR_STATE oldState = state;
switch( state )
{
case SEGHDRSTATE_NONE:
/* Check for OCTET STRING or start or end-of-contents
octets */
segmentLength = 0;
if( buffer[ bufPos ] == BER_OCTETSTRING )
state = SEGHDRSTATE_LEN_OF_LEN;
else
if( buffer[ bufPos ] == BER_EOC )
state = SEGHDRSTATE_END;
else
return( CRYPT_ERROR_BADDATA );
break;
case SEGHDRSTATE_LEN_OF_LEN:
/* We've seen the OCTET STRING header, check for a short
length or length-of-length value */
count = buffer[ bufPos ];
if( !( count & 0x80 ) )
{
/* It's a short/indefinite length */
segmentLength = count;
state = SEGHDRSTATE_DONE;
}
else
{
/* It's a long segment, get the length-of-length
information */
count &= 0x7F;
if( count < 1 || count > 4 )
/* "Nobody will ever need more than 640K" */
return( CRYPT_ERROR_BADDATA );
state = SEGHDRSTATE_LEN;
}
break;
case SEGHDRSTATE_LEN:
/* We're processing a long-format length field, get the next
part of the length */
segmentLength = ( segmentLength << 8 ) | buffer[ bufPos ];
count--;
/* If we've got all the data, make sure that the segment
length is valid and return to the initial state */
if( count <= 0 )
{
if( segmentLength < 0x80 )
/* Probably a bit pedantic, but it helps catch
garbled data */
return( CRYPT_ERROR_BADDATA );
state = SEGHDRSTATE_DONE;
}
break;
case SEGHDRSTATE_END:
{
int status;
/* We've seen the first EOC octet, check for the second
one */
if( buffer[ bufPos ] )
return( CRYPT_ERROR_BADDATA );
/* Process the EOC octets */
status = processEOC( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
state = SEGHDRSTATE_DONE;
break;
}
default:
assert( NOTREACHED );
}
/* If the state hasn't changed when it should have, there's a
problem */
if( state == oldState && state != SEGHDRSTATE_LEN )
return( CRYPT_ERROR_BADDATA );
}
/* Make sure that the length we got is valid. These checks just
duplicate the checks normally performed by the ASN.1-level code */
if( length < 0 )
return( CRYPT_ERROR_BADDATA );
if( ( length & 0x80000000UL ) || length > MAX_INTLENGTH )
return( CRYPT_ERROR_OVERFLOW );
/* If we got the final length, update the appropriate segment length
value */
if( state == SEGHDRSTATE_DONE )
{
envelopeInfoPtr->segmentSize = segmentLength;
envelopeInfoPtr->segHdrSegLength = 0L;
envelopeInfoPtr->segHdrCount = 0;
envelopeInfoPtr->segHdrState = SEGHDRSTATE_NONE;
}
else
{
/* Copy the local state information back into the envelope
structure */
envelopeInfoPtr->segHdrSegLength = segmentLength;
envelopeInfoPtr->segHdrCount = count;
envelopeInfoPtr->segHdrState = state;
}
return( bufPos );
}
/****************************************************************************
* *
* Copy to Envelope *
* *
****************************************************************************/
/* Copy possibly encrypted data into the envelope with special handling for
block encryption modes. Returns the number of bytes copied */
static int copyData( ENVELOPE_INFO *envelopeInfoPtr, const BYTE *buffer,
const int length )
{
BYTE *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
int bytesToCopy, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( length > 0 );
assert( isReadPtr( buffer, length ) );
assert( envelopeInfoPtr->bufPos >= 0 && \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -