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

📄 asn1_wr.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*								ASN.1 Write Routines						*
*						Copyright Peter Gutmann 1992-2008					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "bn.h"
  #include "asn1.h"
#else
  #include "crypt.h"
  #include "bn/bn.h"
  #include "misc/asn1.h"
#endif /* Compiler-specific includes */

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

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

CHECK_RETVAL_RANGE( MAX_ERROR, 5 ) \
static int calculateLengthSize( IN_LENGTH_Z const long length )
	{
	REQUIRES( length >= 0 && length < MAX_INTLENGTH );

	/* Use the short form of the length octets if possible */
	if( length <= 0x7F )
		return( 1 );

	/* Use the long form of the length octets, a length-of-length followed 
	   by an 8, 16, 24, or 32-bit length.  We order the comparisons by 
	   likelihood of occurrence, shorter lengths are far more common than 
	   longer ones */
	if( length <= 0xFF )
		return( 1 + 1 );
	if( length <= 0xFFFFL )
		return( 1 + 2 );
	return( 1 + ( ( length > 0xFFFFFFL ) ? 4 : 3 ) );
	}

/* Write the length octets for an ASN.1 item */

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

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

	REQUIRES_S( length >= 0 && length < MAX_INTLENGTH );

	/* Use the short form of the length octets if possible */
	if( length <= 0x7F )
		return( sputc( stream, length & 0xFF ) );

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

/* Write a (non-bignum) numeric value, used by several routines.  The 
   easiest way to do this is to encode the bytes starting from the LSB
   and then output them in reverse order to get a big-endian encoding */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeNumeric( INOUT STREAM *stream, IN_INT const long integer )
	{
	BYTE buffer[ 16 + 8 ];
	long intValue = integer;
	int length = 0, i, iterationCount;

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

	REQUIRES_S( integer >= 0 && integer < MAX_INTLENGTH );

	/* The value 0 is handled specially */
	if( intValue == 0 )
		return( swrite( stream, "\x01\x00", 2 ) );

	/* Assemble the encoded value in little-endian order */
	if( intValue > 0 )
		{
		for( iterationCount = 0;
			 intValue > 0 && iterationCount < FAILSAFE_ITERATIONS_SMALL;
			 iterationCount++ )
			{
			buffer[ length++ ] = intValue & 0xFF;
			intValue >>= 8;
			}
		ENSURES( iterationCount < FAILSAFE_ITERATIONS_SMALL );

		/* Make sure that we don't inadvertently set the sign bit if the 
		   high bit of the value is set */
		if( buffer[ length - 1 ] & 0x80 )
			buffer[ length++ ] = 0x00;
		}
	else
		{
		/* Write a negative integer values.  This code is never executed 
		   (and is actually checked for by the precondition at the start of
		   theis function), it's present only in case it's ever needed in 
		   the future */
		iterationCount = 0;
		do
			{
			buffer[ length++ ] = intValue & 0xFF;
			intValue >>= 8;
			}
		while( intValue != -1 && length < sizeof( int ) && \
			   iterationCount++ < FAILSAFE_ITERATIONS_SMALL );
		ENSURES( iterationCount < FAILSAFE_ITERATIONS_SMALL );

		/* Make sure that we don't inadvertently clear the sign bit if the 
		   high bit of the value is clear */
		if( !( buffer[ length - 1 ] & 0x80 ) )
			buffer[ length++ ] = 0xFF;
		}
	ENSURES( length > 0 && length <= 8 );

	/* Output the value in reverse (big-endian) order */
	sputc( stream, length );
	for( i = length - 1; i > 0; i-- )
		sputc( stream, buffer[ i ] );
	return( sputc( stream, buffer[ 0 ] ) );
	}

/****************************************************************************
*																			*
*								Sizeof Routines								*
*																			*
****************************************************************************/

/* 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 as
   part of a complex expression using the output of another function that 
   may return an error code.  Because of this we don't use a REQUIRES()
   predicate on it as we usually would but merely throw an exception in
   debug mode */

RETVAL_RANGE( MAX_ERROR, MAX_INTLENGTH ) \
long sizeofObject( IN_LENGTH const long length )
	{
	REQUIRES( length < MAX_INTLENGTH );

	/* If we've been passed an error code as input, pass it back 
	   unmodified */
	if( length < 0 ) 
		{
		assert( DEBUG_WARN );
		return( length );
		}

	/* If we're about to exceed the maximum safe length range, don't try and 
	   go any further */
	if( length > MAX_INTLENGTH - 10 )
		{
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_OVERFLOW );
		}

	return( sizeof( BYTE ) + calculateLengthSize( length ) + length );
	}

#ifdef USE_PKC

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

RETVAL_RANGE( MAX_ERROR, MAX_INTLENGTH_SHORT ) STDC_NONNULL_ARG( ( 1 ) ) \
int signedBignumSize( IN TYPECAST( BIGNUM * ) const void *bignum )
	{
	assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );

	return( BN_num_bytes( bignum ) + \
			( ( BN_high_bit( ( BIGNUM * ) bignum ) ) ? 1 : 0 ) );
	}
#endif /* USE_PKC */

/****************************************************************************
*																			*
*					Write Routines for Primitive Objects					*
*																			*
****************************************************************************/

/* Write a short/large/bignum integer value */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int writeShortInteger( INOUT STREAM *stream, IN_INT const long integer, 
					   IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

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

	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_INTEGER : MAKE_CTAG_PRIMITIVE( tag ) );
	return( writeNumeric( stream, integer ) );
	}

RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int writeInteger( INOUT STREAM *stream, 
				  IN_BUFFER( integerLength ) const BYTE *integer, 
				  IN_LENGTH_SHORT const int integerLength, 
				  IN_TAG const int tag )
	{
	const BOOLEAN leadingZero = ( integerLength > 0 && \
								  ( *integer & 0x80 ) ) ? 1 : 0;

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

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

	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_INTEGER : MAKE_CTAG_PRIMITIVE( tag ) );
	writeLength( stream, integerLength + leadingZero );
	if( leadingZero )
		sputc( stream, 0 );
	return( swrite( stream, integer, integerLength ) );
	}

#ifdef USE_PKC

RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int writeBignumTag( INOUT STREAM *stream, 
					IN TYPECAST( BIGNUM * ) const void *bignum, 
					IN_TAG const int tag )
	{
	BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
	int length, status;

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

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

	/* 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 ) )
		return( sSkip( stream, sizeofBignum( bignum ) ) );

	status = getBignumData( bignum, buffer, CRYPT_MAX_PKCSIZE, &length );
	if( cryptStatusError( status ) )
		retIntError_Stream( stream );
	status = writeInteger( stream, buffer, length, tag );
	zeroise( buffer, CRYPT_MAX_PKCSIZE );
	return( status );
	}
#endif /* USE_PKC */

/* Write an enumerated value */

RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int writeEnumerated( INOUT STREAM *stream, 
					 IN_RANGE( 0, 999 ) const int enumerated, 
					 IN_TAG const int tag )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

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

	writeTag( stream, ( tag == DEFAULT_TAG ) ? \
			  BER_ENUMERATED : MAKE_CTAG_PRIMITIVE( tag ) );

⌨️ 快捷键说明

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