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

📄 certcomp.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*					  Certificate Component Handling Routines				*
*						Copyright Peter Gutmann 1997-2001					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) ||  defined( INC_CHILD )
  #include "asn1.h"
  #include "asn1oid.h"
  #include "cert.h"
#else
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1oid.h"
  #include "keymgmt/cert.h"
#endif /* Compiler-specific includes */

/* This module includes (somewhat complex) handling for GeneralNames and
   DN's, which are handled via indirect selection.  There are four classes
   of field types which cover these names:

	GNSelection	= EXCLUDEDSUBTREES | ...
	GN			= OTHERNAME | ... | DIRECTORYNAME
	DNSelection	= SUBJECTNAME | ISSUERNAME | DIRECTORYNAME
	DN			= C | O | OU | CN | ...

   Note that DIRECTORYNAME is present twice since it's both a component of a
   GeneralName and a DN in its own right.  GNSelection and DNSelection
   components merely select a composite component, the primitive elements are
   read and written via the GN and DN values.  The selection process is as
   follows:

	GNSelection --+	(default = subjectAltName)
				  |
				  v
				 GN -+----------------> non-DirectoryName field
					 |
				  +--+ DirectoryName
				  |
	DNSelection --+	(default = subjectName)
				  |
				  v
				 DN ------------------> DN field

   Selecting a component can therefore lead through a complex heirarchy of
   explicit and implied selections, in the worst case being something like
   subjectAltName -> directoryName -> DN field */

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

/* Convert a binary OID to its text form */

int oidToText( const BYTE *binaryOID, char *oid )
	{
	char *outputPtr = oid;
	int i, j, length = binaryOID[ 1 ];
	long value;
#ifdef sun
	BOOLEAN brokenSprintf = FALSE;
#endif /* sun */

	/* Pick apart the OID.  This assumes that no OID component will be
	   larger than LONG_MAX */
	i = binaryOID[ 2 ] / 40;
	j = binaryOID[ 2 ] % 40;
	if( i > 2 )
		{
		/* Handle special case for large j if i = 2 */
		j += ( i - 2 ) * 40;
		i = 2;
		}
#ifdef sun
	if( sprintf( outputPtr, "X" ) != 1 )
		{
		/* SunOS/Slowaris has broken sprintf() handling, in SunOS 4.x this 
		   was documented as returning a pointer to the output data as per
		   the Berkeley original, under Slowaris the manpage was changed so 
		   it looks like any other sprintf() but it still returns the 
		   pointer to the output buffer in some versions so we have to check 
		   at runtime to see what we've got and adjust our behaviour 
		   accordingly.  In addition the standard sprintf()'s require casts
		   of the return value to avoid compile errors when building on SunOS
		   systems, these are safe because that code path is never taken on
		   these systems */
		assert( sprintf( outputPtr, "123" ) >= 4 );	/* Double-check */
		brokenSprintf = TRUE;
		outputPtr += strlen( ( void * ) sprintf( outputPtr, "%d %d", i, j ) );
		}
	else
#endif /* Sun braindamage */
	outputPtr += ( int ) sprintf( outputPtr, "%d %d", i, j );
	value = 0;
	for( i = 3; i < length + 2; i++ )
		{
		value = ( value << 7 ) | ( binaryOID[ i ] & 0x7F );
		if( !( binaryOID[ i ] & 0x80 ) )
			{
#ifdef sun
			if( brokenSprintf )
				outputPtr += strlen( ( void * ) sprintf( outputPtr, " %ld", value ) );
			else
#endif /* Sun braindamage */
			outputPtr += ( int ) sprintf( outputPtr, " %ld", value );
			value = 0;
			}

		/* Make sure we don't overflow the buffer (the value 20 is the
		   maximum magnitude of a 64-bit int plus space plus '\0') */
		if( outputPtr - oid > ( CRYPT_MAX_TEXTSIZE * 2 ) - 20 )
			return( CRYPT_ERROR_BADDATA );
		}
	length = strlen( oid );
	oid[ length ] = '\0';		/* Not really necessary, but nice */

	return( length );
	}

/* Check that a time value is valid */

