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

📄 asn1_rd.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*								ASN.1 Read Routines							*
*						Copyright Peter Gutmann 1992-2004					*
*																			*
****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "bn.h"
  #include "asn1.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../bn/bn.h"
  #include "asn1.h"
#else
  #include "crypt.h"
  #include "bn/bn.h"
  #include "misc/asn1.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*								Utility Routines							*
*																			*
****************************************************************************/

/* When specifying a tag, we can use either the default tag for the object
   (given with DEFAULT_TAG) or a special-case tag.  The following macro
   selects the correct value.  Since these are all primitive objects, we
   force the tag type to a primitive tag */

#define selectTag( tag, default )	\
		( ( ( tag ) == DEFAULT_TAG ) ? ( default ) : \
									   ( MAKE_CTAG_PRIMITIVE( tag ) ) )

/* Read the length octets for an ASN.1 data type, with special-case handling
   for long and short lengths and indefinite-length encodings.  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[ 16 ], *bufPtr = buffer;
	BOOLEAN shortLen = ( readType == READLENGTH_SHORT || \
						 readType == READLENGTH_SHORT_INDEF );
	long length;
	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 */
	noLengthOctets = length & 0x7F;
	if( noLengthOctets <= 0 )
		{
		/* If indefinite lengths aren't allowed, signal an error */
		if( readType != READLENGTH_SHORT_INDEF && \
			readType != READLENGTH_LONG_INDEF )
			return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

		/* Indefinite length encoding, warn the caller */
		return( OK_SPECIAL );
		}
	if( noLengthOctets > 8 )
		status = CRYPT_ERROR_BADDATA;
	else
		status = sread( stream, buffer, noLengthOctets );
	if( cryptStatusError( status ) )
		return( sSetError( stream, status ) );

	/* Handle leading zero 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 (for short or long lengths 
	   respectively) can be nonzero */
	if( !buffer[ 0 ] )
		{
		int i;

		/* Oddball length encoding with leading zero(es) */
		for( i = 0; i < noLengthOctets && !buffer[ i ]; i++ );
		noLengthOctets -= i;
		if( noLengthOctets <= 0 )
			return( 0 );		/* Very broken encoding of a zero length */
		bufPtr += i;			/* Skip leading zero(es) */
		}

	/* Make sure that the length size is reasonable */
	if( shortLen && noLengthOctets > 2 )
		return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
	if( noLengthOctets > 4 )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	/* Read and check the length value */
	length = 0;
	while( noLengthOctets-- > 0 )
		length = length << 8 | *bufPtr++;
	if( shortLen )
		{
		if( length & 0xFFFF8000UL )
			/* Length must be < 32K for short lengths */
			return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
		}
	else
		if( ( length & 0x80000000UL ) || length > MAX_INTLENGTH )
			/* Length must be < MAX_INTLENGTH for standard data */
			return( sSetError( stream, CRYPT_ERROR_OVERFLOW ) );
	if( length < 0 )
		/* Shouldn't happen since the above check catches it, but we check
		   again just to be safe */
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	return( length );
	}

/* Read the header for a (signed) integer value */

static int readIntegerHeader( STREAM *stream, const int tag )
	{
	int length;

	/* Read the identifier field if necessary and the length */
	if( tag != NO_TAG && readTag( stream ) != selectTag( tag, BER_INTEGER ) )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	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 we get a value with the (supposed) 
	   sign bit set we treat it as an unsigned value, since a number of 
	   implementations get this wrong */
	while( length > 0 && sPeek( stream ) == 0 )
		{
		int status;

		status = sgetc( stream );
		if( cryptStatusError( status ) )
			return( status );
		length--;
		}
	return( length );
	}

/* Read the header for a constructed object */

static int readObjectTag( STREAM *stream, const int tag )
	{
	int tagValue;

	tagValue = readTag( stream );
	if( cryptStatusError( tagValue ) )
		return( tagValue );
	if( tag == ANY_TAG )
		{
		/* Even if we're prepared to accept (almost) any tag, we still have 
		   to check for valid universal tags: BIT STRING, primitive or 
		   constructed OCTET STRING, SEQUENCE, or SET */
		if( ( tagValue & BER_CLASS_MASK ) != BER_CONTEXT_SPECIFIC && \
			tagValue != BER_BITSTRING && tagValue != BER_OCTETSTRING && \
			tagValue != ( BER_OCTETSTRING | BER_CONSTRUCTED ) && \
			tagValue != BER_SEQUENCE && tagValue != BER_SET )
			return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
		}
	else
		if( tagValue != tag )
			return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	return( CRYPT_OK );
	}

