📄 asn1_rd.c
字号:
assert( isWritePtr( stream, sizeof( STREAM ) ) );
REQUIRES_S( tag == NO_TAG || tag == DEFAULT_TAG || \
( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Read the identifier if necessary */
if( tag != NO_TAG && readTag( stream ) != selectTag( tag, BER_NULL ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
value = sgetc( stream );
if( cryptStatusError( value ) )
return( value );
if( value != 0 )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
return( CRYPT_OK );
}
/* Read a boolean value */
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readBooleanTag( INOUT STREAM *stream,
OUT_OPT_BOOL BOOLEAN *boolean,
IN_TAG_EXT const int tag )
{
BYTE buffer[ 2 + 8 ];
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( boolean == NULL || \
isWritePtr( boolean, sizeof( BOOLEAN ) ) );
REQUIRES_S( tag == NO_TAG || tag == DEFAULT_TAG || \
( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Clear return value */
if( boolean != NULL )
*boolean = FALSE;
if( tag != NO_TAG && readTag( stream ) != selectTag( tag, BER_BOOLEAN ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
status = sread( stream, buffer, 2 );
if( cryptStatusError( status ) )
return( status );
if( buffer[ 0 ] != 1 )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( boolean != NULL )
*boolean = ( buffer[ 1 ] != 0 ) ? TRUE : FALSE;
return( CRYPT_OK );
}
/* Read an OID and check it against a permitted value or a selection of
permitted values */
RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readOIDEx( INOUT STREAM *stream,
IN_ARRAY( noOidSelectionEntries ) const OID_INFO *oidSelection,
IN_RANGE( 1, 50 ) const int noOidSelectionEntries,
OUT_OPT_PTR const OID_INFO **oidSelectionValue )
{
static const OID_INFO nullOidSelection = { NULL, CRYPT_ERROR, NULL };
BYTE buffer[ MAX_OID_SIZE + 8 ];
int length, oidEntry, iterationCount, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( oidSelection, \
sizeof( OID_INFO ) * noOidSelectionEntries ) );
assert( oidSelectionValue == NULL || \
isReadPtr( oidSelectionValue, sizeof( OID_INFO * ) ) );
REQUIRES_S( noOidSelectionEntries > 0 && noOidSelectionEntries <= 50 );
/* Clear return value */
if( oidSelectionValue != NULL )
*oidSelectionValue = &nullOidSelection;
/* Read the OID data */
status = readRawObject( stream, buffer, MAX_OID_SIZE, &length,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
ENSURES_S( length == sizeofOID( buffer ) );
/* Try and find the entry for the OID. Since related groups of OIDs
typically have identical lengths, we use the last byte of the OID
as a quick-reject check to avoid performing a full OID comparison
for each entry */
for( oidEntry = 0, iterationCount = 0;
oidSelection[ oidEntry ].oid != NULL && \
oidEntry < noOidSelectionEntries && \
iterationCount < FAILSAFE_ITERATIONS_MED;
oidEntry++, iterationCount++ )
{
const BYTE *oidPtr = oidSelection[ oidEntry ].oid;
/* Check for a match-any wildcard OID */
if( sizeofOID( oidPtr ) == WILDCARD_OID_SZE && \
!memcmp( oidPtr, WILDCARD_OID, WILDCARD_OID_SZE ) )
{
/* The wildcard must be the last entry in the list */
ENSURES_S( oidSelection[ oidEntry + 1 ].oid == NULL );
break;
}
/* Check for a standard OID match */
if( length == sizeofOID( oidPtr ) && \
buffer[ length - 1 ] == oidPtr[ length - 1 ] && \
!memcmp( buffer, oidPtr, length ) )
break;
}
ENSURES_S( oidEntry < noOidSelectionEntries && \
iterationCount < FAILSAFE_ITERATIONS_MED );
if( oidSelection[ oidEntry ].oid == NULL )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( oidSelectionValue != NULL )
*oidSelectionValue = &oidSelection[ oidEntry ];
return( CRYPT_OK );
}
RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int readOID( INOUT STREAM *stream,
IN_ARRAY( noOidSelectionEntries ) const OID_INFO *oidSelection,
IN_RANGE( 1, 50 ) const int noOidSelectionEntries,
OUT_RANGE( CRYPT_ERROR, \
noOidSelectionEntries ) int *selectionID )
{
const OID_INFO *oidSelectionInfo;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( oidSelection, \
sizeof( OID_INFO ) * noOidSelectionEntries ) );
assert( isWritePtr( selectionID, sizeof( int ) ) );
REQUIRES_S( noOidSelectionEntries > 0 && noOidSelectionEntries <= 50 );
/* Clear return value */
*selectionID = CRYPT_ERROR;
status = readOIDEx( stream, oidSelection, noOidSelectionEntries,
&oidSelectionInfo );
if( cryptStatusOK( status ) )
*selectionID = oidSelectionInfo->selectionID;
return( status );
}
RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readFixedOID( INOUT STREAM *stream,
IN_BUFFER( oidLength ) const BYTE *oid,
IN_LENGTH_OID const int oidLength )
{
CONST_INIT_STRUCT_A2( OID_INFO oidInfo[ 3 ], oid, NULL );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( oid, oidLength ) && \
oidLength == sizeofOID( oid ) && \
oid[ 0 ] == BER_OBJECT_IDENTIFIER );
REQUIRES_S( oidLength == sizeofOID( oid ) && \
oid[ 0 ] == BER_OBJECT_IDENTIFIER );
REQUIRES_S( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
/* Set up a one-entry OID_INFO list to pass down to readOID() */
CONST_SET_STRUCT_A( memset( oidInfo, 0, sizeof( OID_INFO ) * 3 ); \
oidInfo[ 0 ].oid = oid );
return( readOIDEx( stream, oidInfo, 3, NULL ) );
}
/* Read a raw OID in encoded form */
RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int readEncodedOID( INOUT STREAM *stream,
OUT_BUFFER( oidMaxLength, *oidLength ) BYTE *oid,
IN_LENGTH_SHORT_MIN( 5 ) const int oidMaxLength,
OUT_LENGTH_SHORT_Z int *oidLength,
IN_TAG_ENCODED const int tag )
{
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( oid, oidMaxLength ) );
assert( isWritePtr( oidLength, sizeof( int ) ) );
REQUIRES_S( oidMaxLength >= MIN_OID_SIZE && \
oidMaxLength < MAX_INTLENGTH_SHORT );
REQUIRES_S( tag == NO_TAG || tag == BER_OBJECT_IDENTIFIER );
/* Clear return values */
memset( oid, 0, min( 16, oidMaxLength ) );
*oidLength = 0;
/* Read the encoded OID and make sure that it's the right size for a
minimal-length OID: tag (optional) + length + minimal-length OID
data */
status = readRawObject( stream, oid, oidMaxLength, &length, tag );
if( cryptStatusError( status ) )
return( status );
if( length < ( tag == NO_TAG ? 0 : 1 ) + 1 + 3 || length > oidMaxLength )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
*oidLength = length;
return( CRYPT_OK );
}
/* Read an octet string value */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int readString( INOUT STREAM *stream,
OUT_BUFFER_OPT( maxLength, *stringLength ) BYTE *string,
OUT_LENGTH_SHORT_Z int *stringLength,
IN_LENGTH_SHORT const int minLength,
IN_LENGTH_SHORT const int maxLength,
IN_TAG_EXT const int tag,
const BOOLEAN isOctetString )
{
long length;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( ( string == NULL ) || \
isWritePtr( string, maxLength ) );
assert( isWritePtr( stringLength, sizeof( int ) ) );
REQUIRES_S( minLength > 0 && minLength <= maxLength && \
maxLength < MAX_INTLENGTH_SHORT );
REQUIRES_S( ( isOctetString && \
( tag == NO_TAG || tag == DEFAULT_TAG ) ) || \
( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Clear return values */
if( string != NULL )
memset( string, 0, min( 16, maxLength ) );
*stringLength = 0;
/* Read the string, limiting the size to the maximum buffer size. If
it's an octet string we make this a hard limit, however if it's a
text string we simply read as much as will fit in the buffer and
discard the rest. This is required to handle the widespread ignoring
of string length limits in certificates and other PKI-related data */
if( isOctetString )
{
if( tag != NO_TAG && \
readTag( stream ) != selectTag( tag, BER_OCTETSTRING ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
}
else
{
if( readTag( stream ) != tag )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
}
status = readLengthValue( stream, &length, READLENGTH_SHORT );
if( cryptStatusError( status ) )
return( status );
if( length < minLength )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( isOctetString && length > maxLength )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( length <= 0 )
return( length ); /* Zero length */
return( readConstrainedData( stream, string, maxLength, stringLength,
length ) );
}
RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int readOctetStringTag( INOUT STREAM *stream,
OUT_BUFFER( maxLength, *stringLength ) BYTE *string,
OUT_LENGTH_SHORT_Z int *stringLength,
IN_LENGTH_SHORT const int minLength,
IN_LENGTH_SHORT const int maxLength,
IN_TAG_EXT const int tag )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( string == NULL || isWritePtr( string, maxLength ) );
assert( stringLength == NULL || \
isWritePtr( stringLength, sizeof( int ) ) );
REQUIRES_S( minLength > 0 && minLength <= maxLength && \
maxLength < MAX_INTLENGTH_SHORT );
REQUIRES_S( tag == NO_TAG || tag == DEFAULT_TAG || \
( tag >= 0 && tag < MAX_TAG_VALUE ) );
return( readString( stream, string, stringLength, minLength, maxLength, \
tag, TRUE ) );
}
/* Read a character string. This handles any of the myriad ASN.1 character
string types. The handling of the tag works somewhat differently here to
the usual manner in that since the function is polymorphic, the tag
defines the character string type and is always used (there's no
NO_TAG or DEFAULT_TAG option like the other functions use). This works
because the plethora of string types means that the higher-level routines
that read them invariably have to sort out the valid tag types
themselves */
RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int readCharacterString( INOUT STREAM *stream,
OUT_BUFFER( stringMaxLength, *stringLength ) BYTE *string,
IN_LENGTH_SHORT const int stringMaxLength,
OUT_LENGTH_SHORT_Z int *stringLength,
IN_TAG_EXT const int tag )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( string == NULL || isWritePtr( string, stringMaxLength ) );
assert( stringLength == NULL || \
isWritePtr( stringLength, sizeof( int ) ) );
REQUIRES_S( stringMaxLength > 0 && \
stringMaxLength < MAX_INTLENGTH_SHORT );
REQUIRES_S( tag >= 0 && tag < MAX_TAG_VALUE );
return( readString( stream, string, stringLength, 1, stringMaxLength, \
tag, FALSE ) );
}
/* Read a bit string */
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readBitStringTag( INOUT STREAM *stream,
OUT_OPT_INT_Z int *bitString,
IN_TAG_EXT const int tag )
{
int length, data, mask = 0x80, flag = 1, value = 0, noBits, i;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( bitString == NULL || isWritePtr( bitString, sizeof( int ) ) );
REQUIRES_S( tag == NO_TAG || tag == DEFAULT_TAG || \
( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Clear return value */
if( bitString != NULL )
*bitString = 0;
/* Make sure that 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 CMP's
bizarre encoding of error subcodes that just provide further
information above and beyond the main error code and text message,
and CMP is highly unlikely to be used on a 16-bit machine */
if( tag != NO_TAG && readTag( stream ) != selectTag( tag, BER_BITSTRING ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
length = sgetc( stream ) - 1; /* -1 for bit count */
noBits = sgetc( stream );
if( cryptStatusError( noBits ) )
return( noBits );
if( length < 0 || length > 4 || length > sizeof( int ) || \
noBits < 0 || noBits > 7 )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( length <= 0 )
return( CRYPT_OK ); /* Zero value */
ENSURES_S( length >= 1 && length <= sizeof( int ) );
ENSURES_S( noBits >= 0 && noBits <= 7 );
/* Convert the bit count from the unused-remainder bit count into the
total bit count */
noBits = ( length * 8 ) - noBits;
ENSURES( noBits >= 0 && noBits <= 32 );
/* ASN.1 bitstrings start at bit 0 so we need to reverse the order of
the bits before we return the value. This uses a straightforward way
of doing it rather than the more efficient but obscure:
data = ( data & 0x55555555 ) << 1 | ( data >> 1 ) & 0x55555555;
data = ( data & 0x33333333 ) << 2 | ( data >> 2 ) & 0x33333333;
data = ( data & 0x0F0F0F0F ) << 4 | ( data >> 4 ) & 0x0F0F0F0F;
data = ( data << 24 ) | ( ( data & 0xFF00 ) << 8 ) | \
( ( data >> 8 ) & 0xFF00 || ( data >> 24 );
which swaps adjacent bits, then 2-bit fields, then 4-bit fields, and
so on */
data = sgetc( stream );
if( cryptStatusError( data ) )
return( data );
for( i = 1; i < length; i++ )
{
const int dataTmp = sgetc( stream );
if( cryptStatusError( dataTmp ) )
return( dataTmp );
data = ( data << 8 ) | dataTmp;
if( data < 0 || data >= MAX_INTLENGTH )
{
/* Integer overflow */
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
}
mask <<= 8;
}
for( i = 0; i < noBits; i++ )
{
if( data & mask )
value |= flag;
flag <<= 1;
data <<= 1;
}
if( bitString != NULL )
{
if( value < 0 || value >= MAX_INTLENGTH )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
*bitString = value;
}
return( CRYPT_OK );
}
/* Read a UTCTime and GeneralizedTime value */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readTime( INOUT STREAM *stream, OUT time_t *timePtr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -