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

📄 certexrd.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*						Certificate Attribute Read Routines					*
*						 Copyright Peter Gutmann 1996-2003					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) ||  defined( INC_CHILD )
  #include "cert.h"
  #include "certattr.h"
  #include "../misc/asn1_rw.h"
  #include "../misc/asn1s_rw.h"
#else
  #include "cert/cert.h"
  #include "cert/certattr.h"
  #include "misc/asn1_rw.h"
  #include "misc/asn1s_rw.h"
#endif /* Compiler-specific includes */

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

#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 ); \
		  }
#else
  #define TRACE_FIELDTYPE( attributeInfoPtr, stackPos )
#endif /* NDEBUG */

/* Prototypes for functions in certcomp.c */

int oidToText( const BYTE *binaryOID, char *oid );

/****************************************************************************
*																			*
*								Attribute Read Routines						*
*																			*
****************************************************************************/

/* 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 the depth parameter indicates how many nesting levels we have to
   undo */

static const ATTRIBUTE_INFO *findItemEnd( const ATTRIBUTE_INFO *attributeInfoPtr,
										  const int depth )
	{
	BOOLEAN attributeContinues;
	int currentDepth = depth;

	assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );
	assert( 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 );

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

/* Given a pointer to a set of SEQUENCE { type, value } entries, return a
   pointer to the value entry appropriate for the data in the stream.  If the
   entry contains user data in the { value } portion then the returned pointer
   points to this, if it contains a fixed value or isn't present at all then
   the returned pointer points to the { type } portion */

static const ATTRIBUTE_INFO *findIdentifiedItem( STREAM *stream,
									const ATTRIBUTE_INFO *attributeInfoPtr )
	{
	BYTE oid[ MAX_OID_SIZE ];
	int oidLength, sequenceLength, status;

	assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );
	assert( attributeInfoPtr->flags & FL_IDENTIFIER );

	/* Skip the header and read the OID.  We only check for a sane total
	   length in the debug version since this isn't a fatal error */
	readSequence( stream, &sequenceLength );
	status = readRawObject( stream, oid, &oidLength, MAX_OID_SIZE,
							BER_OBJECT_IDENTIFIER );
	if( cryptStatusError( status ) )
		return( NULL );
	sequenceLength -= oidLength;
	assert( sequenceLength >= 0 );

	/* Walk down the list of entries trying to match it to an allowed value */
	while( attributeInfoPtr->flags & FL_IDENTIFIER )
		{
		const BYTE *oidPtr;

		/* Skip the SEQUENCE and OID */
		attributeInfoPtr++;
		oidPtr = attributeInfoPtr->oid;
		if( !( attributeInfoPtr->flags & FL_NONENCODING ) )
			attributeInfoPtr++;
		else
			/* If this is a blob field, we've hit a don't-care value (usually
			   the last in a series of type-and-value pairs) which ensures
			   that new additions don't get processed as errors */
			if( attributeInfoPtr->fieldType == FIELDTYPE_BLOB )
				{
				/* If there's a { value } attached to the type, skip it */
				if( sequenceLength > 0 )
					sSkip( stream, sequenceLength );
				return( attributeInfoPtr );
				}

		/* In case there's an error in the encoding table, make sure that we
		   don't die during parsing */
		if( oidPtr == NULL )
			{
			assert( NOTREACHED );
			return( NULL );
			}

		/* If the OID matches, return a pointer to the value entry */
		if( oidLength == sizeofOID( oidPtr ) && \
			!memcmp( oidPtr, oid, sizeofOID( oidPtr ) ) )
			{
			/* If this is a fixed field and there's a value attached, skip
			   it */
			if( ( attributeInfoPtr->flags & FL_NONENCODING ) && \
				sequenceLength > 0 )
				sSkip( stream, sequenceLength );

			return( attributeInfoPtr );
			}

		/* The OID doesn't match, skip the value entry and continue.  We set
		   the current nesting depth parameter to 1 since we've already
		   entered the SEQUENCE above */
		attributeInfoPtr = findItemEnd( attributeInfoPtr, 1 ) + 1;
		}

	/* We reached the end of the set of entries without matching the OID */
	return( NULL );
	}

/* Read a sequence of identifier fields of the form
   SEQUENCE OF { oid, value OPTIONAL } */

static int readIdentifierFields( STREAM *stream, ATTRIBUTE_LIST **attributeListPtrPtr,
			const ATTRIBUTE_INFO **attributeInfoPtrPtr, const int flags,
			const CRYPT_ATTRIBUTE_TYPE fieldID, CRYPT_ATTRIBUTE_TYPE *errorLocus,
			CRYPT_ERRTYPE_TYPE *errorType )
	{
	int count = 0;

	assert( !( flags & ATTR_FLAG_INVALID ) );
	assert( isWritePtr( attributeListPtrPtr, ATTRIBUTE_LIST * ) );
	assert( isReadPtr( attributeInfoPtrPtr, ATTRIBUTE_INFO * ) );
	assert( isReadPtr( *attributeInfoPtrPtr, ATTRIBUTE_INFO ) );

	while( peekTag( stream ) == BER_OBJECT_IDENTIFIER )
		{
		const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
		BYTE oid[ MAX_OID_SIZE ];
		static const int dummy = CRYPT_UNUSED;
		int oidLength, status;

		/* Make sure that we don't die during parsing if there's an error in
		   the encoding table */
		if( attributeInfoPtr->oid == NULL )
			{
			assert( NOTREACHED );
			return( CRYPT_ERROR_FAILED );
			}

		/* Read the OID and walk down the list of possible OIDs up to the end
		   of the group of alternatives trying to match it to an allowed
		   value */
		status = readRawObject( stream, oid, &oidLength, MAX_OID_SIZE,
								BER_OBJECT_IDENTIFIER );
		if( cryptStatusError( status ) )
			return( status );
		while( oidLength != sizeofOID( attributeInfoPtr->oid ) || \
			   memcmp( attributeInfoPtr->oid, oid, oidLength ) )
			{
			/* If we've reached the end of the list and the OID wasn't
			   matched, exit */
			if( ( attributeInfoPtr->flags & FL_SEQEND_MASK ) || \
				!( attributeInfoPtr->flags & FL_MORE ) )
				return( CRYPT_ERROR_BADDATA );

			attributeInfoPtr++;

			/* Make sure that we don't die during parsing if there's an error
			   in the encoding table */
			if( attributeInfoPtr->oid == NULL )
				{
				assert( NOTREACHED );
				return( CRYPT_ERROR_FAILED );
				}
			}

		/* The OID matches, add this field as an identifier field (this
		   will catch duplicate OIDs since we can't add the same identifier
		   field twice) */
		TRACE_FIELDTYPE( attributeInfoPtr, 0 );
		if( fieldID != CRYPT_ATTRIBUTE_NONE )
			/* If there's a field value present then this is a CHOICE of
			   attributes whose value is the field value, so we add it with
			   this value */
			status = addAttributeField( attributeListPtrPtr,
									fieldID, CRYPT_ATTRIBUTE_NONE,
									&attributeInfoPtr->fieldID, CRYPT_UNUSED,
									flags, errorLocus, errorType );
		else
			/* It's a standard field */
			status = addAttributeField( attributeListPtrPtr,
							attributeInfoPtr->fieldID, CRYPT_ATTRIBUTE_NONE,
							&dummy, CRYPT_UNUSED, flags, errorLocus,
							errorType );
		if( cryptStatusError( status ) )
			return( status );
		count++;

		/* If there's more than one OID present in a CHOICE, it's an error */
		if( fieldID != CRYPT_ATTRIBUTE_NONE && count > 1 )
			{
			*errorLocus = attributeInfoPtr->fieldID,
			*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
			return( CRYPT_ERROR_BADDATA );
			}
		}

	/* We've processed the non-data field(s), move on to the next field.
	   We move to the last valid non-data field rather than the start of the
	   field following it since the caller needs to be able to check whether
	   there are more fields to follow using the current fields flags */
	while( !( ( *attributeInfoPtrPtr )->flags & FL_SEQEND_MASK ) && \
			( ( *attributeInfoPtrPtr )->flags & FL_MORE ) )
		( *attributeInfoPtrPtr )++;

	return( CRYPT_OK );
	}

/* Read the contents of attribute field.  This uses the readXXXData() 
   variants of the read functions because the field we're reading may be
   tagged, so we process the tag at a higher level and only read the 
   contents here */

static int fieldErrorReturn( CRYPT_ATTRIBUTE_TYPE *errorLocus,
							 CRYPT_ERRTYPE_TYPE *errorType, const int status,
							 const CRYPT_ATTRIBUTE_TYPE fieldID )
	{
	/* Since some fields are internal-use only (e.g. meaningless blob data,
	   version numbers, and other paraphernalia) we only set the locus if
	   it has a meaningful value */
	*errorLocus = ( fieldID > CRYPT_CERTINFO_FIRST && \
					fieldID < CRYPT_CERTINFO_LAST ) ? \
				  fieldID : CRYPT_ATTRIBUTE_NONE;
	*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
	return( status );
	}

static int readAttributeField( STREAM *stream, ATTRIBUTE_LIST **attributeListPtrPtr,
			const ATTRIBUTE_INFO *attributeInfoPtr,
			const CRYPT_ATTRIBUTE_TYPE subtypeParent, const int flags,
			CRYPT_ATTRIBUTE_TYPE *errorLocus, CRYPT_ERRTYPE_TYPE *errorType )
	{
	CRYPT_ATTRIBUTE_TYPE fieldID, subFieldID;
	int length, status;

	assert( !( flags & ATTR_FLAG_INVALID ) );
	assert( isWritePtr( attributeListPtrPtr, ATTRIBUTE_LIST * ) );
	assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );

	/* Set up the field identifiers depending on whether it's a normal field
	   or a subfield of a parent field */
	if( subtypeParent == CRYPT_ATTRIBUTE_NONE )
		{
		fieldID = attributeInfoPtr->fieldID;
		subFieldID = CRYPT_ATTRIBUTE_NONE;
		}
	else
		{
		fieldID = subtypeParent;
		subFieldID = attributeInfoPtr->fieldID;
		}

	/* If it's an integer or time type, read it */
	if( attributeInfoPtr->fieldType == BER_INTEGER || \
		attributeInfoPtr->fieldType == BER_ENUMERATED || \
		attributeInfoPtr->fieldType == BER_BITSTRING || \
		attributeInfoPtr->fieldType == BER_BOOLEAN || \
		attributeInfoPtr->fieldType == BER_NULL )
		{
		BOOLEAN boolean;
		long longValue;
		int value;

⌨️ 快捷键说明

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