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

📄 ext_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
		   info in the decoding table */
		if( !( flags & SETOF_FLAG_RESTARTPOINT ) && \
			currentPos >= setofInfoPtr->endPos )
			{
			int status;

			status = findItemEnd( &attributeInfoPtr, 0 );
			if( cryptStatusError( status ) )
				return( status );
			}
		}
	ENSURES( iterationCount < SETOF_STATE_STACKSIZE );

	*attributeInfoPtrPtr = attributeInfoPtr;
	return( ( attributeInfoPtr != oldAttributeInfoPtr ) ? \
			OK_SPECIAL : CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Identified Item Management Routines					*
*																			*
****************************************************************************/

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

CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 2 ) ) \
static const ATTRIBUTE_INFO *findIdentifiedItem( INOUT STREAM *stream,
									const ATTRIBUTE_INFO *attributeInfoPtr )
	{
	BYTE oid[ MAX_OID_SIZE + 8 ];
	int oidLength, sequenceLength, iterationCount, status;

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

	REQUIRES_N( 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 = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
							 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.
	   Unfortunately we can't use the attributeInfoSize bounds check limit 
	   here because we don't know how far through the attribute table we 
	   already are, so we have to use a generic large value */
	for( iterationCount = 0;
		 ( attributeInfoPtr->flags & FL_IDENTIFIER ) && \
			iterationCount < FAILSAFE_ITERATIONS_LARGE;
		 iterationCount++ )
		{
		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 { type }s added after the encoding table was defined 
			   don't get processed as errors, skip the field and continue */
			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 */
		ENSURES_N( oidPtr != 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 */
		status = findItemEnd( &attributeInfoPtr, 1 );
		if( cryptStatusError( status ) )
			return( NULL );
		attributeInfoPtr++;		/* Move to start of next item */
		}
	ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5, 6, 7 ) ) \
static int processIdentifiedItem( INOUT STREAM *stream, 
								  /*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
								  IN_FLAGS( ATTR ) const int flags, 
								  const SETOF_STACK *setofStack,
								  const ATTRIBUTE_INFO **attributeInfoPtrPtr,
								  OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
									CRYPT_ATTRIBUTE_TYPE *errorLocus,
								  OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
									CRYPT_ERRTYPE_TYPE *errorType )
	{
	static const int dummy = CRYPT_UNUSED;
	const SETOF_STATE_INFO *setofInfoPtr = setofTOS( setofStack );
	const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
	assert( isReadPtr( setofStack, sizeof( SETOF_STACK ) ) );
	assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
	assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

assert( ( flags & ~( ATTR_FLAG_CRITICAL ) ) == 0 );
	REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
	REQUIRES( !( flags & ATTR_FLAG_INVALID ) );

	/* Search for the identified item from the start of the set of items.  
	   The 0-th value is the SET OF/SEQUENCE OF so we start the search at 
	   the next entry which is the first FL_IDENTIFIER */
	ENSURES( setofInfoPtr->infoStart->flags & FL_SETOF );
	attributeInfoPtr = findIdentifiedItem( stream, 
										   setofInfoPtr->infoStart + 1 );
	if( attributeInfoPtr == NULL )
		return( CRYPT_ERROR_BADDATA );
	*attributeInfoPtrPtr = attributeInfoPtr;

	/* If it's a subtyped field, continue from a new encoding table */
	if( attributeInfoPtr->fieldType == FIELDTYPE_SUBTYPED )
		return( OK_SPECIAL );

	/* If it's not a special-case, non-encoding field, we're done */
	if( !( attributeInfoPtr->flags & FL_NONENCODING ) )
		return( CRYPT_OK );

	/* If the { type, value } pair has a fixed value then the information 
	   being conveyed is its presence, not its contents, so we add an 
	   attribute corresponding to its ID and continue.  The addition of the 
	   attribute is a bit tricky, some of the fixed type-and-value pairs can 
	   have multiple entries denoting things like { algorithm, weak key }, 
	   { algorithm, average key }, { algorithm, strong key }, however all 
	   that we're interested in is the strong key so we ignore the value and 
	   only use the type (in his ordo est ordinem non servare).  Since the 
	   same type can be present multiple times (with different { value }s) 
	   we ignore data duplicate errors and continue.  If we're processing a 
	   blob field type, we've ended up at a generic catch-any value and 
	   can't do much with it */
	if( attributeInfoPtr->fieldType != FIELDTYPE_BLOB )
		{
		int status;

		/* Add the field type, discarding warnings about dups */
		TRACE_FIELDTYPE( attributeInfoPtr, 0 );
		status = addAttributeField( attributeListPtrPtr,
							attributeInfoPtr->fieldID, CRYPT_ATTRIBUTE_NONE,
							&dummy, CRYPT_UNUSED, flags, errorLocus,
							errorType );
		if( status == CRYPT_ERROR_INITED )
			status = CRYPT_OK;
		else
			{
			if( cryptStatusError( status ) )
				return( CRYPT_ERROR_BADDATA );
			}
		}

	/* Reset the attribute info position in preparation for the next value 
	   and continue */
	attributeInfoPtr = setofInfoPtr->infoStart + 1;
	return( OK_SPECIAL );
	}

/* Read a sequence of identifier fields of the form { oid, value OPTIONAL }.
   This is used to read both SEQUENCE OF and CHOICE, with SEQUENCE OF 
   allowing multiple entries and CHOICE allowing only a single entry */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 6, 7 ) ) \
