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

📄 certcget.c

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

#include <stdio.h>
#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 */

/****************************************************************************
*																			*
*								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
		   that 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 that 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 );
	}

/* Copy string data from a cert */

static int copyCertInfo( void *certInfo, int *certInfoLength,
						 const void *data, const int dataLength )
	{
	const int maxLength = *certInfoLength;

	if( dataLength <= 0 )
		return( CRYPT_ERROR_NOTFOUND );
	*certInfoLength = dataLength;
	if( certInfo == NULL )
		return( CRYPT_OK );
	if( dataLength > maxLength )
		return( CRYPT_ERROR_OVERFLOW );
	memcpy( certInfo, data, dataLength );
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							DN/GeneralName Routines							*
*																			*
****************************************************************************/

/* GeneralNames and DNs are handled via indirect selection.  There are four
   classes of field type that cover these names:

	GNSelection	= EXCLUDEDSUBTREES | ...
	GNValue		= OTHERNAME | ... | DIRECTORYNAME
	DNSelection	= SUBJECTNAME | ISSUERNAME | DIRECTORYNAME
	DNValue		= 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 implicit selections, in the worst case being something like
   subjectAltName -> directoryName -> DN field.  DN and GeneralName
   components may be absent (if we're selecting it in order to create it),
   or present (if we're about to read it), or can be created when accessed
   (if we're about to write to it).  The handling is selected by the
   SELECTION_OPTION type, if a cert is in the high state then MAY/CREATE 
   options are implicitly converted to MUST_BE_PRESENT during the selection 
   process.

   The selection is performed as follows:

	set attribute:

	  selectionComponent:
		selectDN	subject | issuer			| MAY_BE_ABSENT
		selectGN	attributeID					| MAY_BE_ABSENT
			- Select prior to use

	  valueComponent:
		selectDN	-							| CREATE_IF_ABSENT
		selectGN	-							| CREATE_IF_ABSENT
			- To create DN/GeneralName before adding DN/GN
			  component/setting DN string

	get attribute:

	  selectionComponent:
		check		subject | issuer | other	| Presence check only
		check		attributeID
			- Return T/F if present

	  valueComponent:
		selectDN	none						| MUST_BE_PRESENT
		selectGN	none						| MUST_BE_PRESENT
			- To get DN/GeneralName component

	delete attribute:

		selectDN	subject | issuers			| MUST_BE_PRESENT
		selectGN	attributeID					| MUST_BE_PRESENT
			- To delete DN/GeneralName component

   This code is cursed */

/* Check whether the currently selected extension is a GeneralName.  We do
   this both for simplicity and because isGeneralNameSelectionComponent() is
   a complex macro that we want to avoid expanding as much as possible */

static BOOLEAN isGeneralNameSelected( const CERT_INFO *certInfoPtr )
	{
	return( certInfoPtr->attributeCursor != NULL && \
			isGeneralNameSelectionComponent( certInfoPtr->attributeCursor->fieldID ) ? \
			TRUE : FALSE );
	}

#ifndef NDEBUG

static BOOLEAN selectionInfoConsistent( const CERT_INFO *certInfoPtr )
	{
	/* If the DN-in-extension flag is set, there must be a DN selected */
	if( certInfoPtr->currentSelection.dnPtr == NULL && \
		certInfoPtr->currentSelection.dnInExtension )
		return( FALSE );

	/* If there's a DN selected and it's not in in an extension, it must be
	   the subject or issuer DN */
	if( certInfoPtr->currentSelection.dnPtr != NULL && \
		!certInfoPtr->currentSelection.dnInExtension && \
		certInfoPtr->currentSelection.dnPtr != &certInfoPtr->subjectName && \
		certInfoPtr->currentSelection.dnPtr != &certInfoPtr->issuerName )
		return( FALSE );

	/* If there's a GeneralName selected, there can't also be a saved
	   GeneralName present */
	if( isGeneralNameSelected( certInfoPtr ) && \
		certInfoPtr->currentSelection.generalName != CRYPT_ATTRIBUTE_NONE )
		return( FALSE );

	return( TRUE );
	}
#endif /* NDEBUG */

/* Check whether there's a DN in the currently-selected extension, and update
   the various selection values if we find one */

static int findDnInExtension( CERT_INFO *certInfoPtr,
							  const BOOLEAN updateCursor )
	{
	const CRYPT_ATTRIBUTE_TYPE attributeID = certInfoPtr->attributeCursor->attributeID;
	const CRYPT_ATTRIBUTE_TYPE fieldID = certInfoPtr->attributeCursor->fieldID;
	ATTRIBUTE_LIST *attributeListPtr;

	/* We're inside a GeneralName, clear any possible saved selection */
	certInfoPtr->currentSelection.generalName = CRYPT_ATTRIBUTE_NONE;

	assert( selectionInfoConsistent( certInfoPtr ) );

	/* Search for a DN in the current GeneralName */
	for( attributeListPtr = certInfoPtr->attributeCursor; \
		 attributeListPtr != NULL && \
			attributeListPtr->attributeID == attributeID && \
			attributeListPtr->fieldID == fieldID; \
		 attributeListPtr = attributeListPtr->next )
		if( attributeListPtr->fieldType == FIELDTYPE_DN )
			{
			/* We found a DN, select it */
			certInfoPtr->currentSelection.dnPtr = &attributeListPtr->value;
			if( updateCursor )
				certInfoPtr->attributeCursor = attributeListPtr;
			certInfoPtr->currentSelection.dnInExtension = TRUE;
			assert( selectionInfoConsistent( certInfoPtr ) );
			return( CRYPT_OK );
			}

	return( CRYPT_ERROR_NOTFOUND );
	}

/* Find a GeneralName field in a GeneralName */

#if 0

/* Currently handled with:

	attributeListPtr = findAttributeField( certInfoPtr->attributeCursor,
										   certInfoPtr->attributeCursor->fieldID,
										   certInfoType ); */

static const ATTRIBUTE_LIST *findGeneralNameField( const ATTRIBUTE_LIST *attributeListPtr,
												   const CRYPT_ATTRIBUTE_TYPE certInfoType )
	{
	const CRYPT_ATTRIBUTE_TYPE attributeID = attributeListPtr->attributeID;
	const CRYPT_ATTRIBUTE_TYPE fieldID = attributeListPtr->fieldID;

	assert( isGeneralNameSelectionComponent( attributeListPtr->fieldID ) );

	/* Search for the GeneralName component in the current GeneralName */
	while( attributeListPtr != NULL && \
		   attributeListPtr->attributeID == attributeID && \
		   attributeListPtr->fieldID == fieldID )
		{
		if( attributeListPtr->subFieldID == certInfoType )
			return( attributeListPtr );
		attributeListPtr = attributeListPtr->next;
		}

	return( NULL );
	}
#endif /* 0 */

/* Move the extension cursor to the given extension field */

int moveCursorToField( CERT_INFO *certInfoPtr,
					   const CRYPT_ATTRIBUTE_TYPE certInfoType )
	{
	const ATTRIBUTE_LIST *attributeListPtr;

	assert( selectionInfoConsistent( certInfoPtr ) );
	assert( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
			certInfoType <= CRYPT_CERTINFO_LAST );

	/* Try and locate the given field in the extension */
	attributeListPtr = findAttributeField( certInfoPtr->attributes,
										   certInfoType,
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr == NULL )
		return( CRYPT_ERROR_NOTFOUND );

	/* We found the given field, update the cursor and select the DN within
	   it if it's present */
	certInfoPtr->currentSelection.updateCursor = FALSE;
	certInfoPtr->attributeCursor = ( ATTRIBUTE_LIST * ) attributeListPtr;
	if( isGeneralNameSelectionComponent( certInfoType ) )
		/* If this is a GeneralName, select the DN within it if there's one
		   present */
		findDnInExtension( certInfoPtr, FALSE );
	assert( selectionInfoConsistent( certInfoPtr ) );
	return( CRYPT_OK );
	}

/* Synchronise DN/GeneralName selection information after moving the
   extension cursor */

void syncSelection( CERT_INFO *certInfoPtr )
	{
	/* We've moved the cursor, clear any saved GeneralName selection */
	certInfoPtr->currentSelection.generalName = CRYPT_ATTRIBUTE_NONE;

	/* I've we've moved the cursor off the GeneralName or there's no DN in
	   the GeneralName, deselect the DN */
	if( !isGeneralNameSelected( certInfoPtr ) || \
		cryptStatusError( findDnInExtension( certInfoPtr, FALSE ) ) )
		{
		certInfoPtr->currentSelection.dnPtr = NULL;
		certInfoPtr->currentSelection.dnInExtension = FALSE;
		}
	}

/* Handle selection of a GeneralName in a cert extension */

int selectGeneralName( CERT_INFO *certInfoPtr,
					   const CRYPT_ATTRIBUTE_TYPE certInfoType,
					   const SELECTION_OPTION option )
	{
	assert( ( option == MAY_BE_ABSENT && \
			  isGeneralNameSelectionComponent( certInfoType ) ) || \
			( ( option == MUST_BE_PRESENT || option == CREATE_IF_ABSENT ) && \
			  certInfoType == CRYPT_ATTRIBUTE_NONE ) );
	assert( selectionInfoConsistent( certInfoPtr ) );

	certInfoPtr->currentSelection.updateCursor = FALSE;

	if( option == MAY_BE_ABSENT )
		{
		/* If the selection is present, update the extension cursor and
		   exit */
		if( cryptStatusOK( moveCursorToField( certInfoPtr, certInfoType ) ) )
			return( CRYPT_OK );

		/* If the certificate is in the high state, the MAY is treated as
		   a MUST, since we can't be selecting something so that we can
		   create it later */
		if( certInfoPtr->certificate != NULL )
			return( CRYPT_ERROR_NOTFOUND );

		/* The selection isn't present, remember it for later, without
		   changing any other selection info */
		certInfoPtr->currentSelection.generalName = certInfoType;
		certInfoPtr->attributeCursor = NULL;
		assert( selectionInfoConsistent( certInfoPtr ) );
		return( CRYPT_OK );
		}

	assert( option == MUST_BE_PRESENT || option == CREATE_IF_ABSENT );

	/* If there's no saved GeneralName selection present, the extension
	   cursor must be pointing to a GeneralName */
	if( certInfoPtr->currentSelection.generalName == CRYPT_ATTRIBUTE_NONE )
		return( isGeneralNameSelected( certInfoPtr ) ? \
				CRYPT_OK : CRYPT_ERROR_NOTFOUND );

	/* Try and move the cursor to the saved GeneralName selection */

⌨️ 快捷键说明

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