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

📄 ext_add.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*					Certificate Attribute Add/Delete Routines				*
*						Copyright Peter Gutmann 1996-2004					*
*																			*
****************************************************************************/

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

/* Prototypes for functions in cryptcrt.c */

int textToOID( const char *oid, const int oidLength, BYTE *binaryOID );

/* Prototypes for functions in ext.c */

ATTRIBUTE_LIST *findAttributeStart( const ATTRIBUTE_LIST *attributeListPtr );

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Check the validity of an attribute field */

static int checkAttributeField( const ATTRIBUTE_LIST *attributeListPtr,
								const ATTRIBUTE_INFO *attributeInfoPtr,
								const CRYPT_ATTRIBUTE_TYPE fieldID,
								const CRYPT_ATTRIBUTE_TYPE subFieldID,
								const void *data, const int dataLength,
								const int flags, 
								CRYPT_ERRTYPE_TYPE *errorType )
	{
	assert( attributeListPtr == NULL || \
			isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
	assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
	assert( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
			fieldID <= CRYPT_CERTINFO_LAST );
	assert( dataLength == CRYPT_UNUSED || \
			( dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE ) );
	assert( dataLength == CRYPT_UNUSED || isReadPtr( data, dataLength ) );
	assert( !( flags & ATTR_FLAG_INVALID ) );

	/* Make sure that a valid field has been specified, and that this field
	   isn't already present as a non-default entry unless it's a field for
	   which multiple values are allowed */
	if( attributeInfoPtr == NULL )
		return( CRYPT_ARGERROR_VALUE );
	if( attributeListPtr != NULL && \
		findAttributeField( attributeListPtr, fieldID, subFieldID ) != NULL )
		{
		/* If it's not multivalued, we can't have any duplicate fields */
		if( !( ( attributeInfoPtr->flags & FL_MULTIVALUED ) || \
			   ( flags & ATTR_FLAG_MULTIVALUED ) ) )
			{
			if( errorType != NULL )
				*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
			return( CRYPT_ERROR_INITED );
			}
		}

	/* If it's a blob field, don't do any type checking.  This is a special
	   case that differs from FIELDTYPE_BLOB in that it corresponds to an
	   ASN.1 value that's mis-encoded by one or more implementations, so we
	   have to accept absolutely anything at this point */
	if( flags & ATTR_FLAG_BLOB )
		return( CRYPT_OK );

	switch( attributeInfoPtr->fieldType )
		{
		case FIELDTYPE_IDENTIFIER:
			/* It's an identifier, make sure that all parameters are correct */
			assert( dataLength == CRYPT_UNUSED );
			if( *( ( int * ) data ) != CRYPT_UNUSED )
				return( CRYPT_ARGERROR_NUM1 );

			return( CRYPT_OK );

		case FIELDTYPE_DN:
			/* When creating a new cert, this is a special-case field that's 
			   used as a placeholder to indicate that a DN structure is being 
			   instantiated.  When reading an encoded cert, this is the 
			   decoded DN structure */
			assert( dataLength == CRYPT_UNUSED );
			return( CRYPT_OK );

		case BER_OBJECT_IDENTIFIER:
			{
			const BYTE *oidPtr = data;
			BYTE binaryOID[ MAX_OID_SIZE ];

			/* If it's a BER/DER-encoded OID, make sure that it's valid 
			   ASN.1 */
			if( oidPtr[ 0 ] == BER_OBJECT_IDENTIFIER )
				{
				if( dataLength >= 3 && sizeofOID( oidPtr ) == dataLength )
					return( CRYPT_OK );
				}
			else
				/* It's a text OID, check the syntax and make sure that the 
				   length is valid */
				if( textToOID( data, dataLength, binaryOID ) )
					return( CRYPT_OK );

			if( errorType != NULL )
				*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
			return( CRYPT_ARGERROR_STR1 );
			}

		case BER_BOOLEAN:
			assert( dataLength == CRYPT_UNUSED );

			/* BOOLEAN data is accepted as zero/nonzero so it's always 
			   valid, however we let the caller know that this is non-string 
			   data */
			return( OK_SPECIAL );

		case BER_INTEGER:
		case BER_ENUMERATED:
		case BER_BITSTRING:
		case BER_NULL:
		case FIELDTYPE_CHOICE:
			{
			int value = *( ( int * ) data );

			/* Check that the range is valid */
			if( value < attributeInfoPtr->lowRange || \
				value > attributeInfoPtr->highRange )
				{
				if( errorType != NULL )
					*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
				return( CRYPT_ARGERROR_NUM1 );
				}

			/* Let the caller know that this is non-string data */
			return( OK_SPECIAL );
			}

		}

	/* It's some sort of string value, perform a general data size check */
	if( dataLength < attributeInfoPtr->lowRange || \
		dataLength > attributeInfoPtr->highRange )
		{
		if( errorType != NULL )
			*errorType = CRYPT_ERRTYPE_ATTR_SIZE;
		return( CRYPT_ARGERROR_NUM1 );
		}

	/* If we're not checking the payload in order to handle CAs who stuff 
	   any old rubbish into the fields, exit now unless it's a blob field, 
	   for which we need to find at least valid ASN.1 data */
	if( ( flags & ATTR_FLAG_BLOB_PAYLOAD ) && \
		( attributeInfoPtr->fieldType != FIELDTYPE_BLOB ) )
		return( CRYPT_OK );

	switch( attributeInfoPtr->fieldType )
		{
		case FIELDTYPE_BLOB:
			/* It's a blob field, make sure that it's a valid ASN.1 object */
			if( cryptStatusError( checkObjectEncoding( data, dataLength ) ) )
				{
				if( errorType != NULL )
					*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
				return( CRYPT_ARGERROR_STR1 );
				}
			return( CRYPT_OK );

		case BER_STRING_NUMERIC:
			{
			const char *dataPtr = data;
			int i;

			/* Make sure that it's a numeric string */
			for( i = 0; i < dataLength; i++ )
				if( !isDigit( dataPtr[ i ] ) )
					{
					if( errorType != NULL )
						*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
					return( CRYPT_ARGERROR_STR1 );
					}
			return( CRYPT_OK );
			}

		case BER_STRING_IA5:
		case BER_STRING_ISO646:
		case BER_STRING_PRINTABLE:
			/* Make sure that it's an ASCII string of the correct type */
			if( !checkTextStringData( data, dataLength, 
					( attributeInfoPtr->fieldType == BER_STRING_PRINTABLE ) ? \
					TRUE : FALSE ) )
				{
				if( errorType != NULL )
					*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
				return( CRYPT_ARGERROR_STR1 );
				}
			return( CRYPT_OK );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								Add Attribute Data							*
*																			*
****************************************************************************/

/* Add a blob-type attribute to a list of attributes */

int addAttribute( const ATTRIBUTE_TYPE attributeType,
				  ATTRIBUTE_LIST **listHeadPtr, const BYTE *oid,
				  const BOOLEAN criticalFlag, const void *data,
				  const int dataLength, const int flags )
	{
	ATTRIBUTE_LIST *newElement, *insertPoint = NULL;
	const int oidLength = sizeofOID( oid );

	assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
	assert( isReadPtr( oid, oidLength ) );
	assert( criticalFlag == TRUE || criticalFlag == FALSE );
	assert( isReadPtr( data, dataLength ) );
	assert( ( flags & ( ATTR_FLAG_IGNORED | ATTR_FLAG_BLOB ) ) || \
			!cryptStatusError( checkObjectEncoding( data, dataLength ) ) );
	assert( dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE );
	assert( flags == ATTR_FLAG_NONE || flags == ATTR_FLAG_BLOB || \
			flags == ( ATTR_FLAG_BLOB | ATTR_FLAG_IGNORED ) );

	/* If this attribute type is already handled as a non-blob attribute,
	   don't allow it to be added as a blob as well.  This avoids problems
	   with the same attribute being added twice, once as a blob and once as
	   a non-blob.  In addition it forces the caller to use the (recommended)
	   normal attribute handling mechanism, which allows for proper type
	   checking */
	if( !( flags & ATTR_FLAG_BLOB ) && \
		oidToAttribute( attributeType, oid ) != NULL )
		return( CRYPT_ERROR_PERMISSION );

	/* Find the correct place in the list to insert the new element */
	if( *listHeadPtr != NULL )
		{
		ATTRIBUTE_LIST *prevElement = NULL;

		for( insertPoint = *listHeadPtr; insertPoint != NULL;
			 insertPoint = insertPoint->next )
			{
			/* Make sure that this blob attribute isn't already present */
			if( isBlobAttribute( insertPoint ) && \
				sizeofOID( insertPoint->oid ) == oidLength && \
				!memcmp( insertPoint->oid, oid, oidLength ) )
				return( CRYPT_ERROR_INITED );

			prevElement = insertPoint;
			}
		insertPoint = prevElement;
		}

	/* Allocate memory for the new element and copy the information across.  
	   The data is stored in storage ... storage + dataLength, the OID in
	   storage + dataLength ... storage + dataLength + oidLength */
	if( ( newElement = ( ATTRIBUTE_LIST * ) \
					   clAlloc( "addAttribute", sizeof( ATTRIBUTE_LIST ) + \
												dataLength + oidLength ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	initVarStruct( newElement, ATTRIBUTE_LIST, dataLength + oidLength );
	newElement->oid = newElement->storage + dataLength;
	memcpy( newElement->oid, oid, oidLength );
	newElement->flags = ( flags & ATTR_FLAG_IGNORED ) | \
						( criticalFlag ? ATTR_FLAG_CRITICAL : ATTR_FLAG_NONE );
	memcpy( newElement->value, data, dataLength );
	newElement->valueLength = dataLength;
	insertDoubleListElements( listHeadPtr, insertPoint, newElement, newElement );

	return( CRYPT_OK );
	}

⌨️ 快捷键说明

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