static int readObjectHeader( STREAM *stream, int *length, const int tag,
							 const BOOLEAN isBitString, 
							 const BOOLEAN indefOK )
	{
	int dataLength, status;

	/* Clear return value */
	if( length != NULL )
		*length = 0;

	/* Read the object tag */
	status = readObjectTag( stream, tag );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the length.  If the indefiniteOK flag is set or the length is 
	   being ignored by the caller we allow indefinite lengths.  The latter
	   is because it makes handling of infinitely-nested SEQUENCEs and 
	   whatnot easier if we don't have to worry about definite vs. 
	   indefinite-length encoding, and if indefinite lengths really aren't 
	   OK then they'll be picked up when the caller runs into the EOC at the
	   end of the object */
	dataLength = readLengthValue( stream, ( indefOK || length == NULL ) ? \
								  READLENGTH_SHORT_INDEF : READLENGTH_SHORT );
	if( cryptStatusError( dataLength ) )
		{
		/* If we've asked for an indication of indefinite-length values and we
		   got one, convert the length to CRYPT_UNUSED */
		if( indefOK && dataLength == OK_SPECIAL )
			dataLength = CRYPT_UNUSED;
		else
			return( dataLength );
		}

	/* If it's a bit string there's an extra unused-bits count */
	if( isBitString )
		{
		int value;

		if( dataLength != CRYPT_UNUSED )
			{
			dataLength--;
			if( dataLength < 0 )
				return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
			}
		value = sgetc( stream );
		if( cryptStatusError( value ) )
			return( value );
		}

	if( length != NULL )
		*length = dataLength;
	return( CRYPT_OK );
	}

static int readLongObjectHeader( STREAM *stream, long *length, const int tag )
	{
	long dataLength;
	int status;

	/* Clear return value */
	if( length != NULL )
		*length = 0;

	/* Read the object tag */
	status = readObjectTag( stream, tag );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the length */
	dataLength = readLengthValue( stream, READLENGTH_LONG_INDEF );
	if( cryptStatusError( dataLength ) )
		{
		/* We've asked for an indication of indefinite-length values, if we
		   got one convert the length to CRYPT_UNUSED */
		if( dataLength == OK_SPECIAL )
			dataLength = CRYPT_UNUSED;
		else
			return( dataLength );
		}
	if( length != NULL )
		*length = dataLength;

	return( CRYPT_OK );
	}

/* 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 */
	length = readIntegerHeader( stream, NO_TAG );
	if( length <= 0 )
		return( length );	/* Error or zero length */
	if( length > 4 )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	/* Read the data */
	status = sread( stream, buffer, length );
	if( cryptStatusError( status ) || value == NULL )
		return( status );
	while( length-- > 0 )
		*value = ( *value << 8 ) | *bufPtr++;

	return( CRYPT_OK );
	}

/* 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, status;

	assert( length > 0 && maxLength > 0 );

	if( bufferLength != NULL )
		*bufferLength = dataLength;

	/* If we don't care about the return value, skip it and exit */
	if( buffer == NULL )
		return( sSkip( stream, dataLength ) );

	/* Read the object, limiting the size to the maximum buffer size */
	if( dataLength > maxLength )
		{
		remainder = dataLength - maxLength;
		dataLength = maxLength;
		*bufferLength = dataLength;
		}
	status = sread( stream, buffer, dataLength );

	/* Skip any remaining data if necessary */
	if( remainder > 0 && cryptStatusOK( status ) )
		status = sSkip( stream, remainder );

	return( status );
	}

/****************************************************************************
*																			*
*						Read Routines for Primitive Objects					*
*																			*
****************************************************************************/

/* Check for constructed data end-of-contents octets */

int checkEOC( STREAM *stream )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	/* Read the tag and check for an EOC octet pair */
	if( peekTag( stream ) != BER_EOC )
		return( FALSE );
	readTag( stream );
	if( sgetc( stream ) != 0 )
		/* After finding an EOC tag we need to have a length of zero */
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	return( TRUE );
	}

/* 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -