📄 asn1_rw.c
字号:
}
return( TRUE );
}
/* Read the length octets for an ASN.1 data type, with special-case handling
for long and short lengths and how indefinite-length encodings are handled.
The short-length read is limited to 32K, the limit for most PKI data and
one that doesn't cause type conversion problems on systems where
sizeof( int ) != sizeof( long ). If the caller indicates that indefinite
lengths are OK, we return OK_SPECIAL if we encounter one. Long length
reads always allow indefinite lengths since these are quite likely for
large objects */
typedef enum {
READLENGTH_NONE, /* No length read behaviour */
READLENGTH_SHORT, /* Short length, no indef.allowed */
READLENGTH_SHORT_INDEF, /* Short length, indef.to OK_SPECIAL */
READLENGTH_LONG_INDEF, /* Long length, indef.to OK_SPECIAL */
READLENGTH_LAST /* Last possible read type */
} READLENGTH_TYPE;
static long readLengthValue( STREAM *stream, const READLENGTH_TYPE readType )
{
BYTE buffer[ 8 ], *bufPtr = buffer;
BOOLEAN shortLen = ( readType == READLENGTH_SHORT || \
readType == READLENGTH_SHORT_INDEF );
long length = 0;
int noLengthOctets, status;
/* Read the first byte of length data. If it's a short length, we're
done */
length = sgetc( stream );
if( cryptStatusError( length ) || !( length & 0x80 ) )
return( length );
/* Read the actual length octets. Since BER lengths can be encoded in
peculiar ways (at least one text uses a big-endian 32-bit encoding
for everything) we allow up to 8 bytes of non-DER length data, but
only the last 2 or 4 of these can be nonzero */
noLengthOctets = length & 0x7F;
if( noLengthOctets <= 0 )
{
/* If indefinite lengths aren't allowed, signal an error */
if( readType == READLENGTH_SHORT )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
/* Indefinite length encoding, warn the caller */
assert( readType == READLENGTH_SHORT_INDEF || \
readType == READLENGTH_LONG_INDEF );
return( OK_SPECIAL );
}
if( noLengthOctets > 8 )
status = CRYPT_ERROR_BADDATA;
else
status = sread( stream, buffer, noLengthOctets );
if( cryptStatusError( status ) )
{
sSetError( stream, status );
return( status );
}
if( !buffer[ 0 ] )
{
int i;
/* Oddball length encoding with leading zero(es) */
for( i = 0; i < noLengthOctets && !buffer[ i ]; i++ );
if( noLengthOctets - i > ( shortLen ? 2 : 4 ) )
{
/* > 32-bit length, this should never happen */
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
if( i >= noLengthOctets )
return( 0 ); /* Very broken encoding of a zero length */
noLengthOctets -= i;
bufPtr += i; /* Skip leading zero(es) */
}
else
{
if( shortLen && noLengthOctets > 2 )
{
sSetError( stream, CRYPT_ERROR_OVERFLOW );
return( CRYPT_ERROR_OVERFLOW );
}
if( noLengthOctets > 4 )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
}
length = 0;
while( noLengthOctets-- > 0 )
length = length << 8 | *bufPtr++;
if( shortLen )
{
if( length & 0xFFFF8000UL )
{
/* Length must be < 32K for short lengths */
sSetError( stream, CRYPT_ERROR_OVERFLOW );
return( CRYPT_ERROR_OVERFLOW );
}
}
else
if( ( length & 0x80000000UL ) || length > MAX_INTLENGTH )
{
/* Length must be < MAX_INTLENGTH for standard data */
sSetError( stream, CRYPT_ERROR_OVERFLOW );
return( CRYPT_ERROR_OVERFLOW );
}
if( length < 0 )
{
/* Shouldn't happen since the above check catches it, but we check
again just to be safe */
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
return( length );
}
/* Read a constrained-length data value, used by several routines */
static int readConstrainedData( STREAM *stream, BYTE *buffer,
int *bufferLength, const int length,
const int maxLength )
{
int dataLength = length, remainder = 0;
if( bufferLength != NULL )
*bufferLength = length;
/* If we don't care about the return value, skip it and exit */
if( buffer == NULL )
return( sSkip( stream, dataLength ) );
/* Read in the object, limiting the size to the maximum buffer size */
if( dataLength > maxLength )
{
remainder = dataLength - maxLength;
dataLength = maxLength;
}
if( dataLength > 0 )
{
sread( stream, buffer, dataLength );
*bufferLength = dataLength;
}
/* Skip any remaining data if necessary */
if( remainder > 0 )
sSkip( stream, remainder );
return( sGetStatus( stream ) );
}
/* Read a short (<= 256 bytes) raw object without decoding it. This is used
to read short data blocks like object identifiers, which are only ever
handled in encoded form */
int readRawObjectTag( STREAM *stream, BYTE *buffer, int *bufferLength,
const int maxLength, const int expectedTag )
{
int length, offset = 0, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( bufferLength, sizeof( int ) ) );
assert( maxLength > 0 );
/* Clear return value */
if( buffer != NULL )
*buffer = '\0';
*bufferLength = 0;
/* Read the identifier field and length. Since we need to remember each
byte as it's read we can't just call readLengthValue() for the length,
but since we only need to handle lengths that can be encoded in one
or two bytes this isn't much of a problem */
if( expectedTag != NO_TAG )
{
const int tag = readTag( stream );
if( expectedTag != CRYPT_UNUSED && expectedTag != tag )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
if( buffer != NULL )
buffer[ offset++ ] = tag;
}
length = sgetc( stream );
if( buffer != NULL )
buffer[ offset++ ] = length;
if( length & 0x80 )
{
length &= 0x7F;
if( length <= 0 || length > 1 )
{
/* If the object is indefinite-length or longer than 256 bytes,
we don't want to handle it */
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
length = sgetc( stream );
if( buffer != NULL )
buffer[ offset++ ] = length;
}
if( cryptStatusError( length ) )
return( length );
/* Read in the rest of the data, adjusting the length for the header data
that we've already read */
status = readConstrainedData( stream, buffer + offset, bufferLength,
length, maxLength - offset );
if( cryptStatusOK( status ) )
*bufferLength += offset;
return( status );
}
/* Read a (short) numeric value, used by several routines */
static int readNumeric( STREAM *stream, long *value )
{
BYTE buffer[ 8 ], *bufPtr = buffer;
int length, status;
/* Clear return value */
if( value != NULL )
*value = 0L;
/* Read the length field and make sure that it's a short value, and read
the data */
length = sgetc( stream );
if( length <= 0 )
return( length ); /* Error or zero length */
if( length > 4 )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
status = sread( stream, buffer, length );
if( cryptStatusError( status ) || value == NULL )
return( status );
while( length-- > 0 )
*value = ( *value << 8 ) | *bufPtr++;
return( CRYPT_OK );
}
/* Read a large integer value */
int readIntegerTag( STREAM *stream, BYTE *integer, int *integerLength,
const int maxLength, const int tag )
{
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( maxLength > 0 );
/* Clear return value */
if( integer != NULL )
*integer = '\0';
if( integerLength != NULL )
*integerLength = 0;
/* Read the identifier field if necessary and the length */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_INTEGER ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
length = readLengthValue( stream, READLENGTH_SHORT );
if( length <= 0 )
return( length ); /* Error or zero length */
/* ASN.1 encoded values are signed while the internal representation is
unsigned, so we skip any leading zero bytes needed to encode a value
that has the high bit set */
if( sPeek( stream ) == 0 )
{
sgetc( stream );
length--; /* Skip the zero byte */
}
if( length == 0 )
return( CRYPT_OK ); /* Zero value */
/* Read in the numeric value, limiting the size to the maximum buffer
size. This is safe because the only situation where this can occur
is when reading some blob (whose value we don't care about) dressed
up as an integer rather than for any real integer */
return( readConstrainedData( stream, integer, integerLength, length,
maxLength ) );
}
/* Read a bignum integer value */
int readBignumTag( STREAM *stream, void *bignum, const int tag )
{
BYTE buffer[ CRYPT_MAX_PKCSIZE ];
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( bignum, sizeof( BIGNUM ) ) );
/* Read the identifier field if necessary and the length */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_INTEGER ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
length = readLengthValue( stream, READLENGTH_SHORT );
if( length <= 0 )
return( length ); /* Error or zero length */
/* ASN.1 encoded values are signed while the internal representation is
unsigned, so we skip any leading zero bytes needed to encode a value
that has the high bit set */
if( sPeek( stream ) == 0 )
{
sgetc( stream );
length--; /* Skip the zero byte */
}
if( length == 0 )
return( CRYPT_OK ); /* Zero value */
/* Read the value into a fixed buffer */
if( length > CRYPT_MAX_PKCSIZE )
{
sSetError( stream, CRYPT_ERROR_OVERFLOW );
return( sGetStatus( stream ) );
}
status = sread( stream, buffer, length );
if( !cryptStatusError( status ) )
{
if( BN_bin2bn( buffer, length, bignum ) == NULL )
{
sSetError( stream, CRYPT_ERROR_MEMORY );
status = CRYPT_ERROR_MEMORY;
}
zeroise( buffer, CRYPT_MAX_PKCSIZE );
}
return( status );
}
/* Read a universal type and discard it (used to skip unknown or unwanted
types) */
int readUniversalData( STREAM *stream )
{
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
length = readLengthValue( stream, READLENGTH_SHORT );
if( length <= 0 )
return( length ); /* Error or zero length */
return( sSkip( stream, length ) );
}
int readUniversal( STREAM *stream )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
readTag( stream );
return( readUniversalData( stream ) );
}
/* Read a short integer value */
int readShortIntegerTag( STREAM *stream, long *value, const int tag )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Clear return value */
if( value != NULL )
*value = 0L;
/* Read the identifier field if necessary */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_INTEGER ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
/* Read the numeric field */
return( readNumeric( stream, value ) );
}
/* Read an enumerated value. This is encoded like an ASN.1 integer so we
just read it as such */
int readEnumeratedTag( STREAM *stream, int *enumeration, const int tag )
{
long value;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Clear return value */
if( enumeration != NULL )
*enumeration = 0;
/* Read the identifier field if necessary */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_ENUMERATED ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -