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

📄 ext_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						Certificate Attribute Read Routines					*
*						 Copyright Peter Gutmann 1996-2007					*
*																			*
****************************************************************************/

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

/* Define the following to print a trace of the certificate fields being 
   parsed, useful for debugging broken certificates */

#if !defined( NDEBUG ) && 0
  #define TRACE_FIELDTYPE( attributeInfoPtr, stackPos ) \
		  { \
		  int i; \
		  \
		  for( i = 0; i < stackPos; i++ ) \
			  printf( "  " ); \
		  if( ( attributeInfoPtr ) != NULL && \
			  ( attributeInfoPtr )->description != NULL ) \
			  puts( ( attributeInfoPtr )->description ); \
		  }
  #define TRACE_DEBUG( message, status ) \
		  printf( message, status );
#else
  #define TRACE_FIELDTYPE( attributeInfoPtr, stackPos )
  #define TRACE_DEBUG( message, status )
#endif /* NDEBUG */

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

/* Get the tag for a field from the attribute field definition */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int getFieldTag( INOUT STREAM *stream, 
						const ATTRIBUTE_INFO *attributeInfoPtr,
						int *tag )
	{
	int status, value;

	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
	assert( isWritePtr( tag, sizeof( int ) ) );

	/* Clear return value.  This is actually a bit difficult to do because 
	   the output can have both positive values (tags) and negative values 
	   (field codes), setting the output to -1000 is invalid for both 
	   types */
	*tag = -1000;

	/* Check whether the field is tagged */
	status = value = getFieldEncodedTag( attributeInfoPtr );
	if( cryptStatusError( status ) )
		{
		/* If there's no tagging (i.e. the tag is the same as the field 
		   type) we'll get an OK_SPECIAL return value, this isn't an 
		   error */
		if( status != OK_SPECIAL )
			return( status );
		}
	else
		{
		/* It's a tagged field, return the encoded form */
		*tag = value;

		return( CRYPT_OK );
		}
	ENSURES( status == OK_SPECIAL );

	/* It's a non-tagged field, the tag is the same as the field type */
	value = attributeInfoPtr->fieldType;
	if( value == FIELDTYPE_DISPLAYSTRING )
		{
		/* This is a variable-tag field that can have one of a number of 
		   tags.  To handle this we peek ahead into the stream to see if an 
		   acceptable tag is present and if not set the value to a non-
		   matching tag value */
		status = value = peekTag( stream );
		if( cryptStatusError( status ) )
			return( status );
		if( ( value != BER_STRING_IA5 ) && \
			( value != BER_STRING_ISO646 ) && \
			( value != BER_STRING_BMP ) && ( value != BER_STRING_UTF8 ) )
			value++;	/* Make sure that it doesn't match */
		}

	ENSURES( ( ( value == FIELDTYPE_BLOB || value == FIELDTYPE_DN ) && \
			   !( attributeInfoPtr->flags & FL_OPTIONAL ) ) || \
			 ( value > 0 && value < 0xF0 ) );
	*tag = value;

	return( CRYPT_OK );
	}

/* Find the end of an item (either primitive or constructed) in the attribute
   table.  Sometimes we may have already entered a constructed object (for
   example when an attribute has a version number so we don't know until we've
   started processing it that we can't do anything with it), if this is the
   case then the depth parameter indicates how many nesting levels we have to 
   undo */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int findItemEnd( const ATTRIBUTE_INFO **attributeInfoPtrPtr,
						IN_RANGE( 0, 3 ) const int depth )
	{
	const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
	BOOLEAN attributeContinues;
	int currentDepth = depth, iterationCount = 0;

	assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
	assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );

	REQUIRES( depth >= 0 && depth < 3 );

	/* Skip to the end of the (potentially) constructed item by recording the
	   nesting level and continuing until either it reaches zero or we reach
	   the end of the item */
	do
		{
		/* If it's a sequence/set, increment the depth; if it's an end-of-
		   constructed-item marker, decrement it by the appropriate amount */
		if( attributeInfoPtr->fieldType == BER_SEQUENCE || \
			attributeInfoPtr->fieldType == BER_SET )
			currentDepth++;
		currentDepth -= decodeNestingLevel( attributeInfoPtr->flags );

		/* Move to the next entry */
		attributeContinues = ( attributeInfoPtr->flags & FL_MORE ) ? TRUE : FALSE;
		attributeInfoPtr++;
		}
	while( currentDepth > 0 && attributeContinues && \
		   iterationCount++ < FAILSAFE_ITERATIONS_MED );
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );

	/* We return the previous entry, since we're going to move on to the 
	   next entry once we return */
	*attributeInfoPtrPtr = attributeInfoPtr - 1;
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							SET/SEQUENCE Management Routines				*
*																			*
****************************************************************************/

