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

📄 certchk.c

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

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

/****************************************************************************
*																			*
*								Key Usage Routines							*
*																			*
****************************************************************************/

/* The following keyUsage settings are used based on extendedKeyUsage and
   Netscape key usage extensions.  In the following 'Y' = required, 'w' =
   written but apparently not required, S = for signature keys only, E = for
   encryption keys only, KA = for key agreement keys only.

						dig	non	key	dat	key	cer	crl	enc	dec		CA
						sig	rep	enc	enc	agt	sig	sig	onl	onl
   PKIX:				-------------------------------------------
	serverAuth			 S		 E		KA
	clientAuth			 S
	codeSign			 Y
	email				 Y	 Y	 E
	ipsecEndSys			 S		 E		KA
	ipsecTunnel			 S		 E		KA
	ipsecUser			 S		 E		KA
	timeStamping		 Y	 Y
   MS:					-------------------------------------------
	individualCodeSign	 Y
	commercialCodeSign	 Y
	ctlSign				 Y
	sgc									?
	encryptedFS							?
   NS:					-------------------------------------------
	sgc									?
   NS extensions:		-------------------------------------------
	sslClient			 Y
	sslServer					 Y
	sMime				 S		 E
	objectSign			 Y
	sslCA                               	 Y	 w				 Y
	sMimeCA									 Y	 w				 Y
	objectSignCA							 Y	 w				 Y
						-------------------------------------------
						dig	non	key	dat	key	cer	crl	enc	dec		CA
						sig	rep	enc	enc	agt	sig	sig	onl	onl */

/* Masks for various key usage types */

#define USAGE_SIGN_MASK			( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
								  CRYPT_KEYUSAGE_NONREPUDIATION | \
								  CRYPT_KEYUSAGE_KEYCERTSIGN | \
								  CRYPT_KEYUSAGE_CRLSIGN )
#define USAGE_CRYPT_MASK		( CRYPT_KEYUSAGE_KEYENCIPHERMENT | \
								  CRYPT_KEYUSAGE_DATAENCIPHERMENT )
#define USAGE_KEYAGREEMENT_MASK	( CRYPT_KEYUSAGE_KEYAGREEMENT | \
								  CRYPT_KEYUSAGE_ENCIPHERONLY | \
								  CRYPT_KEYUSAGE_DECIPHERONLY )

/* Flags to denote the algorithm type */

#define ALGO_TYPE_SIGN			1
#define ALGO_TYPE_CRYPT			2
#define ALGO_TYPE_KEYAGREEMENT	4

/* Table mapping extended key usage values to key usage flags */

static const struct {
	const CRYPT_ATTRIBUTE_TYPE usageType;
	const int keyUsageFlags;
	} extendedUsageInfo[] = {
	{ CRYPT_CERTINFO_EXTKEY_MS_INDIVIDUALCODESIGNING,	/* individualCodeSigning */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_MS_COMMERCIALCODESIGNING,	/* commercialCodeSigning */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_MS_CERTTRUSTLISTSIGNING,	/* certTrustListSigning */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_MS_TIMESTAMPSIGNING,	/* timeStampSigning */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_MS_SERVERGATEDCRYPTO,	/* serverGatedCrypto */
	  CRYPT_KEYUSAGE_NONE },	/* Not sure about this one */
	{ CRYPT_CERTINFO_EXTKEY_MS_ENCRYPTEDFILESYSTEM,	/* encrypedFileSystem */
	  CRYPT_KEYUSAGE_NONE },	/* Not sure about this one */
	{ CRYPT_CERTINFO_EXTKEY_SERVERAUTH,				/* serverAuth */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_CLIENTAUTH,				/* clientAuth */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_CODESIGNING,			/* codeSigning */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_EMAILPROTECTION,		/* emailProtection */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION },
	{ CRYPT_CERTINFO_EXTKEY_IPSECENDSYSTEM,			/* ipsecEndSystem */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_IPSECTUNNEL,			/* ipsecTunnel */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_IPSECUSER,				/* ipsecUser */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_TIMESTAMPING,			/* timeStamping */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION },
	{ CRYPT_CERTINFO_EXTKEY_NS_SERVERGATEDCRYPTO,	/* serverGatedCrypto */
	  CRYPT_KEYUSAGE_NONE },	/* Not sure about this one */
	{ CRYPT_ATTRIBUTE_NONE, 0 }
	};

