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

📄 asn1.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 4 页
字号:
		if( data & mask )
			value |= flag;
		flag <<= 1;
		data <<= 1;
		}
	if( bitString != NULL )
		*bitString = value;

	return( sGetStatus( stream ) );
	}

/* Read a UTCTime and GeneralizedTime value */

static int getDigits( const BYTE *bufPtr )
	{
	int result, ch = *bufPtr++;

	if( !isdigit( ch ) )
		return( -1 );
	result = ( ch - '0' ) * 10;
	ch = *bufPtr++;
	if( !isdigit( ch ) )
		return( -1 );
	return( result + ( ch - '0' ) );
	}

static int readTime( STREAM *stream, time_t *timePtr, const BOOLEAN isUTCTime )
	{
	BYTE buffer[ 32 ], *bufPtr = buffer;
	struct tm theTime,  *gm_tm;
	time_t utcTime, gmTime, localTime;
	int value = 0, length, status;

	/* Read the length field and make sure it's of the correct size.  There's
	   only one encoding allowed although in theory the encoded value could 
	   range in length from 11 to 17 bytes for UTCTime and 13 to 19 bytes for
	   GeneralizedTime.  In practice we also have to allow 11-byte UTCTime's
	   since an obsolete encoding rule allowed the time to be encoded without
	   seconds, and Sweden Post haven't realised that this has changed yet */
	length = sgetc( stream );
	if( ( isUTCTime && length != 13 && length != 11 ) || \
		( !isUTCTime && length != 15 ) )
		{
		sSetError( stream, CRYPT_ERROR_BADDATA );
		return( sGetStatus( stream ) );
		}

	/* Read the encoded time data */
	memset( buffer, 0, 32 );
	status = sread( stream, buffer, length );
	if( cryptStatusError( status ) )
		return( status );

	/* Decode the time fields.  Ideally we should use sscanf(), but there
	   are too many dodgy versions of this around */
	memset( &theTime, 0, sizeof( struct tm ) );
	theTime.tm_isdst = -1;		/* Get the system to adjust for DST */
	if( !isUTCTime )
		{
		value = ( getDigits( bufPtr ) - 19 ) * 100;	/* Read the century */
		bufPtr += 2;
		length -= 2;
		}
	theTime.tm_year = getDigits( bufPtr ) + value;
	theTime.tm_mon = getDigits( bufPtr + 2 ) - 1;
	theTime.tm_mday = getDigits( bufPtr + 4 );
	theTime.tm_hour = getDigits( bufPtr + 6 );
	theTime.tm_min = getDigits( bufPtr + 8 );

	/* Read the seconds field if there's one present */
	if( length == 13 )
		{
		theTime.tm_sec = getDigits( bufPtr + 10 );
		if( bufPtr[ 12 ] != 'Z' )
			status = CRYPT_ERROR_BADDATA;
		}
	else
		if( length != 11 || bufPtr[ 10 ] != 'Z' )
			status = CRYPT_ERROR_BADDATA;

	/* Make sure there were no format errors */
	if( cryptStatusOK( status ) && \
		( theTime.tm_year | theTime.tm_mon | theTime.tm_mday | \
		  theTime.tm_hour | theTime.tm_min | theTime.tm_sec ) < 0 )
		status = CRYPT_ERROR_BADDATA;
	if( cryptStatusError( status ) )
		{
		sSetError( stream, status );
		return( status );
		}

	/* Finally, convert it to the local time.  Since the UTCTime format
	   doesn't take centuries into account (and you'd think that when the ISO
	   came up with the world's least efficient time encoding format they
	   could have spared another two bytes to fully specify the year), we
	   have to adjust by one century for years < 50 (and hope there aren't
	   any Y2K bugs in mktime()) if the format is UTCTime.  Note that there
	   are some implementations which currently roll over a century from 1970
	   (the Unix/Posix epoch and sort-of ISO/ANSI C epoch although they never
	   come out and say it), but hopefully these will be fixed by 2050.

		"The time is out of joint; o cursed spite,
		 That ever I was born to set it right"	- Shakespeare, "Hamlet" */
	if( isUTCTime && theTime.tm_year < 50 )
		theTime.tm_year += 100;
	utcTime = mktime( &theTime );
	if( utcTime == -1 )
		{
		sSetError( stream, CRYPT_ERROR_BADDATA );
		return( CRYPT_ERROR_BADDATA );
		}

	/* Convert the UTC time to local time.  This is complicated by the fact 
	   that although the C standard library can convert from local time -> 
	   UTC, it can't convert the time back, so we calculate the local offset 
	   from UTC and adjust the time as appropriate.  Since we can't assume 
	   that time_t is signed, we have to treat a negative and positive offset 
	   separately.  An extra complication is added by daylight savings time 
	   adjustment, some systems adjust for DST by default, some don't, and 
	   some allow you to set it in the Control Panel so it varies from 
	   machine to machine (thanks Bill!), so we have to make it explicit as 
	   part of the conversion process.  Even this still isn't perfect 
	   because it displays the time adjusted for DST now rather than DST 
	   when the cert was created, however this problem is more or less 
	   undecidable, the code used here has the property that the values for 
	   Windows agree with those for Unix and everything else which is the 
	   main thing */
	localTime = time( NULL );
	gm_tm = gmtime( &localTime );
	gm_tm->tm_isdst = -1;		/* Force correct DST adjustment */
	gmTime = mktime( gm_tm );
	if( timePtr != NULL )
		if( localTime < gmTime )
			*timePtr = utcTime - ( gmTime - localTime );
		else
			*timePtr = utcTime + ( localTime - gmTime );

	return( CRYPT_OK );
	}