/* When we're processing SETs/SEQUENCEs (generically referred to as a SET
   OF) we need to maintain a stack of state information to handle a nested 
   SET OF.  The following code implements the state stack */

#define SETOF_STATE_STACKSIZE	16

#define SETOF_FLAG_NONE			0x00	/* No flag value */
#define SETOF_FLAG_SUBTYPED		0x01	/* SET ends on a subtyped value */
#define SETOF_FLAG_RESTARTPOINT	0x02	/* SET OF rather than SET */
#define SETOF_FLAG_ISEMPTY		0x04	/* Cleared if SET OF contains at least one entry */

typedef struct {
	/* SET OF state information */
	const ATTRIBUTE_INFO *infoStart;	/* Start of SET OF attribute info */
	int startPos, endPos;	/* Start and end position of SET OF */
	int flags;				/* SET OF flags */

	/* Subtype information */
	CRYPT_ATTRIBUTE_TYPE subtypeParent;	/* Parent type if this is subtyped */
	int inheritedFlags;		/* Flags inherited from parent if subtyped */
	} SETOF_STATE_INFO;

typedef struct {
	ARRAY( SETOF_STATE_STACKSIZE, stackPos ) \
	SETOF_STATE_INFO stateInfo[ SETOF_STATE_STACKSIZE + 8 ];
	int stackPos;			/* Current position in stack */
	} SETOF_STACK;

STDC_NONNULL_ARG( ( 1 ) ) \
static void setofStackInit( OUT SETOF_STACK *setofStack )
	{
	assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );

	memset( setofStack, 0, sizeof( SETOF_STACK ) );
	}

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN setofStackPush( INOUT SETOF_STACK *setofStack )
	{
	const int newPos = setofStack->stackPos + 1;

	assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );

	/* Increment the stack pointer and make sure that we don't overflow */
	ENSURES_B( newPos >= 1 && newPos < SETOF_STATE_STACKSIZE );
	setofStack->stackPos = newPos;

	/* Initialise the new entry */
	memset( &setofStack->stateInfo[ newPos ], 0, \
			sizeof( SETOF_STATE_INFO ) );

	return( TRUE );
	}

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN setofStackPop( INOUT SETOF_STACK *setofStack )
	{
	const int newPos = setofStack->stackPos - 1;

	assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );

	/* Decrement the stack pointer and make sure that we don't underflow */
	ENSURES_B( newPos >= 0 && newPos < SETOF_STATE_STACKSIZE - 1 );
	setofStack->stackPos = newPos;

	return( TRUE );
	}

CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
static SETOF_STATE_INFO *setofTOS( const SETOF_STACK *setofStack )
	{
	assert( isReadPtr( setofStack, sizeof( SETOF_STACK ) ) );

	return( ( SETOF_STATE_INFO * ) \
			&setofStack->stateInfo[ setofStack->stackPos ] );
	}

/* Process the start of a SET/SET OF/SEQUENCE/SEQUENCE OF */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int beginSetof( INOUT STREAM *stream, 
					   INOUT SETOF_STACK *setofStack,
					   const ATTRIBUTE_INFO *attributeInfoPtr )
	{
	SETOF_STATE_INFO *setofInfoPtr = setofTOS( setofStack );
	CRYPT_ATTRIBUTE_TYPE oldSubtypeParent;
	int oldInheritedFlags, setofLength, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );
	assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
	
	REQUIRES( !( attributeInfoPtr->flags & FL_EXPLICIT ) );

	/* Determine the length and start position of the SET OF items */
	if( attributeInfoPtr->fieldEncodedType >= 0 )
		{
		status = readConstructed( stream, &setofLength,
								  attributeInfoPtr->fieldEncodedType );
		}
	else
		{
		if( attributeInfoPtr->fieldType == BER_SET )
			status = readSet( stream, &setofLength );
		else
			status = readSequence( stream, &setofLength );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* When processing a SET/SEQUENCE with default values for the elements 
	   the result may be a zero-length object, in which case we don't take 
	   any action */
	if( setofLength <= 0 )
		return( CRYPT_OK );

	/* Remember assorted info such as where the SET/SEQUENCE ends.  In 
	   addition if this is a SET OF/SEQUENCE OF, remember this as a restart 
	   point for when we're parsing the next item in the SET/SEQUENCE OF */
	oldSubtypeParent = setofInfoPtr->subtypeParent;
	oldInheritedFlags = setofInfoPtr->inheritedFlags;
	if( !setofStackPush( setofStack ) )
		{
		/* Stack overflow, there's a problem with the certificate */
		return( CRYPT_ERROR_OVERFLOW );
		}
	setofInfoPtr = setofTOS( setofStack );
	setofInfoPtr->infoStart = attributeInfoPtr;
	if( attributeInfoPtr->flags & FL_SETOF )
		setofInfoPtr->flags |= SETOF_FLAG_RESTARTPOINT;
	if( attributeInfoPtr->flags & FL_NONEMPTY )
		setofInfoPtr->flags |= SETOF_FLAG_ISEMPTY;
	setofInfoPtr->subtypeParent = oldSubtypeParent;
	setofInfoPtr->inheritedFlags = oldInheritedFlags;
	setofInfoPtr->startPos = stell( stream );
	setofInfoPtr->endPos = setofInfoPtr->startPos + setofLength;

	return( CRYPT_OK );
	}

/* Check whether we've reached the end of a SET/SEQUENCE.  Returns OK_SPECIAL
   if the end has been reached */

CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int checkSetofEnd( const STREAM *stream, 
						  INOUT SETOF_STACK *setofStack,
						  const ATTRIBUTE_INFO **attributeInfoPtrPtr )
	{
	const SETOF_STATE_INFO *setofInfoPtr = setofTOS( setofStack );
	const ATTRIBUTE_INFO *oldAttributeInfoPtr = *attributeInfoPtrPtr;
	const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
	const int currentPos = stell( stream );
	int iterationCount;

	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );
	assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
	assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );

	/* If we're still within the SET/SEQUENCE, we're done */
	if( setofStack->stackPos <= 0 || currentPos < setofInfoPtr->endPos )
		return( CRYPT_OK );

	/* We've reached the end of or or more layers of SET/SEQUENCE, keep 
	   popping SET/SEQUENCE state info until we can continue */
	for( iterationCount = 0;
		 setofStack->stackPos > 0 && \
			currentPos >= setofInfoPtr->endPos && \
			iterationCount < SETOF_STATE_STACKSIZE;
		 iterationCount++ )
		{
		const int flags = setofInfoPtr->flags;

		/* Pop one level of parse state */
		if( !setofStackPop( setofStack ) )
			{
			/* Stack underflow, there's a problem with the certificate */
			return( CRYPT_ERROR_UNDERFLOW );
			}
		setofInfoPtr = setofTOS( setofStack );
		attributeInfoPtr = setofInfoPtr->infoStart;
		ENSURES( setofInfoPtr->endPos > 0 && \
				 setofInfoPtr->endPos < MAX_INTLENGTH_SHORT );

		/* If it's a pure SET/SEQUENCE (not a SET OF/SEQUENCE OF) and there 
		   are no more elements present, go to the end of the SET/SEQUENCE 

⌨️ 快捷键说明

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