/* Table mapping Netscape cert-type flags to extended key usage flags */

static const struct {
	const int certType;
	const int keyUsageFlags;
	} certTypeInfo[] = {
	{ CRYPT_NS_CERTTYPE_SSLCLIENT,
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_NS_CERTTYPE_SSLSERVER,
	  CRYPT_KEYUSAGE_KEYENCIPHERMENT },
	{ CRYPT_NS_CERTTYPE_SMIME,
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_KEYENCIPHERMENT },
	{ CRYPT_NS_CERTTYPE_OBJECTSIGNING,
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION },
	{ CRYPT_NS_CERTTYPE_RESERVED, 0 },
	{ CRYPT_NS_CERTTYPE_SSLCA,
	  CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
	{ CRYPT_NS_CERTTYPE_SMIMECA,
	  CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
	{ CRYPT_NS_CERTTYPE_OBJECTSIGNINGCA,
	  CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
	{ 0, 0 }
	};

/* Build up key usage flags consistent with the extended key usage purpose */

static int getExtendedKeyUsageFlags( const ATTRIBUTE_LIST *attributes,
									 const int algorithmType,
									 CRYPT_ATTRIBUTE_TYPE *errorLocus )
	{
	int keyUsage = 0, i;

	for( i = 0; extendedUsageInfo[ i ].usageType != CRYPT_ATTRIBUTE_NONE; i++ )
		{
		const ATTRIBUTE_LIST *attributeListPtr = findAttributeField( attributes, \
					extendedUsageInfo[ i ].usageType, CRYPT_ATTRIBUTE_NONE );
		int extendedUsage = 0;

		/* If this usage isn't present, continue */
		if( attributeListPtr == NULL )
			continue;

		/* If the usage is consistent with the algorithm type, add it */
		if( algorithmType & ALGO_TYPE_SIGN )
			extendedUsage |= extendedUsageInfo[ i ].keyUsageFlags & USAGE_SIGN_MASK;
		if( algorithmType & ALGO_TYPE_CRYPT )
			extendedUsage |= extendedUsageInfo[ i ].keyUsageFlags & USAGE_CRYPT_MASK;
		if( algorithmType & ALGO_TYPE_KEYAGREEMENT )
			extendedUsage |= extendedUsageInfo[ i ].keyUsageFlags & USAGE_KEYAGREEMENT_MASK;

		/* If there's no key usage consistent with the extended usage and the
		   extended usage isn't some special-case usage, return an error */
		if( !extendedUsage && extendedUsageInfo[ i ].keyUsageFlags )
			{
			*errorLocus = extendedUsageInfo[ i ].usageType;
			return( CRYPT_ERROR_INVALID );
			}

		keyUsage |= extendedUsage;
		}

	return( keyUsage );
	}

/* Build up key usage flags consistent with the Netscape cert-type purpose */

static int getCertTypeFlags( const ATTRIBUTE_LIST *attributes,
							 const int algorithmType,
							 CRYPT_ATTRIBUTE_TYPE *errorLocus, BOOLEAN *isCA )
	{
	const ATTRIBUTE_LIST *attributeListPtr = findAttributeField( attributes, \
							CRYPT_CERTINFO_NS_CERTTYPE, CRYPT_ATTRIBUTE_NONE );
	int nsCertType, keyUsage = 0, i;

	/* If there isn't a Netscape cert-type extension present, exit */
	if( attributeListPtr == NULL )
		return( 0 );
	nsCertType = ( int ) attributeListPtr->value;

	for( i = 0; certTypeInfo[ i ].certType; i++ )
		{
		int nsUsage = 0;

		/* If this isn't given cert-type, continue */
		if( !( nsCertType & certTypeInfo[ i ].certType ) )
			continue;

		/* If the usage is consistent with the algorithm type, add it */
		if( algorithmType & ALGO_TYPE_SIGN )
			nsUsage |= certTypeInfo[ i ].keyUsageFlags & USAGE_SIGN_MASK;
		if( algorithmType & ALGO_TYPE_CRYPT )
			nsUsage |= certTypeInfo[ i ].keyUsageFlags & USAGE_CRYPT_MASK;
		if( algorithmType & ALGO_TYPE_KEYAGREEMENT )
			nsUsage |= certTypeInfo[ i ].keyUsageFlags & USAGE_KEYAGREEMENT_MASK;

		/* If there's no key usage consistent with the Netscape cert-type,
		   return an error */
		if( !nsUsage )
			{
			*errorLocus = CRYPT_CERTINFO_NS_CERTTYPE;
			return( CRYPT_ERROR_INVALID );
			}

		keyUsage |= nsUsage;
		}

	/* If this is a CA cert-type, mark the key usage as being for a CA */
	if( nsCertType & ( CRYPT_NS_CERTTYPE_SSLCA | CRYPT_NS_CERTTYPE_SMIMECA | \
					   CRYPT_NS_CERTTYPE_OBJECTSIGNINGCA ) )
		*isCA = TRUE;

	return( keyUsage );
	}

/* Get the required key usage for the given cert object */

int getKeyUsageFlags( CERT_INFO *certInfoPtr, BOOLEAN *isCA )
	{
	int algorithmType = 0, keyUsage;

	*isCA = FALSE;

	/* Determine the possible algorithm usage type(s).  If we're passed a 
	   data-only cert (for example one from a cert chain read from an 
	   implicitly trusted private key store), there won't be a context 
	   present but we know the algorithm is OK for signing since it came 
	   from the trusted source */
	if( !cryptStatusError( certInfoPtr->iCryptContext ) )
		{
		int cryptAlgo;

		krnlSendMessage( certInfoPtr->iCryptContext, 
						 RESOURCE_IMESSAGE_GETATTRIBUTE, &cryptAlgo, 
						 CRYPT_CTXINFO_ALGO );
		if( isCryptAlgo( cryptAlgo ) )
			algorithmType |= ALGO_TYPE_CRYPT;
		if( isSigAlgo( cryptAlgo ) )
			algorithmType |= ALGO_TYPE_SIGN;
		if( isKeyxAlgo( cryptAlgo ) )
			algorithmType |= ALGO_TYPE_KEYAGREEMENT;
		}
	else
		algorithmType = ALGO_TYPE_SIGN;

	/* Get the key usage flags for the given extended/Netscape usage type(s)
	   and algorithm type */
	keyUsage = getExtendedKeyUsageFlags( certInfoPtr->attributes,
										 algorithmType,
										 &certInfoPtr->errorLocus );
	keyUsage |= getCertTypeFlags( certInfoPtr->attributes, algorithmType,
								  &certInfoPtr->errorLocus, isCA );
	if( cryptStatusError( keyUsage ) )
		{
		certInfoPtr->errorType = CRYPT_ERRTYPE_CONSTRAINT;
		return( CRYPT_ERROR_INVALID );
		}

	return( keyUsage );
	}

/* Check that the key usage flags are in order */

static int checkKeyUsageFlags( CERT_INFO *certInfoPtr )
	{
	ATTRIBUTE_LIST *attributeListPtr;
	BOOLEAN isCA;
	int attributeID, givenKeyUsage, keyUsage;

	/* Get the key usage modulo nonrepudiation and CRL signing (which have a
	   somewhat vague status) */
	keyUsage = getKeyUsageFlags( certInfoPtr, &isCA );
	if( cryptStatusError( keyUsage ) )
		return( keyUsage );
	keyUsage &= ~( CRYPT_KEYUSAGE_NONREPUDIATION | CRYPT_KEYUSAGE_CRLSIGN );

	/* Check the CA flag if necessary */
	if( isCA )
		{
		/* If the Netscape cert-type indicates the cert needs to be a CA cert
		   but it isn't marked as such, return an error */
		attributeListPtr = findAttributeField( certInfoPtr->attributes,
									CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE );
		if( attributeListPtr == NULL || !attributeListPtr->value )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
						  CRYPT_ERRTYPE_CONSTRAINT );
			return( CRYPT_ERROR_INVALID );
			}
		}

	/* Make sure that mutually exclusive flags aren't set */
	if( ( keyUsage & CRYPT_KEYUSAGE_ENCIPHERONLY ) && \
		( keyUsage & CRYPT_KEYUSAGE_DECIPHERONLY ) )
		{
		setErrorInfo( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
					  CRYPT_ERRTYPE_ATTR_VALUE );
		return( CRYPT_ERROR_INVALID );
		}

	/* If the usage and extended usage are critical (but only if both are 
	   critical, because PKIX says so) make sure that the given usage is 
	   consistent with the required usage.  Checking whether the extended 
	   usage is critical is a bit nontrivial, we have to check each possible
	   extended usage since only one of them may be present, so we check the
	   criticality of the basic key usage first to allow quick short-circuit
	   evaluation */
	attributeListPtr = findAttributeField( certInfoPtr->attributes,
							CRYPT_CERTINFO_KEYUSAGE, CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL && \
		!( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) )
		/* No critical key usage, return */
		return( CRYPT_OK );
	for( attributeID = CRYPT_CERTINFO_EXTKEYUSAGE + 1; 
		 attributeID < CRYPT_CERTINFO_NS_CERTTYPE; attributeID++ )
		{
		attributeListPtr = findAttributeField( certInfoPtr->attributes,
									attributeID, CRYPT_ATTRIBUTE_NONE );
		if( attributeListPtr != NULL && \
			!( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) )
			/* No critical extended usage, return */
			return( CRYPT_OK );
		}

	/* If there's no usage present we allow any usage, which isn't a good
	   thing but it's what's required */
	givenKeyUsage = ( attributeListPtr == NULL ) ? \
					~0 : ( int ) attributeListPtr->value;
	if( ( keyUsage & givenKeyUsage ) != keyUsage )
		{
		setErrorInfo( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
					  CRYPT_ERRTYPE_CONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	return( CRYPT_OK );
	}

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

/* Compare two attribute components */

static BOOLEAN compareAttributeComponents( const ATTRIBUTE_LIST *attribute1ptr,
										   const ATTRIBUTE_LIST *attribute2ptr )
	{
	const void *data1ptr, *data2ptr;

	/* Make sure either both are absent or present */
	if( attribute1ptr != NULL )
		{
		if( attribute2ptr == NULL )
			return( FALSE );	/* Both must be present or absent */
		}
	else
		{
		if( attribute2ptr != NULL )
			return( FALSE );	/* Both must be present or absent */
		return( TRUE );
		}

	/* If it's an attribute containing a composite field, use a special-case
	   compare */
	if( attribute1ptr->fieldType == FIELDTYPE_DN )
		return( compareDN( attribute1ptr->data, attribute2ptr->data, FALSE ) );

	/* Compare the data values */
	data1ptr = ( attribute1ptr->dataLength <= CRYPT_MAX_TEXTSIZE ) ? \
			   attribute1ptr->smallData : attribute1ptr->data;
	data2ptr = ( attribute2ptr->dataLength <= CRYPT_MAX_TEXTSIZE ) ? \
			   attribute2ptr->smallData : attribute2ptr->data;
	if( attribute1ptr->dataLength != attribute2ptr->dataLength || \
		memcmp( data1ptr, data2ptr, attribute1ptr->dataLength ) )
		return( FALSE );

⌨️ 快捷键说明

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