static int readIdentifierFields( INOUT STREAM *stream, 
								 /*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
								 const ATTRIBUTE_INFO **attributeInfoPtrPtr, 
								 IN_FLAGS( ATTR ) const int flags,
								 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID, 
								 OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
									CRYPT_ATTRIBUTE_TYPE *errorLocus,
								 OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
									CRYPT_ERRTYPE_TYPE *errorType )
	{
	const BOOLEAN isChoice = ( fieldID != CRYPT_ATTRIBUTE_NONE );
	int count = 0, iterationCount;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
	assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
	assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

assert( flags == ATTR_FLAG_NONE );
	REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
	REQUIRES( !( flags & ATTR_FLAG_INVALID ) );

	for( iterationCount = 0;
		 peekTag( stream ) == BER_OBJECT_IDENTIFIER && \
			iterationCount < FAILSAFE_ITERATIONS_LARGE;
		 iterationCount++ )
		{
		const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
		BYTE oid[ MAX_OID_SIZE + 8 ];
		BOOLEAN addField = TRUE;
		static const int dummy = CRYPT_UNUSED;
		int oidLength, innerIterationCount, status;

		/* Make sure that we don't die during parsing if there's an error in
		   the encoding table */
		ENSURES( attributeInfoPtr->oid != NULL );

		/* 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 = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
								 BER_OBJECT_IDENTIFIER );
		if( cryptStatusError( status ) )
			return( status );
		for( innerIterationCount = 0;
			 ( oidLength != sizeofOID( attributeInfoPtr->oid ) || \
			   memcmp( attributeInfoPtr->oid, oid, oidLength ) ) && \
			   innerIterationCount < FAILSAFE_ITERATIONS_MED;
			 innerIterationCount++ )
			{
			/* 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++;

			/* If this is a blob field we've hit a don't-care value which 
			   ensures that { type }s added after the encoding table was 
			   defined don't get processed as errors, skip the field and 
			   continue */
			if( attributeInfoPtr->fieldType == FIELDTYPE_BLOB )
				{
				addField = FALSE;
				break;
				}

			/* Make sure that we don't die during parsing if there's an error
			   in the encoding table */
			ENSURES( attributeInfoPtr->oid != NULL );
			}
		ENSURES( innerIterationCount < FAILSAFE_ITERATIONS_MED );
		TRACE_FIELDTYPE( attributeInfoPtr, 0 );
		if( addField )
			{
			/* 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 */
			if( isChoice )
				{
				/* 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( isChoice && count > 1 )
			{
			*errorLocus = attributeInfoPtr->fieldID,
			*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
			return( CRYPT_ERROR_BADDATA );
			}
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );

	/* 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 field's flags.
	   Unfortunately we can't use the attributeInfoSize bounds check limit 
	   here because we don't know how far through the attribute table we 
	   already are, so we have to use a generic large value */
	iterationCount = 0;
	while( !( ( *attributeInfoPtrPtr )->flags & FL_SEQEND_MASK ) && \
			( ( *attributeInfoPtrPtr )->flags & FL_MORE ) && \
			iterationCount++ < FAILSAFE_ITERATIONS_LARGE )
		( *attributeInfoPtrPtr )++;
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );

	return( CRYPT_OK );
	}

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

/* Generic error-handler that sets extended error codes */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int fieldErrorReturn( OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
								CRYPT_ATTRIBUTE_TYPE *errorLocus,
							 OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
								CRYPT_ERRTYPE_TYPE *errorType, 
							 IN_ERROR const int status,
							 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID )

⌨️ 快捷键说明

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