📄 asn1.c
字号:
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 */
bufPtr = buffer + i;
}
else
if( noLengthOctets > ( shortLen ? 2 : 4 ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
length = 0;
while( noLengthOctets-- > 0 )
length = length << 8 | *bufPtr++;
if( length & ( shortLen ? 0xFFFF8000UL : 0xC0000000UL ) )
{
/* Length must be < 1GB for standard data, < 32K for short lengths */
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 );
/* Read in 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;
/* Clear return value */
*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 readShortLength() for the length,
but since we only need to handle lengths which 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 ) );
}
buffer[ offset++ ] = tag;
}
length = sgetc( stream );
buffer[ offset++ ] = length;
if( length & 0x80 )
{
if( ( length & 0x7F ) > 1 )
{
/* If the object is longer than 256 bytes, we don't want to
handle it */
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
length = sgetc( stream );
buffer[ offset++ ] = length;
}
if( cryptStatusError( length ) )
return( length );
/* Read in the rest of the data, adjusting the length for the header data
which 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 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 bignum integer value */
int readIntegerTag( STREAM *stream, BYTE *integer, int *integerLength,
const int maxLength, const int tag )
{
int length, remainder = 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 = readShortLength( stream );
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
which has the high bit set */
if( sgetc( stream ) )
sungetc( stream ); /* It's not zero, put it back */
else
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 universal type and discard it (used to skip unknown or unwanted
types) */
int readUniversalData( STREAM *stream )
{
int length;
length = readShortLength( stream );
if( length <= 0 )
return( length ); /* Error or zero length */
return( sSkip( stream, length ) );
}
int readUniversal( STREAM *stream )
{
readTag( stream );
return( readUniversalData( stream ) );
}
/* Read a short integer value */
int readShortIntegerTag( STREAM *stream, long *value, const int tag )
{
/* 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;
/* 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 ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
/* Read the numeric field */
status = readNumeric( stream, &value );
if( cryptStatusOK( status ) && enumeration != NULL )
*enumeration = ( int ) value;
return( status );
}
/* Read a null value */
int readNullTag( STREAM *stream, const int tag )
{
/* Read the identifier if necessary */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_NULL ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
/* Skip the length octet */
if( sgetc( stream ) )
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
/* Read a boolean value */
int readBooleanTag( STREAM *stream, BOOLEAN *boolean, const int tag )
{
int value;
/* Clear return value */
if( boolean != NULL )
*boolean = FALSE;
/* Read the identifier if necessary */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_BOOLEAN ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
/* Skip the length octet and read the boolean value */
if( sgetc( stream ) != 1 )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
value = sgetc( stream );
if( !cryptStatusError( value ) && boolean != NULL )
*boolean = value ? TRUE : FALSE;
return( sGetStatus( stream ) );
}
/* Read an octet string value */
int readOctetStringTag( STREAM *stream, BYTE *string, int *stringLength,
const int maxLength, const int tag )
{
int length, remainder = 0;
/* Clear return value */
if( string != NULL )
{
*string = '\0';
*stringLength = 0;
}
/* Read the identifier field if necessary */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_OCTETSTRING ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
/* Now read in the string, limiting the size to the maximum buffer size */
length = readShortLength( stream );
if( length <= 0 )
return( length ); /* Error or zero length */
return( readConstrainedData( stream, string, stringLength, length,
maxLength ) );
}
/* Read a bit string */
int readBitStringTag( STREAM *stream, int *bitString, const int tag )
{
unsigned int data, mask = 0x80;
int length, flag = 1, value = 0, noBits, i;
/* Clear return value */
if( bitString != NULL )
*bitString = 0;
/* Read the identifier field if necessary */
if( tag != NO_TAG )
{
if( readTag( stream ) != selectTag( tag, BER_BITSTRING ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( sGetStatus( stream ) );
}
}
/* Make sure we have a bitstring with between 0 and sizeof( int ) bits.
This isn't as machine-dependant as it seems, the only place where
bit strings longer than one or two bytes are used is with the more
obscure CMP error subcodes which just provide further information
above and beyond the main error code and text message, so we provide
the extra information if the machine architecture can handle it and
skip it otherwise */
length = sgetc( stream ) - 1;
noBits = sgetc( stream );
if( length < 0 || length > sizeof( int ) || noBits < 0 || noBits > 7 )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
if( length == 0 )
return( CRYPT_OK ); /* Zero value */
noBits = ( length * 8 ) - noBits;
/* ASN.1 bitstrings start at bit 0, so we need to reverse the order of
the bits */
data = sgetc( stream );
for( i = noBits - 8; i > 0; i -= 8 )
{
data = ( data << 8 ) | sgetc( stream );
mask <<= 8;
}
for( i = 0; i < noBits; i++ )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -