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

📄 asn1_rw.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						   ASN.1 Read/Write Routines						*
*						Copyright Peter Gutmann 1992-2003					*
*																			*
****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "bn.h"
  #include "asn1_rw.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../bn/bn.h"
  #include "asn1_rw.h"
#else
  #include "crypt.h"
  #include "bn/bn.h"
  #include "misc/asn1_rw.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 ) ) )

/* Calculate the size of the encoded length octets */

static int calculateLengthSize( const long length )
	{
	if( length < 128 )
		/* Use short form of length octets */
		return( 1 );
	else
		/* Use long form of length octets: length-of-length followed by
		   32, 24, 16, or 8-bit length */
		return( 1 + ( ( length > 0xFFFFFFL ) ? 4 : \
					  ( length > 0xFFFF ) ? 3 : ( length > 0xFF ) ? 2 : 1 ) );
	}

/* Determine the encoded size of an object given only a length.  This is
   implemented as a function rather than a macro since the macro form would
   evaluate the length argument a great many times.

   The function checks for a length < 0 since this is frequently called with
   the output of another function that may return an error code */

long sizeofObject( const long length )
	{
	return( ( length < 0 ) ? length : \
			sizeof( BYTE ) + calculateLengthSize( length ) + length );
	}

/* Determine the size of a bignum.  When we're writing these we can't use 
   sizeofObject() directly because the internal representation is unsigned 
   whereas the encoded form is signed */

int signedBignumSize( const void *bignum )
	{
	assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );

	return( BN_num_bytes( bignum ) + BN_high_bit( ( BIGNUM * ) bignum ) );
	}

/****************************************************************************
*																			*
*							ASN.1 Output Routines							*
*																			*
****************************************************************************/

/* Write the length octets for an ASN.1 data type */

int writeLength( STREAM *stream, const long length )
	{
	BYTE buffer[ 8 ];
	const int noLengthOctets = ( length > 0xFFFFFFL ) ? 4 : \
							   ( length > 0xFFFFL ) ? 3 : \
							   ( length > 0xFF ) ? 2 : 1;
	int bufPos = 1;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( length >= 0 );

	/* Check if we can use the short form of length octets */
	if( length < 128 )
		return( sputc( stream, ( BYTE ) length ) );

	/* Encode the number of length octets followed by the octets themselves */
	buffer[ 0 ] = 0x80 | noLengthOctets;
	if( noLengthOctets > 3 )
		buffer[ bufPos++ ] = ( BYTE ) ( length >> 24 );
	if( noLengthOctets > 2 )
		buffer[ bufPos++ ] = ( BYTE ) ( length >> 16 );
	if( noLengthOctets > 1 )
		buffer[ bufPos++ ] = ( BYTE ) ( length >> 8 );
	buffer[ bufPos++ ] = ( BYTE ) length;
	return( swrite( stream, buffer, bufPos ) );
	}

/* Write a (non-bignum) numeric value, used by several routines */

static int writeNumeric( STREAM *stream, const long integer )
	{
	BOOLEAN needsLZ = TRUE;
	BYTE buffer[ 8 ];
	int length = 1;

	/* Determine the number of bytes necessary to encode the integer and
	   encode it into a temporary buffer */
	if( integer < 0 )
		buffer[ length++ ] = 0;
	if( integer > 0x00FFFFFFL )
		{
		buffer[ length++ ] = ( BYTE ) ( integer >> 24 );
		needsLZ = FALSE;
		}
	if( integer >= 0x00800000L && needsLZ )
		buffer[ length++ ] = 0;
	if( integer > 0x0000FFFFL )
		{
		buffer[ length++ ] = ( BYTE ) ( integer >> 16 );
		needsLZ = FALSE;
		}
	if( integer >= 0x00008000L && needsLZ )
		buffer[ length++ ] = 0;
	if( integer > 0x000000FFL )
		{
		buffer[ length++ ] = ( BYTE ) ( integer >> 8 );
		needsLZ = FALSE;
		}
	if( integer >= 0x00000080L && needsLZ )
		buffer[ length++ ] = 0;
	buffer[ length++ ] = ( BYTE ) integer;

	/* Write the length and numeric data */
	buffer[ 0 ] = length - 1;
	return( swrite( stream, buffer, length ) );
	}

/* Write a short integer value */

int writeShortInteger( STREAM *stream, const long integer, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( integer >= 0 );

	/* Write the identifier and numeric fields */
	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_INTEGER : BER_CONTEXT_SPECIFIC | tag );
	return( writeNumeric( stream, integer ) );
	}

/* Write a large integer value */

int writeInteger( STREAM *stream, const BYTE *integer,
				  const int integerLength, const int tag )
	{
	const BOOLEAN leadingZero = integerLength && ( *integer & 0x80 ) ? 1 : 0;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( integer, integerLength ) );
	assert( integerLength >= 0 );

	/* Write the identifier field */
	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_INTEGER : BER_CONTEXT_SPECIFIC | tag );

	/* Write it as a big-endian bignum value.  We have to be careful about 
	   how we handle values with the high bit set since the internal format 
	   is unsigned while ASN.1 values are signed */
	if( !integerLength )
		return( swrite( stream, "\x01\x00", 2 ) );
	writeLength( stream, integerLength + leadingZero );
	if( leadingZero )
		sputc( stream, 0 );
	return( swrite( stream, integer, integerLength ) );
	}

/* Write an bignum integer value */

int writeBignumTag( STREAM *stream, const void *bignum, const int tag )
	{
	BYTE buffer[ CRYPT_MAX_PKCSIZE ];
	int length, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );

	/* If it's a dummy write, don't go through the full encoding process.
	   This optimisation both speeds things up and reduces unnecessary
	   writing of key data to memory */
	if( sIsNullStream( stream ) )
		{
		swrite( stream, buffer, sizeofBignum( bignum ) );
		return( CRYPT_OK );
		}

	length = BN_bn2bin( ( BIGNUM * ) bignum, buffer );
	status = writeInteger( stream, buffer, length, tag );
	zeroise( buffer, CRYPT_MAX_PKCSIZE );

	return( status );
	}

/* Write an enumerated value */

int writeEnumerated( STREAM *stream, const int enumerated, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( enumerated >= 0 );

	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_ENUMERATED : BER_CONTEXT_SPECIFIC | tag );
	return( writeNumeric( stream, ( long ) enumerated ) );
	}

/* Write a null value */

int writeNull( STREAM *stream, const int tag )
	{
	BYTE buffer[ 8 ];

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

	buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? \
				  BER_NULL : BER_CONTEXT_SPECIFIC | tag;
	buffer[ 1 ] = 0;
	return( swrite( stream, buffer, 2 ) );
	}

/* Write a boolean value */

int writeBoolean( STREAM *stream, const BOOLEAN boolean, const int tag )
	{
	BYTE buffer[ 8 ];

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

	buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? \
				  BER_BOOLEAN : BER_CONTEXT_SPECIFIC | tag;
	buffer[ 1 ] = 1;
	buffer[ 2 ] = boolean ? 0xFF : 0;
	return( swrite( stream, buffer, 3 ) );
	}

/* Write an octet string */

int writeOctetString( STREAM *stream, const BYTE *string, const int length,
					  const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( string, length ) );

	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_OCTETSTRING : BER_CONTEXT_SPECIFIC | tag );
	writeLength( stream, length );
	return( swrite( stream, string, length ) );
	}

/* Write 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
   DEFAULT_TAG like the other functions use) */

int writeCharacterString( STREAM *stream, const BYTE *string,
						  const int length, const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( string, length ) );
	assert( tag != DEFAULT_TAG );

	writeTag( stream, tag );
	writeLength( stream, length );
	return( swrite( stream, string, length ) );
	}

/* Write a bit string */

int writeBitString( STREAM *stream, const int bitString, const int tag )
	{
	BYTE buffer[ 16 ];
	unsigned int value = 0;
	int data = bitString, noBits = 0, i;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( bitString >= 0 );

	/* ASN.1 bitstrings start at bit 0, so we need to reverse the order of
	  the bits before we write them out */
	for( i = 0; i < ( sizeof( int ) > 2 ? 32 : 16 ); i++ )
		{
		/* Update the number of significant bits */
		if( data )
			noBits++;

		/* Reverse the bits */
		value <<= 1;
		if( data & 1 )
			value |= 1;
		data >>= 1;
		}

	/* Write the data as an ASN.1 BITSTRING.  This has the potential to lose
	   some bits on 16-bit systems, but this only applies to the more obscure
	   CMP error codes and it's unlikely too many people will be running a
	   CMP server on a DOS box */
	buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? BER_BITSTRING : \
				  BER_CONTEXT_SPECIFIC | tag;
	buffer[ 1 ] = 1 + ( ( noBits + 7 ) >> 3 );
	buffer[ 2 ] = ~( ( noBits - 1 ) & 7 ) & 7;
#if UINT_MAX > 0xFFFF
	buffer[ 3 ] = value >> 24;
	buffer[ 4 ] = value >> 16;
	buffer[ 5 ] = value >> 8;
	buffer[ 6 ] = value;
#else
	buffer[ 3 ] = value >> 8;
	buffer[ 4 ] = value;
#endif /* 16 vs.32-bit systems */
	return( swrite( stream, buffer, 3 + ( ( noBits + 7 ) >> 3 ) ) );
	}

/* Write a canonical UTCTime and GeneralizedTime value */

int writeUTCTime( STREAM *stream, const time_t timeVal, const int tag )
	{
	struct tm *timeInfo = gmtime( &timeVal );
	char buffer[ 20 ];

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( timeVal > 0 );

	/* Sanity check on input data */
	if( timeInfo == NULL || timeInfo->tm_year <= 90 )
		{
		assert( NOTREACHED );
		sSetError( stream, CRYPT_ERROR_BADDATA );
		return( CRYPT_ERROR_BADDATA );
		}

	/* Print the main time fields */
	sPrintf( buffer + 2, "%02d%02d%02d%02d%02d%02dZ", 
			 timeInfo->tm_year % 100, timeInfo->tm_mon + 1, 
			 timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min, 
			 timeInfo->tm_sec );

	/* Write the time string */
	buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? \
				  BER_TIME_UTC : BER_CONTEXT_SPECIFIC | tag;
	buffer[ 1 ] = 13;
	return( swrite( stream, buffer, 15 ) );
	}

int writeGeneralizedTime( STREAM *stream, const time_t timeVal, const int tag )
	{
	struct tm *timeInfo = gmtime( &timeVal );
	char buffer[ 20 ];

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( timeVal > 0 );

	/* Sanity check on input data */
	if( timeInfo == NULL || timeInfo->tm_year <= 90 )
		{
		assert( NOTREACHED );
		sSetError( stream, CRYPT_ERROR_BADDATA );
		return( CRYPT_ERROR_BADDATA );
		}

	/* Print the main time fields */
	sPrintf( buffer + 2, "%04d%02d%02d%02d%02d%02dZ", 
			 timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, 
			 timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min, 
			 timeInfo->tm_sec );

	/* Write the time string */
	buffer[ 0 ] = ( tag == DEFAULT_TAG ) ? \
				  BER_TIME_GENERALIZED : BER_CONTEXT_SPECIFIC | tag;
	buffer[ 1 ] = 15;
	return( swrite( stream, buffer, 17 ) );
	}

/****************************************************************************
*																			*
*							ASN.1 Input Routines							*
*																			*
****************************************************************************/

/* Check for constructed end-of-item 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 ) )
		{
		/* After finding an EOC tag we need to have a length of zero */
		sSetError( stream, CRYPT_ERROR_BADDATA );
		return( CRYPT_ERROR_BADDATA );

⌨️ 快捷键说明

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