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

📄 asn1_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
					 const BOOLEAN isUTCTime )
	{
	BYTE buffer[ 16 + 8 ], *bufPtr = buffer;
	struct tm theTime,  gmTimeInfo, *gmTimeInfoPtr = &gmTimeInfo;
	time_t utcTime, gmTime;
	int value = 0, length, i, iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( timePtr, sizeof( time_t ) ) );

	/* Clear return value */
	*timePtr = 0;

	/* 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.  We formerly also allowed 11-byte 
	   UTCTimes because an obsolete encoding rule allowed the time to be 
	   encoded without seconds and Sweden Post hadn't realised that this had 
	   changed yet, but these certs have now expired */
	length = sgetc( stream );
	if( cryptStatusError( length ) )
		return( length );
	if( ( isUTCTime && length != 13 ) || ( !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, 16 );
	status = sread( stream, buffer, length );
	if( cryptStatusError( status ) )
		return( status );
	for( i = 0, iterationCount = 0; 
		 i < length - 1 && iterationCount < FAILSAFE_ITERATIONS_MED; 
		 i++, iterationCount++ )
		{
		if( !isDigit( buffer[ i ] ) )
			return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
		}
	ENSURES_S( iterationCount < FAILSAFE_ITERATIONS_MED );
	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 )
		{
		status = strGetNumeric( bufPtr, 2, &value, 19, 20 );
		if( cryptStatusError( status ) )
			return( status );
		value = ( value - 19 ) * 100;	/* Read the century */
		bufPtr += 2;
		length -= 2;
		}
	status = strGetNumeric( bufPtr, 2, &theTime.tm_year, 0, 99 );
	if( cryptStatusOK( status ) )
		{
		theTime.tm_year += value;
		status = strGetNumeric( bufPtr + 2, 2, &theTime.tm_mon, 1, 12 );
		}
	if( cryptStatusOK( status ) )
		{
		theTime.tm_mon--;				/* Months are zero-based */
		status = strGetNumeric( bufPtr + 4, 2, &theTime.tm_mday, 1, 31 );
		}
	if( cryptStatusOK( status ) )
		status = strGetNumeric( bufPtr + 6, 2, &theTime.tm_hour, 0, 23 );
	if( cryptStatusOK( status ) )
		status = strGetNumeric( bufPtr + 8, 2, &theTime.tm_min, 0, 59 );
	if( cryptStatusOK( status ) )
		status = strGetNumeric( bufPtr + 10, 2, &theTime.tm_sec, 0, 59 );
	if( cryptStatusError( 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 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.

	   In theory we could also check for an at least vaguely sane input 
	   value range on the grounds that (a) some systems' mktime()s may be 
	   broken and (b) some mktime()s may allow (and return) outrageous date 
	   values that others don't.  However it's probably better to simply be 
	   consistent with what the system does rather than try and second-guess
	   the intent of the mktime() authors.

		"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 < MIN_STORED_TIME_VALUE )
		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_s() 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 
	   other systems */
	gmTimeInfoPtr = gmTime_s( &utcTime, gmTimeInfoPtr );
	if( gmTimeInfoPtr == NULL )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	gmTimeInfoPtr->tm_isdst = -1;		/* Force correct DST adjustment */
	gmTime = mktime( gmTimeInfoPtr );
	if( gmTime < MIN_STORED_TIME_VALUE )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	if( utcTime < gmTime )
		*timePtr = utcTime - ( gmTime - utcTime );
	else
		*timePtr = utcTime + ( utcTime - gmTime );

	/* This still isn't quite perfect since it can't handle the 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
	gmTimeInfoPtr = gmTime_s( timePtr );
	gmTimeInfoPtr->tm_isdst = -1;
	gmTime = mktime( gmTimeInfoPtr );
	if( gmTime != utcTime )
		{
		*timePtr += 3600;		/* Try +1 first */
		gmTimeInfoPtr = gmTime_s( timePtr, gmTimeInfoPtr );
		gmTimeInfoPtr->tm_isdst = -1;
		gmTime = mktime( gmTimeInfoPtr );
		if( gmTime != utcTime )
			*timePtr -= 7200;	/* Nope, use -1 instead */
		}
#endif /* 0 */

	return( CRYPT_OK );
	}

RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readUTCTimeTag( STREAM *stream, OUT time_t *timeVal, 
					IN_TAG_EXT const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( timeVal, sizeof( time_t ) ) );

	REQUIRES_S( tag == NO_TAG || tag == DEFAULT_TAG || \
				( tag >= 0 && tag < MAX_TAG_VALUE ) );

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

RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readGeneralizedTimeTag( INOUT STREAM *stream, OUT time_t *timeVal, 
							IN_TAG_EXT const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( timeVal, sizeof( time_t ) ) );

	REQUIRES_S( tag == NO_TAG || tag == DEFAULT_TAG || \
				( tag >= 0 && tag < MAX_TAG_VALUE ) );

	/* Clear return value */
	*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 */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readSequence( INOUT STREAM *stream, OUT_OPT_LENGTH_Z int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readSequenceI( INOUT STREAM *stream, OUT_OPT_LENGTH_INDEF int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readSet( INOUT STREAM *stream, OUT_OPT_LENGTH_Z int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readSetI( INOUT STREAM *stream, OUT_OPT_LENGTH_INDEF int *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readConstructed( INOUT STREAM *stream, OUT_OPT_LENGTH_Z int *length, 
					 IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	REQUIRES_S( ( tag == DEFAULT_TAG ) || ( tag >= 0 && tag < MAX_TAG_VALUE ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readConstructedI( INOUT STREAM *stream, OUT_OPT_LENGTH_INDEF int *length, 
					  IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	REQUIRES_S( ( tag == DEFAULT_TAG ) || ( tag >= 0 && tag < MAX_TAG_VALUE ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readOctetStringHole( INOUT STREAM *stream, OUT_OPT_LENGTH_Z int *length, 
						 IN_LENGTH_SHORT const int minLength, 
						 IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	REQUIRES_S( ( tag == DEFAULT_TAG ) || ( tag >= 0 && tag < MAX_TAG_VALUE ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readBitStringHole( INOUT STREAM *stream, OUT_OPT_LENGTH_Z int *length, 
					   IN_LENGTH_SHORT const int minLength, 
					   IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	REQUIRES_S( ( tag == DEFAULT_TAG ) || ( tag >= 0 && tag < MAX_TAG_VALUE ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readGenericHole( INOUT STREAM *stream, OUT_OPT_LENGTH_Z int *length, 
					 IN_LENGTH_SHORT const int minLength, 
					 IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	ENSURES_S( ( tag == DEFAULT_TAG ) || ( tag > 0 && tag < MAX_TAG ) );
			   /* In theory we should use MAX_TAG_VALUE but this function is 
			      frequently used as part of the sequence 'read tag; 
				  save tag; readGenericXYZ( tag );' so we have to allow all
				  tag values */

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readGenericHoleI( INOUT STREAM *stream, 
					  OUT_OPT_LENGTH_INDEF int *length, 
					  IN_LENGTH_SHORT const int minLength, 
					  IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( int ) ) );

	ENSURES_S( ( tag == DEFAULT_TAG ) || ( tag > 0 && tag < MAX_TAG ) );
			   /* See comment for readGenericHole() */

	return( readObjectHeader( stream, length, minLength, 
							  ( 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 situations 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 */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readLongSequence( INOUT STREAM *stream, 
					  OUT_OPT_LENGTH_INDEF long *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readLongSet( INOUT STREAM *stream, OUT_OPT_LENGTH_INDEF long *length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readLongConstructed( INOUT STREAM *stream, 
						 OUT_OPT_LENGTH_INDEF long *length, 
						 IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

	REQUIRES_S( ( tag == DEFAULT_TAG ) || ( tag >= 0 && tag < MAX_TAG_VALUE ) );

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

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readLongGenericHole( INOUT STREAM *stream, 
						 OUT_OPT_LENGTH_INDEF long *length, 
						 IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

	ENSURES_S( ( tag == DEFAULT_TAG ) || ( tag > 0 && tag < MAX_TAG ) );
			   /* See comment for readGenericHole() */

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

⌨️ 快捷键说明

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