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

📄 asn1_rd.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* 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 the 
	   more obscure CMP error subcodes that just provide further information
	   above and beyond the main error code and text message, which are 
	   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;
	noBits = sgetc( stream );
	if( length < 0 || length > sizeof( int ) || noBits < 0 || noBits > 7 )
		return( sSetError( stream, 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 before we return the value */
	data = sgetc( stream );
	for( i = noBits - 8; i > 0; i -= 8 )
		{
		data = ( data << 8 ) | sgetc( stream );
		mask <<= 8;
		}
	if( !sStatusOK( stream ) )
		return( sGetStatus( stream ) );
	for( i = 0; i < noBits; i++ )
		{
		if( data & mask )
			value |= flag;
		flag <<= 1;
		data <<= 1;
		}
	if( bitString != NULL )
		*bitString = value;

	return( CRYPT_OK );
	}

/* Read a UTCTime and GeneralizedTime value */

static int getDigits( const BYTE *bufPtr )
	{
	return( ( ( bufPtr[ 0 ] - '0' ) * 10 ) + ( bufPtr[ 1 ] - '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;
#if 0
	time_t localTime;
#endif /* 0 */
	int value = 0, length, i, status;

	/* Read the length field and make sure that 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 UTCTimes 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 ) )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	/* Read the encoded time data and make sure that the contents are 
	   valid */
	memset( buffer, 0, 32 );
	status = sread( stream, buffer, length );
	if( cryptStatusError( status ) )
		return( status );
	for( i = 0; i < length - 1; i++ )
		if( buffer[ i ] < '0' || buffer[ i ] > '9' )
			return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	if( buffer[ length - 1 ] != 'Z' )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	/* Decode the time fields */
	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 );
	if( length > 11 )
		theTime.tm_sec = getDigits( bufPtr + 10 );

	/* 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 if the format is 
	   UTCTime.  Note that there are some implementations that 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 < 0 )
		{
		/* Some Java-based apps with 64-bit times use ridiculous validity
		   dates (yes, we're going to be keeping the same key in active use
		   for *forty years*) that postdate the time_t range when time_t is 
		   a signed 32-bit value.  If we can't convert the time, we check 
		   for a year after the time_t overflow (2038) and try again.  In
		   theory we should just reject objects with such broken dates, but
		   since we otherwise accept all sorts of rubbish we at least try 
		   and accept these as well */
		if( theTime.tm_year > 138 && theTime.tm_year < 180 )
			{
			theTime.tm_year = 136;	/* 2036 */
			utcTime = mktime( &theTime );
			}

		/* Some broken apps set dates to 1/1/1970, handling times this close 
		   to the epoch is problematic because once any possible DST 
		   adjustment is taken into account it's no longer possible to
		   represent the converted time as a time_t unless the system allows
		   it to be negative (Windows doesn't, many Unixen do, but having
		   cryptlib return a negative time value is probably a bad thing).  
		   To handle this, if we find a date set anywhere during January 1970 
		   we manually set the time to zero (the epoch) */
		if( theTime.tm_year == 70 && theTime.tm_mon == 0 )
			{
			*timePtr = 0;
			return( CRYPT_OK );
			}
		}
	if( utcTime < 0 )
		return( sSetError( stream, 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 treat the UTC time as 
	   local time (gmtime() always assumes that the input is local time) and 
	   covert to GMT and back, which should give the offset from GMT.  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 */
	gm_tm = gmtime( &utcTime );
	if( gm_tm != NULL )
		{
		gm_tm->tm_isdst = -1;		/* Force correct DST adjustment */
		gmTime = mktime( gm_tm );
		}
	if( gm_tm == NULL || gmTime < 0 )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	if( timePtr != NULL )
		{
		if( utcTime < gmTime )
			*timePtr = utcTime - ( gmTime - utcTime );
		else
			*timePtr = utcTime + ( utcTime - gmTime );

		/* This still isn't quite perfect, since it can't handle time at
		   a DST changeover.  This is really a user problem ("Don't do that,
		   then"), but if necessary can be corrected by converting back to
		   GMT as a sanity check and applying a +/- 1 hour correction if 
		   there's a mismatch */
  #if 0
		gm_tm = gmtime( timePtr );
		gm_tm->tm_isdst = -1;
		gmTime = mktime( gm_tm );
		if( gmTime != utcTime )
			{
			*timePtr = ( *timePtr ) + 3600;	/* Try +1 first */
			gm_tm = gmtime( timePtr );
			gm_tm->tm_isdst = -1;
			gmTime = mktime( gm_tm );
			if( gmTime != utcTime )
				/* Nope, use -1 instead */
				*timePtr = ( *timePtr ) -7200;
			}
  #endif /* 0 */
		}

	return( CRYPT_OK );
	}

int readUTCTimeTag( STREAM *stream, time_t *timeVal, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( timeVal == NULL || isWritePtr( timeVal, sizeof( time_t ) ) );

	/* Clear return value */
	if( timeVal != NULL )
		*timeVal = 0;
	
	if( tag != NO_TAG && readTag( stream ) != selectTag( tag, BER_TIME_UTC ) )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	return( readTime( stream, timeVal, TRUE ) );
	}

int readGeneralizedTimeTag( STREAM *stream, time_t *timeVal, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( timeVal == NULL || isWritePtr( timeVal, sizeof( time_t ) ) );

	/* Clear return value */
	if( timeVal != NULL )
		*timeVal = 0;
	
	if( tag != NO_TAG && readTag( stream ) != selectTag( tag, BER_TIME_GENERALIZED ) )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	return( readTime( stream, timeVal, FALSE ) );
	}

/****************************************************************************
*																			*
*						Read Routines for Constructed Objects				*
*																			*
****************************************************************************/

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

int readSequence( STREAM *stream, int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, BER_SEQUENCE, FALSE, FALSE ) );
	}

int readSequenceI( STREAM *stream, int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, BER_SEQUENCE, FALSE, TRUE ) );
	}