static int checkTime( CERT_INFO *certInfoPtr, const CRYPT_ATTRIBUTE_TYPE type,
					  const time_t currentValue, const time_t newValue,
					  const int newValueLength )
	{
	/* Check to make sure the time given isn't before 1993, the start date
	   for X.509v2 (this is more of a consistency check than any real
	   requirement) */
	if( newValue < 0x2B3C0000L )
		{
		setErrorInfo( certInfoPtr, type, CRYPT_ERRTYPE_ATTR_VALUE );
		return( CRYPT_ARGERROR_STR1 );
		}
	if( newValueLength != sizeof( time_t ) )
		{
		setErrorInfo( certInfoPtr, type, CRYPT_ERRTYPE_ATTR_SIZE );
		return( CRYPT_ARGERROR_NUM1 );
		}
	if( currentValue )
		{
		setErrorInfo( certInfoPtr, type, CRYPT_ERRTYPE_ATTR_PRESENT );
		return( CRYPT_ERROR_INITED );
		}
	return( CRYPT_OK );
	}

/* Option codes for the GeneralName/DN selection functions */

typedef enum {
	SELECT_SELECT,			/* Remember current value */
	SELECT_INSTANTIATE_SET,	/* Instatiate remembered value, set pointer */
	SELECT_SET,				/* Set pointer from remembered value */
	SELECT_SYNC				/* Clear pointer from remembered value if item
							   deleted */
	} SELECT_OPTION;

/* Select a DN */

static int selectDN( CERT_INFO *certInfoPtr, const CRYPT_ATTRIBUTE_TYPE type,
					 const SELECT_OPTION option )
	{
	ATTRIBUTE_LIST *attributeListPtr;

	/* If we're being asked to remember the setting, just save the value and
	   exit */
	if( option == SELECT_SELECT )
		{
		if( certInfoPtr->currentDN != type )
			certInfoPtr->currentDNptr = NULL;
		certInfoPtr->currentDN = type;
		return( CRYPT_OK );
		}

	/* If there's no selection made, default to the subject name */
	if( certInfoPtr->currentDN == CRYPT_ATTRIBUTE_NONE )
		certInfoPtr->currentDN = CRYPT_CERTINFO_SUBJECTNAME;

	/* If we're being asked to sync the value to the current setting, make
	   sure the entry is still present and clear the settings if not */
	if( option == SELECT_SYNC )
		{
		const CRYPT_ATTRIBUTE_TYPE dnType = ( type == CRYPT_ATTRIBUTE_NONE ) ? \
											certInfoPtr->currentDN : type;
		ATTRIBUTE_LIST *attributeListPtr;

		/* If the subject name isn't present but is selected or specified,
		   clear the selection.  We can never get a sync on an issuer name
		   since it's read-only */
		if( dnType == CRYPT_CERTINFO_SUBJECTNAME )
			{
			if( certInfoPtr->subjectName == NULL )
				{
				certInfoPtr->currentDN = CRYPT_ATTRIBUTE_NONE;
				certInfoPtr->currentDNptr = NULL;
				}
			return( CRYPT_OK );
			}

		/* It's a DN in an attribute, check that the attribute is still
		   present and clear the DN selection if not */
		attributeListPtr = findAttributeField( certInfoPtr->attributes,
				certInfoPtr->currentGeneralName, CRYPT_CERTINFO_DIRECTORYNAME );
		if( attributeListPtr == NULL )
			{
			certInfoPtr->currentDN = CRYPT_ATTRIBUTE_NONE;
			certInfoPtr->currentDNptr = NULL;
			}
		return( CRYPT_OK );
		}

	/* If the DN is already selected, return now */
	if( certInfoPtr->currentDNptr != NULL )
		return( CRYPT_OK );

	/* The issuer and subject name fields are always present */
	if( certInfoPtr->currentDN == CRYPT_CERTINFO_ISSUERNAME )
		{
		certInfoPtr->currentDNptr = &certInfoPtr->issuerName;

		/* If it's a self-signed cert and the issuer name isn't explicitly
		   present then it must be implicitly present as the subject name */
		if( certInfoPtr->issuerName == NULL && \
			( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
			certInfoPtr->currentDNptr = &certInfoPtr->subjectName;

		return( CRYPT_OK );
		}
	if( certInfoPtr->currentDN == CRYPT_CERTINFO_SUBJECTNAME )
		{
		certInfoPtr->currentDNptr = &certInfoPtr->subjectName;
		return( CRYPT_OK );
		}

	/* From here on we're handling a DN in a GeneralName.  If there's
	   currently no GeneralName selected, default to the subject altName */
	if( certInfoPtr->currentGeneralName == CRYPT_ATTRIBUTE_NONE )
		certInfoPtr->currentGeneralName = CRYPT_CERTINFO_SUBJECTALTNAME;

	/* Try and find the requested DN */
	attributeListPtr = findAttributeField( certInfoPtr->attributes,
										   certInfoPtr->currentGeneralName,
										   CRYPT_CERTINFO_DIRECTORYNAME );
	if( attributeListPtr == NULL )
		{
		int value = CRYPT_UNUSED, status;

		/* If it's not present and we're not being asked to instantiate it,
		   return an error */
		if( option != SELECT_INSTANTIATE_SET )
			return( CRYPT_ERROR_NOTINITED );

		/* We're being asked to instantiate the DN, create the attribute
		   field which contains it */
		status = addAttributeField( &certInfoPtr->attributes,
					certInfoPtr->currentGeneralName,
					CRYPT_CERTINFO_DIRECTORYNAME, &value, CRYPT_UNUSED,
					ATTR_FLAG_NONE, &certInfoPtr->errorLocus,
					&certInfoPtr->errorType );
		if( cryptStatusError( status ) )
			return( status );

		/* Find the field we just created.  Since this can be a multivalued
		   attribute, we have to find the last component in the collection,
		   which will be the one we just added */
		attributeListPtr = findAttributeField( certInfoPtr->attributes,
				certInfoPtr->currentGeneralName, CRYPT_CERTINFO_DIRECTORYNAME );
		moveAttributeCursor( &attributeListPtr, 
				CRYPT_CERTINFO_CURRENT_COMPONENT, CRYPT_CURSOR_LAST );
		}

	/* Obtain the DN pointer from the attribute field */
	certInfoPtr->currentDNptr = ( void ** ) &attributeListPtr->data;

	return( CRYPT_OK );
	}

/* Select a GeneralName */

static ATTRIBUTE_LIST *selectGeneralName( CERT_INFO *certInfoPtr,
										  const CRYPT_ATTRIBUTE_TYPE certInfoType,
										  const SELECT_OPTION option  )
	{
	ATTRIBUTE_LIST *attributeListPtr;

	/* If it's a sync, make sure the selected GeneralName is still present */
	if( option == SELECT_SYNC )
		{
		if( certInfoPtr->currentGeneralName != CRYPT_ATTRIBUTE_NONE && \
			findAttributeField( certInfoPtr->attributes, \
								certInfoPtr->currentGeneralName, \
								CRYPT_ATTRIBUTE_NONE ) == NULL )
			certInfoPtr->currentGeneralName = CRYPT_ATTRIBUTE_NONE;

		return( NULL );		/* Return value is ignored */
		}

	/* If it's a straight GeneralName selection, remember the setting and
	   select as the new default DN the DirectoryName within the
	   GeneralName */
	if( isGeneralNameSelectionComponent( certInfoType ) )
		{
		if( certInfoPtr->currentGeneralName != certInfoType )
			{
			certInfoPtr->currentGeneralName = certInfoType;
			selectDN( certInfoPtr, CRYPT_CERTINFO_DIRECTORYNAME,
					  SELECT_SELECT );
			}
		attributeListPtr = findAttributeField( certInfoPtr->attributes,
					certInfoPtr->currentGeneralName, CRYPT_ATTRIBUTE_NONE );
		}
	else
		{
		/* If there's no General Name selected, default to the subject 
		   altName */
		if( certInfoPtr->currentGeneralName == CRYPT_ATTRIBUTE_NONE )
			certInfoPtr->currentGeneralName = CRYPT_CERTINFO_SUBJECTALTNAME;

		/* If we're selecting a DirectoryName, pass the call down to the DN
		   selection to set things up at that level */
		if( certInfoType == CRYPT_CERTINFO_DIRECTORYNAME )
			{
			if( cryptStatusError( selectDN( certInfoPtr,
								CRYPT_CERTINFO_DIRECTORYNAME, option ) ) )
				return( NULL );
			}
		attributeListPtr = findAttributeField( certInfoPtr->attributes,
							certInfoPtr->currentGeneralName, certInfoType );
		}

	/* Since a GeneralName is always part of an attribute, we also need to 
	   update the attribute cursor unless it's already set to this field, 
	   in which case updating it might overwrite the current component 
	   position in a multivalued field */
	if( attributeListPtr != NULL )
		{
		if( certInfoPtr->attributeCursor == NULL || \
			attributeListPtr->attributeID != \
							certInfoPtr->attributeCursor->attributeID || \
			attributeListPtr->fieldID != \
							certInfoPtr->attributeCursor->fieldID )
			certInfoPtr->attributeCursor = attributeListPtr;
		else
			/* Return the currently-selected component of a potentially
			   multivalued field.  Since this is set by the attribute
			   cursor management subsystem, we don't try and change it
			   here */
			attributeListPtr = certInfoPtr->attributeCursor;
		}
	return( attributeListPtr );
	}

⌨️ 快捷键说明

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