int readUTCTimeTag( STREAM *stream, time_t *timeVal, const int tag )
	{
	/* Clear return value */
	if( timeVal != NULL )
		*timeVal = 0;
	
	/* Read the identifier field if necessary */
	if( tag != NO_TAG )
		{
		if( readTag( stream ) != selectTag( tag, BER_TIME_UTC ) )
			{
			sSetError( stream, CRYPT_ERROR_BADDATA );
			return( CRYPT_ERROR_BADDATA );
			}
		}

	/* Read the time fields */
	return( readTime( stream, timeVal, TRUE ) );
	}

int readGeneralizedTimeTag( STREAM *stream, time_t *timeVal, const int tag )
	{
	/* Clear return value */
	if( timeVal != NULL )
		*timeVal = 0;
	
	/* Read the identifier field if necessary */
	if( tag != NO_TAG )
		{
		if( readTag( stream ) != selectTag( tag, BER_TIME_GENERALIZED ) )
			{
			sSetError( stream, CRYPT_ERROR_BADDATA );
			return( CRYPT_ERROR_BADDATA );
			}
		}

	/* Read the time fields */
	return( readTime( stream, timeVal, FALSE ) );
	}

/****************************************************************************
*																			*
*					Utility Routines for Constructed Objects				*
*																			*
****************************************************************************/

/* Read the start of an encapsulating SEQUENCE or SET or BIT STRING/OCTET 
   STRING hole */

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

	if( length != NULL )
		*length = 0;	/* Clear return value */
	tagValue = readTag( stream );
	if( cryptStatusError( tagValue ) )
		return( tagValue );
	if( tag != ANY_TAG && tagValue != tag )
		{
		sSetError( stream, CRYPT_ERROR_BADDATA );
		return( sGetStatus( stream ) );
		}
	dataLength = readShortLength( stream );
	if( cryptStatusError( dataLength ) )
		return( dataLength );
	if( length != NULL )
		*length = dataLength - ( isBitString ? 1 : 0 );
	if( isBitString )
		sgetc( stream );

	return( sGetStatus( stream ) );
	}

int readSequence( STREAM *stream, int *length )
	{
	return( readObjectHeader( stream, length, BER_SEQUENCE, FALSE ) );
	}

int readSet( STREAM *stream, int *length )
	{
	return( readObjectHeader( stream, length, BER_SET, FALSE ) );
	}

int readConstructed( STREAM *stream, int *length, const int tag )
	{
	return( readObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
							  BER_SEQUENCE : MAKE_CTAG( tag ), FALSE ) );
	}

int readOctetStringHole( STREAM *stream, int *length, const int tag )
	{
	return( readObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
							  BER_OCTETSTRING : MAKE_CTAG_PRIMITIVE( tag ),
							  FALSE ) );
	}

int readBitStringHole( STREAM *stream, int *length, const int tag )
	{
	return( readObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
							  BER_BITSTRING : MAKE_CTAG_PRIMITIVE( tag ),
							  TRUE ) );
	}

int readGenericHole( STREAM *stream, int *length )
	{
	return( readObjectHeader( stream, length, ANY_TAG, FALSE ) );
	}

/* Write the start of an encapsulating SEQUENCE, SET, or generic tagged
   constructed object.  The default type for the generic object is assumed
   to be a SEQUENCE */

int writeSequence( STREAM *stream, const int length )
	{
	writeTag( stream, BER_SEQUENCE );
	writeLength( stream, length );
	return( sGetStatus( stream ) );
	}

int writeSet( STREAM *stream, const int length )
	{
	writeTag( stream, BER_SET );
	writeLength( stream, length );
	return( sGetStatus( stream ) );
	}

int writeConstructed( STREAM *stream, const int length, const int tag )
	{
	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_SEQUENCE : MAKE_CTAG( tag ) );
	writeLength( stream, length );
	return( sGetStatus( stream ) );
	}

/****************************************************************************
*																			*
*						ASN.1 Encoding/Length Checks						*
*																			*
****************************************************************************/

/* The maximum nesting level for constructed or encapsulated objects (this
   can get surprisingly high for some of the more complex attributes).  This
   value is chosen to pass all normal certs while avoiding stack overflows
   for artificial bad data */

#define MAX_NESTING_LEVEL	50

/* When we parse a nested data object encapsulated within a larger object,
   the length is initially set to a magic value which is adjusted to the
   actual length once we start parsing the object */

#define LENGTH_MAGIC		177545L

/* Current parse state.  This is used to check for potential BIT STRING and
   OCTET STRING targets for OCTET/BIT STRING holes, which are always
   preceded by an AlgorithmIdentifier.  In order to detect these without
   having to know every imaginable AlgorithmIdentifier OID, we check for the
   following sequence of events:

	checkASN1Object								-- SEQUENCE
		checkASN1
			checkASN1Object
				checkPrimitive					-- OID
			checkASN1Object
				checkPrimitive					-- opt.BOOLEAN	  OCTET STRING
				checkPrimitive					-- NULL, or		|
				checkASN1Object					-- SEQUENCE		| BIT STRING
	checkASN1Object
		checkPrimitive							-- OCTET/BIT STRING

   This type of checking is rather awkward in the (otherwise stateless) code,
   but is the only way to be sure that it's safe to try burrowing into an
   OCTET STRING or BIT STRING to try to find encapsulated data, since
   otherwise even with relatively strict checking there's still a very small
   chance that random data will look like a nested object */

typedef enum {
	/* Generic non-state */
	STATE_NONE,

	/* States corresponding to ASN.1 primitives */
	STATE_BOOLEAN, STATE_NULL, STATE_OID, STATE_SEQUENCE,

	/* States corresponding to different parts of a SEQUENCE { OID, optional,
	   OCTET/BIT STRING } sequence */
	STATE_HOLE_OID, STATE_HOLE_BITSTRING, STATE_HOLE_OCTETSTRING,

	/* Error state */
	STATE_ERROR
	} ASN1_STATE;

/* Structure to hold info on an ASN.1 item */

typedef struct {
	int tag;			/* Tag */
	long length;		/* Data length */
	BOOLEAN indefinite;	/* Item has indefinite length */
	int headerSize;		/* Size of tag+length */
	} ASN1_ITEM;

/* Get an ASN.1 object's tag and length */

static int getItem( STREAM *stream, ASN1_ITEM *item )
	{
	int length;

	memset( item, 0, sizeof( ASN1_ITEM ) );
	item->headerSize = 2;
	item->tag = sgetc( stream );
	length = sgetc( stream );
	if( cryptStatusError( length ) )
		return( STATE_NONE );
	if( length & 0x80 )
		{
		int i;

		length &= 0x7F;
		if( length > 4 )
			/* Object has a bad length field, usually because we've lost sync
			   in the decoder or run into garbage */
			return( STATE_NONE );
		item->headerSize += length;
		item->length = 0;
		if( !length )
			item->indefinite = TRUE;
		for( i = 0; i < length; i++ )
			item->length = ( item->length << 8 ) | sgetc( stream );
		}
	else
		item->length = length;

	return( sStatusOK( stream ) ? STATE_NONE : STATE_ERROR );
	}

/* Check whether an ASN.1 object is encapsulated inside an OCTET STRING or
   BIT STRING.  After performing the various checks we have to explicitly
   clear the stream error state since the probing for valid data could have
   set the error indicator if nothing valid was found */

static BOOLEAN checkEncapsulation( STREAM *stream, const int length,
								   const BOOLEAN isBitstring,
								   const ASN1_STATE state )
	{
	BOOLEAN isEncapsulated = TRUE;
	long streamPos = stell( stream );
	int tag = readTag( stream ), innerLength;

	/* Perform a quick check to see whether an OCTET STRING or BIT STRING hole
	   is allowed at this point.  A BIT STRING must be preceded by { SEQ, OID,
	   NULL }.  An OCTET STRING must be preceded by { SEQ, OID, {BOOLEAN} } */

⌨️ 快捷键说明

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