⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asn1_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -