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

📄 chk_use.c

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

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

/****************************************************************************
*																			*
*						ExtKeyUsage to 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
						sig	rep	enc	enc	agt	sig	sig	onl	onl
   PKIX:				-----------------------------------
	serverAuth			 S		 E		KA					[1]
	clientAuth			 S
	codeSign			 Y
	email				 Y	 Y	 E
	ipsecEndSys			 S		 E		KA
	ipsecTunnel			 S		 E		KA
	ipsecUser			 S		 E		KA
	timeStamping		 Y	 Y
	ocsp				 Y
	directoryService	 ?
   MS:					-----------------------------------
	individualCodeSign	 Y
	commercialCodeSign	 Y
	ctlSign				 Y
	tsa					 Y
	sgc							 E
	encryptedFS					 E
   NS:					-----------------------------------
	sgc							 E
   NS extensions:		-----------------------------------
	sslClient			 Y
	sslServer			 S		 E							[1]
	sMime				 S		 E
	objectSign			 Y
	sslCA                               	 Y	 w
	sMimeCA									 Y	 w
	objectSignCA							 Y	 w
						-----------------------------------
						dig	non	key	dat	key	cer	crl	enc	dec
						sig	rep	enc	enc	agt	sig	sig	onl	onl

   [1] These keys need to potentially perform both decryption for RSA key 
       transport and signing for (authenticating) DH key agreement */

/* 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 )

/* Mask for key usage types that we don't check for consistency against
   extended key usages.  The two CA usages don't occur in extended key usage,
   and no-one can agree on what non-repudiation is supposed to mean */

#define USAGE_MASK_NONRELEVANT	( CRYPT_KEYUSAGE_NONREPUDIATION | \
								  CRYPT_KEYUSAGE_KEYCERTSIGN | \
								  CRYPT_KEYUSAGE_CRLSIGN )

/* 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 FAR_BSS 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_KEYENCIPHERMENT },
	{ CRYPT_CERTINFO_EXTKEY_MS_ENCRYPTEDFILESYSTEM,	/* encrypedFileSystem */
	  CRYPT_KEYUSAGE_KEYENCIPHERMENT },
	{ 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_OCSPSIGNING,			/* ocspSigning */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_DIRECTORYSERVICE,		/* directoryService */
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_CERTINFO_EXTKEY_NS_SERVERGATEDCRYPTO,	/* serverGatedCrypto */
	  CRYPT_KEYUSAGE_KEYENCIPHERMENT },
	{ CRYPT_ATTRIBUTE_NONE, 0 }
	};

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

static const FAR_BSS struct {
	const int certType;
	const int keyUsageFlags;
	} certTypeInfo[] = {
	{ CRYPT_NS_CERTTYPE_SSLCLIENT,
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE },
	{ CRYPT_NS_CERTTYPE_SSLSERVER,
	  CRYPT_KEYUSAGE_DIGITALSIGNATURE | 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.  
   We don't have to perform any special-case handling for 
   anyExtendedKeyUsage (added in RFC 3280, section 4.2.1.13) since it's a 
   no-op extension whose presence is the equivalent of adding "|| TRUE" to 
   an expression */

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 getNetscapeCertTypeFlags( const ATTRIBUTE_LIST *attributes,
									 const int algorithmType,
									 CRYPT_ATTRIBUTE_TYPE *errorLocus )
	{
	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->intValue;

	/* The Netscape cert-type value is a bitfield containing the different
	   cert types.  For each cert-type flag which is set, we set the
	   corresponding keyUsage flags */
	for( i = 0; certTypeInfo[ i ].certType; i++ )
		{
		int nsUsage = 0;

		/* If this isn't the currently-selected 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;
		}

	return( keyUsage );
	}

/* Get key usage flags for a cert based on its extended key usage/Netscape 
   cert-type.  Returns 0 if no extKeyUsage/cert-type values present */

int getKeyUsageFromExtKeyUsage( const CERT_INFO *certInfoPtr,
								CRYPT_ATTRIBUTE_TYPE *errorLocus, 
								CRYPT_ERRTYPE_TYPE *errorType )
	{
	int algorithmType = 0, keyUsage;

	assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	/* Determine the possible algorithm usage type(s) */
	if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
		algorithmType |= ALGO_TYPE_CRYPT;
	if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
		algorithmType |= ALGO_TYPE_SIGN;
	if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
		algorithmType |= ALGO_TYPE_KEYAGREEMENT;

	/* Get the key usage flags for the given extended/Netscape usage type(s)
	   and algorithm type */
	keyUsage = getExtendedKeyUsageFlags( certInfoPtr->attributes,
										 algorithmType, errorLocus );
	keyUsage |= getNetscapeCertTypeFlags( certInfoPtr->attributes, 
										  algorithmType, errorLocus );
	if( cryptStatusError( keyUsage ) )
		{
		/* We only have to set the error type at this point since the error
		   locus was set when we got the key usage flags */
		*errorType = CRYPT_ERRTYPE_CONSTRAINT;
		return( CRYPT_ERROR_INVALID );
		}

	return( keyUsage );
	}

/****************************************************************************
*																			*
*								Check Key/Cert Usage						*
*																			*
****************************************************************************/

/* Check that a certificate/key is valid for a particular purpose.  This is 
   used both to check that contexts/certs are valid for key exchange/sig.
   generation/cert signing, and as a part of the chk_cert.c checking 
   process.  If used for the latter, the check flag CHECKKEY_FLAG_GENCHECK 
   is passed in, since a specific-usage check just checks for a specific
   usage for the key without necessarily checking that the usage makes 
   sense */

int checkKeyUsage( const CERT_INFO *certInfoPtr,
				   const int flags, const int specificUsage, 
				   const int complianceLevel, 
				   CRYPT_ATTRIBUTE_TYPE *errorLocus, 
				   CRYPT_ERRTYPE_TYPE *errorType )
	{
	ATTRIBUTE_LIST *attributeListPtr;
	const BOOLEAN isGeneralCheck = ( flags & CHECKKEY_FLAG_GENCHECK );
	BOOLEAN keyUsageCritical = 0, isCA = FALSE;
	const int trustedUsage = \
				( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
				  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN ) ? \
				certInfoPtr->cCertCert->trustedUsage : CRYPT_ERROR;
	int keyUsage, rawKeyUsage, extKeyUsage, rawExtKeyUsage, caKeyUsage;

	assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( ( ( flags & CHECKKEY_FLAG_CA ) && \
			  ( specificUsage & ( CRYPT_KEYUSAGE_KEYCERTSIGN | \
								  CRYPT_KEYUSAGE_CRLSIGN ) ) ) || \
			( !( flags & CHECKKEY_FLAG_CA ) && \
			  ( ( specificUsage & ( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
									CRYPT_KEYUSAGE_KEYENCIPHERMENT | \
									CRYPT_KEYUSAGE_KEYAGREEMENT ) ) || \
				( specificUsage == CRYPT_UNUSED ) ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	/* There is one universal case in which a key is regarded as invalid for
	   the requested use and that's when it's explicitly not trusted for the 
	   purpose.  Note that this check (in oblivious mode) differs slightly
	   from the later check (in reduced mode or higher) in that in oblivious
	   mode we ignore the cert's actual key usage and check only the 
	   requested against trusted usage */
	if( specificUsage != CRYPT_UNUSED && trustedUsage != CRYPT_ERROR && \
		!( trustedUsage & specificUsage ) )
		{
		/* The issuer is explicitly not trusted to perform the requested 
		   operation */
		setErrorValues( CRYPT_CERTINFO_TRUSTED_USAGE,
						CRYPT_ERRTYPE_ISSUERCONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	/* If we're running in oblivious mode, there's nothing else to check */
	if( complianceLevel < CRYPT_COMPLIANCELEVEL_REDUCED )
		return( CRYPT_OK );

	/* Obtain assorted cert information */
	attributeListPtr = findAttributeField( certInfoPtr->attributes, 
										   CRYPT_CERTINFO_CA, 
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL )
		isCA = attributeListPtr->intValue;
	extKeyUsage = getKeyUsageFromExtKeyUsage( certInfoPtr, errorLocus, 
											  errorType );
	if( cryptStatusError( extKeyUsage ) )
		return( extKeyUsage );

	/* If it's a v1 self-signed cert the CA status and key usage is 

⌨️ 快捷键说明

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