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

📄 certext.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:

	/* Moving by field or component is relatively simple.  For fields we move
	   backwards or forwards until we either run out of fields or the next 
	   field belongs to a different attribute.  For components we move 
	   similarly, except that we stop when we reach a field whose attribute
	   type, field type, and subfield type don't match the current one */
	if( certInfoType == CRYPT_CERTINFO_CURRENT_FIELD )
		{
		const CRYPT_ATTRIBUTE_TYPE attributeID = ( *currentCursor )->attributeID;

		if( position == CRYPT_CURSOR_FIRST || position == CRYPT_CURSOR_PREVIOUS )
			while( count-- && newCursor->prev != NULL && \
				   newCursor->prev->attributeID == attributeID )
				newCursor = newCursor->prev;
		else
			while( count-- && newCursor->next != NULL && \
				   newCursor->next->attributeID == attributeID )
				newCursor = newCursor->next;

		if( !absMove && *currentCursor == newCursor )
			return( CRYPT_ERROR_NOTFOUND );
		*currentCursor = ( ATTRIBUTE_LIST * ) newCursor;
		return( CRYPT_OK );
		}
	if( certInfoType == CRYPT_CERTINFO_CURRENT_COMPONENT )
		{
		const CRYPT_ATTRIBUTE_TYPE attributeID = ( *currentCursor )->attributeID;
		const CRYPT_ATTRIBUTE_TYPE fieldID = ( *currentCursor )->fieldID;
		const CRYPT_ATTRIBUTE_TYPE subFieldID = ( *currentCursor )->subFieldID;

		if( position == CRYPT_CURSOR_FIRST || position == CRYPT_CURSOR_PREVIOUS )
			while( count-- && newCursor->prev != NULL && \
				   newCursor->prev->attributeID == attributeID && \
				   newCursor->prev->fieldID == fieldID && \
				   newCursor->prev->subFieldID == subFieldID )
				newCursor = newCursor->prev;
		else
			while( count-- && newCursor->next != NULL && \
				   newCursor->next->attributeID == attributeID && \
				   newCursor->next->fieldID == fieldID && \
				   newCursor->next->subFieldID == subFieldID )
				newCursor = newCursor->next;

		if( !absMove && *currentCursor == newCursor )
			return( CRYPT_ERROR_NOTFOUND );
		*currentCursor = ( ATTRIBUTE_LIST * ) newCursor;
		return( CRYPT_OK );
		}

	/* Moving by attribute is a bit more complex.  First we find the start or
	   end of the current attribute.  Then we move to the start of the 
	   previous (via findAttributeStart())/start of the next (via the 'next' 
	   pointer) attribute beyond that.  This has the effect of moving us from 
	   anywhere in the current attribute to the start of the preceding or 
	   following attribute.  Finally, we repeat this as required */
	while( count-- && newCursor != NULL )
		{
		lastCursor = newCursor;
		if( position == CRYPT_CURSOR_FIRST || position == CRYPT_CURSOR_PREVIOUS )
			newCursor = findAttributeStart( findAttributeStart( newCursor )->prev );
		else
			newCursor = findAttributeEnd( newCursor )->next;
		}
	assert( lastCursor != NULL );	/* We went through loop at least once */

	/* If the new cursor is NULL, we've reached the start or end of the 
	   attribute list */
	if( newCursor == NULL )
		{
		/* Move to the start of the first or last attribute we got to before 
		   we ran out of attributes to make sure that we don't fall off the 
		   start/end of the list */
		*currentCursor = findAttributeStart( lastCursor );

		/* If it's an absolute move we've reached our destination, otherwise
		   there's nowhere left to move to */
		return( absMove ? CRYPT_OK : CRYPT_ERROR_NOTFOUND );
		}

	/* We've found what we were looking for */
	*currentCursor = ( ATTRIBUTE_LIST * ) newCursor;
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								Misc. Attribute Routines					*
*																			*
****************************************************************************/

/* Fix up certificate attributes, mapping from incorrect values to standards-
   compliant ones */

int fixAttributes( CERT_INFO *certInfoPtr )
	{
	ATTRIBUTE_LIST *attributeListPtr;
	int complianceLevel, status;

	/* Try and locate email addresses wherever they might be stashed and move
	   them to the cert altNames */
	status = convertEmail( certInfoPtr, &certInfoPtr->subjectName,
						   CRYPT_CERTINFO_SUBJECTALTNAME );
	if( cryptStatusOK( status ) )
		status = convertEmail( certInfoPtr, &certInfoPtr->issuerName,
							   CRYPT_CERTINFO_ISSUERALTNAME );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're running at a compliance level of 
	   CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL or above, don't try and fiddle any
	   dubious attributes */
	status = krnlSendMessage( certInfoPtr->ownerHandle, 
							  IMESSAGE_GETATTRIBUTE, &complianceLevel, 
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		return( status );
	if( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
		return( CRYPT_OK );

	/* If the only key usage info present is the Netscape one, convert it 
	   into the X.509 equivalent */
	if( findAttributeField( certInfoPtr->attributes, CRYPT_CERTINFO_KEYUSAGE, 
							CRYPT_ATTRIBUTE_NONE ) == NULL && \
		( attributeListPtr = findAttributeField( certInfoPtr->attributes, 
										CRYPT_CERTINFO_NS_CERTTYPE, 
										CRYPT_ATTRIBUTE_NONE ) ) != NULL )
		{
		int keyUsage = 0;

		/* There's a Netscape cert usage present but no X.509 one, map the
		   Netscape usage to the X.509 one */
		if( attributeListPtr->intValue & CRYPT_NS_CERTTYPE_SSLCLIENT )
			keyUsage |= CRYPT_KEYUSAGE_DIGITALSIGNATURE;
		if( attributeListPtr->intValue & CRYPT_NS_CERTTYPE_SSLSERVER )
			keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
		if( attributeListPtr->intValue & CRYPT_NS_CERTTYPE_SMIME )
			{
			keyUsage |= CRYPT_KEYUSAGE_DIGITALSIGNATURE;
			if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
				{
				int cryptAlgo;

				krnlSendMessage( certInfoPtr->iPubkeyContext, 
								 IMESSAGE_GETATTRIBUTE, &cryptAlgo, 
								 CRYPT_CTXINFO_ALGO );
				if( isCryptAlgo( cryptAlgo ) )
					keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
				}
			}
		if( attributeListPtr->intValue & ( CRYPT_NS_CERTTYPE_SSLCA | \
										   CRYPT_NS_CERTTYPE_SMIMECA | \
										   CRYPT_NS_CERTTYPE_OBJECTSIGNINGCA ) )
			keyUsage |= CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN;
		status = addAttributeField( &certInfoPtr->attributes,
							CRYPT_CERTINFO_KEYUSAGE, CRYPT_ATTRIBUTE_NONE,
							&keyUsage, CRYPT_UNUSED, ATTR_FLAG_NONE, 
							&certInfoPtr->errorLocus, &certInfoPtr->errorType );
		if( cryptStatusError( status ) )
			return( status );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Attribute Management Routines					*
*																			*
****************************************************************************/

/* 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 storageSize = dataLength + sizeofOID( oid );

	assert( isWritePtr( listHeadPtr, ATTRIBUTE_LIST * ) );
	assert( isReadPtr( oid, 3 ) );
	assert( criticalFlag == TRUE || criticalFlag == FALSE );
	assert( !checkBadPtrRead( data, dataLength ) );
	assert( dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE );
	assert( flags == ATTR_FLAG_NONE || flags == ATTR_FLAG_BLOB );

	/* 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 ) == sizeofOID( oid ) && \
				!memcmp( insertPoint->oid, oid, sizeofOID( oid ) ) )
				return( CRYPT_ERROR_INITED );

			prevElement = insertPoint;
			}
		insertPoint = prevElement;
		}

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

	return( CRYPT_OK );
	}

/* 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 )
	{
	ATTRIBUTE_LIST *attributeListSearchPtr;

	assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );
	assert( dataLength == CRYPT_UNUSED || \
			( dataLength > 0 && dataLength <= MAX_ATTRIBUTE_SIZE ) );
	assert( dataLength == CRYPT_UNUSED || \
			!checkBadPtrRead( 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 );
	attributeListSearchPtr = findAttributeField( attributeListPtr, fieldID,
												 subFieldID );
	if( attributeListSearchPtr != 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:
			/* It's a special-case field used as a placeholder when creating 
			   a new cert 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( oidPtr[ 1 ] == dataLength - 2 )
					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 via an alternative
			   return code 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 data size and 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 type 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 );

⌨️ 快捷键说明

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