int readSet( STREAM *stream, int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, BER_SET, FALSE, FALSE ) );
	}

int readSetI( STREAM *stream, int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, BER_SET, FALSE, TRUE ) );
	}

int readConstructed( STREAM *stream, int *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
							  BER_SEQUENCE : MAKE_CTAG( tag ), FALSE, FALSE ) );
	}

int readConstructedI( STREAM *stream, int *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
							  BER_SEQUENCE : MAKE_CTAG( tag ), FALSE, TRUE ) );
	}

int readOctetStringHole( STREAM *stream, int *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
							  BER_OCTETSTRING : MAKE_CTAG_PRIMITIVE( tag ),
							  FALSE, FALSE ) );
	}

int readBitStringHole( STREAM *stream, int *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
							  BER_BITSTRING : MAKE_CTAG_PRIMITIVE( tag ),
							  TRUE, FALSE ) );
	}

int readGenericHole( STREAM *stream, int *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, 
							  ( tag == DEFAULT_TAG ) ? ANY_TAG : tag, 
							  FALSE, FALSE ) );
	}

int readGenericHoleI( STREAM *stream, int *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	return( readObjectHeader( stream, length, 
							  ( tag == DEFAULT_TAG ) ? ANY_TAG : tag, 
							  FALSE, TRUE ) );
	}

/* Read an abnormally-long encapsulating SEQUENCE or OCTET STRING hole.  
   This is used in place of the usual read in places where potentially huge 
   data quantities would fail the sanity check enforced by the standard 
   read.  This form always allows indefinite lengths, which are likely for 
   large objects */

int readLongSequence( STREAM *stream, long *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

	return( readLongObjectHeader( stream, length, BER_SEQUENCE ) );
	}

int readLongConstructed( STREAM *stream, long *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

	return( readLongObjectHeader( stream, length, ( tag == DEFAULT_TAG ) ? \
								  BER_SEQUENCE : MAKE_CTAG( tag ) ) );
	}

int readLongGenericHole( STREAM *stream, long *length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

	return( readLongObjectHeader( stream, length, 							  
								  ( tag == DEFAULT_TAG ) ? ANY_TAG : tag ) );
	}

⌨️ 快捷键说明

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