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

📄 certchn.c

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

/* This module and certchk.c implement the following PKIX checks (* =
   unhandled, see the code comments.  Currently only policy mapping is
   unhandled, this is optional in PKIX and given the nature of the
   kitchenSink extension no-one really knows how to apply it anyway):

	General:

	(a) Verify the basic certificate information:
		(1) The certificate signature is valid.
		(2a) The certificate has not expired.
		(2b) If present, the private key usage period is satisfied.
		(3) The certificate has not been revoked.
		(4a) The subject and issuer name chains correctly.
		(4b) If present, the subjectAltName and issuerAltName chains
			 correctly.

	NameConstraints:

	(b) Verify that the subject name or critical subjectAltName is consistent
		with the constrained subtrees.

	(c) Verify that the subject name or critical subjectAltName is consistent
		with the excluded subtrees.

	Policy Constraints:

	(d) Verify that policy info.is consistent with the initial policy set:
		(1) If the explicit policy state variable is less than or equal to n,
			a policy identifier in the certificate must be in initial policy
			set.
*		(2) If the policy mapping variable is less than or equal to n, the
			policy identifier may not be mapped.

	(e) Verify that policy info.is consistent with the acceptable policy set:
		(1) If the policies extension is marked critical, the policies
			extension must lie within the acceptable policy set.
		(2) The acceptable policy set is assigned the resulting intersection
			as its new value.

	(g) Verify that the intersection of the acceptable policy set and the
		initial policy set is non-null (this is covered by chaining of e(1)).

	Other Constraints:

	(h) Recognize and process any other critical extension present in the
		certificate.

	(i) Verify that the certificate is a CA certificate.

	Update of state:

	(j) If permittedSubtrees is present in the certificate, set the
		constrained subtrees state variable to the intersection of its
		previous value and the value indicated in the extension field.

	(k) If excludedSubtrees is present in the certificate, set the excluded
		subtrees state variable to the union of its previous value and the
		value indicated in the extension field.

	(l) If a policy constraints extension is included in the certificate,
		modify the explicit policy and policy mapping state variables as
		follows:
		(1) If requireExplicitPolicy is present and has value r, the explicit
			policy state variable is set to the minimum of (a) its current
			value and (b) the sum of r and n (the current certificate in the
			sequence).
*		(2) If inhibitPolicyMapping is present and has value q, the policy
			mapping state variable is set to the minimum of (a) its current
			value and (b) the sum of q and n (the current certificate in the
			sequence) */

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

/* When matching by subjectKeyIdentifier, we don't use values less than 40
   bits because some CAs use monotonically increasing sequence numbers for 
   the sKID, which can clash with the same values when used by other CAs */

#define MIN_SKID_SIZE	5

/* A structure for storing pointers to parent and child (issuer and subject)
   names, key identifiers, and serial numbers (for finding a cert by 
   issuerAndSerialNumber), and one for storing pointers to chaining info */

typedef struct {
	const void *issuerDN, *subjectDN;
	int issuerDNsize, subjectDNsize;
	const void *subjectKeyIdentifier, *issuerKeyIdentifier;
	int subjectKeyIDsize, issuerKeyIDsize;
	const void *serialNumber;
	int serialNumberSize;
	} CERTCHAIN_INFO;

typedef struct {
	const void *DN, *keyIdentifier;
	int DNsize, keyIDsize;
	} CHAINING_INFO;

/* Prototypes for functions in cryptcrt.c */

int compareSerialNumber( const void *canonSerialNumber, 
						 const int canonSerialNumberLength,
						 const void *serialNumber, 
						 const int serialNumberLength );

/* Prototypes for functions in lib_sign.c */

int checkX509signature( const void *signedObject, const int signedObjectLength,
						void **object, int *objectLength, 
						const CRYPT_CONTEXT sigCheckContext,
						const int formatInfo );

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

/* Copy subject or issuer chaining values from the chaining info */

static void getSubjectChainingInfo( CHAINING_INFO *chainingInfo,
									const CERTCHAIN_INFO *certChainInfo )
	{
	assert( isWritePtr( chainingInfo, CHAINING_INFO ) );
	assert( isReadPtr( certChainInfo, CERTCHAIN_INFO ) );

	chainingInfo->DN = certChainInfo->subjectDN;
	chainingInfo->DNsize = certChainInfo->subjectDNsize;
	chainingInfo->keyIdentifier = certChainInfo->subjectKeyIdentifier;
	chainingInfo->keyIDsize = certChainInfo->subjectKeyIDsize;
	}

static void getIssuerChainingInfo( CHAINING_INFO *chainingInfo,
								   const CERTCHAIN_INFO *certChainInfo )
	{
	assert( isWritePtr( chainingInfo, CHAINING_INFO ) );
	assert( isReadPtr( certChainInfo, CERTCHAIN_INFO ) );

	chainingInfo->DN = certChainInfo->issuerDN;
	chainingInfo->DNsize = certChainInfo->issuerDNsize;
	chainingInfo->keyIdentifier = certChainInfo->issuerKeyIdentifier;
	chainingInfo->keyIDsize = certChainInfo->issuerKeyIDsize;
	}

/* Determine whether a given cert is the subject or issuer for the requested 
   cert based on the chaining info.  We chain by issuer DN if possible, but
   if that fails we use the keyID.  This is somewhat dodgy since it can lead 
   to the situation where a certificate supposedly issued by Verisign Class 1 
   Public Primary Certification Authority is actually issued by Honest Joe's 
   Used Cars, but the standard requires this as a fallback.  There are 
   actually two different interpretations of chaining by keyID, the first
   (which we use here) says that the keyID is a non-DN identifier that can
   survive operations such as cross-certification and re-parenting, so that
   if a straight chain by DN fails then a chain by keyID is possible as a
   fallback option.  The second interpretation is that the keyID is a
   disambiguator if multiple paths in a chain-by-DN scenario are present in
   a spaghetti PKI.  Since the latter is rather unlikely to occur in a 
   standard PKCS #7/SSL cert chain (half the implementations around wouldn't
   be able to assemble the chain any more), we use the former 
   interpretation */

static BOOLEAN isSubject( const CHAINING_INFO *chainingInfo,
						  const CERTCHAIN_INFO *certChainInfo )
	{
	assert( isReadPtr( chainingInfo, CHAINING_INFO ) );
	assert( isReadPtr( certChainInfo, CERTCHAIN_INFO ) );

	/* In the simplest case we chain by name.  This works for almost all
	   certificates */
	if( chainingInfo->DNsize > 0 && \
		chainingInfo->DNsize == certChainInfo->subjectDNsize && \
		!memcmp( chainingInfo->DN, certChainInfo->subjectDN,
				 certChainInfo->subjectDNsize ) )
		return( TRUE );

	/* If that fails we chain by keyID */
	if( chainingInfo->keyIDsize > MIN_SKID_SIZE && \
		chainingInfo->keyIDsize == certChainInfo->subjectKeyIDsize && \
		!memcmp( chainingInfo->keyIdentifier, 
				 certChainInfo->subjectKeyIdentifier,
				 certChainInfo->subjectKeyIDsize ) )
		return( TRUE );

	return( FALSE );
	}

static BOOLEAN isIssuer( const CHAINING_INFO *chainingInfo,
						 const CERTCHAIN_INFO *certChainInfo )
	{
	assert( isReadPtr( chainingInfo, CHAINING_INFO ) );
	assert( isReadPtr( certChainInfo, CERTCHAIN_INFO ) );

	/* In the simplest case we chain by name.  This works for almost all
	   certificates */
	if( chainingInfo->DNsize > 0 && \
		chainingInfo->DNsize == certChainInfo->issuerDNsize && \
		!memcmp( chainingInfo->DN, certChainInfo->issuerDN,
				 certChainInfo->issuerDNsize ) )
		return( TRUE );

	/* If that fails we chain by keyID */
	if( chainingInfo->keyIDsize > MIN_SKID_SIZE && \
		chainingInfo->keyIDsize == certChainInfo->issuerKeyIDsize && \
		!memcmp( chainingInfo->keyIdentifier, 
				 certChainInfo->issuerKeyIdentifier,
				 certChainInfo->issuerKeyIDsize ) )
		return( TRUE );

	return( FALSE );
	}

/* Get the location and size of certificate attribute data required for
   chaining */

static void *getChainingAttribute( CERT_INFO *certInfoPtr,
								   const CRYPT_ATTRIBUTE_TYPE attributeType,
								   int *attributeLength )
	{
	ATTRIBUTE_LIST *attributePtr;

	assert( isWritePtr( certInfoPtr, CERT_INFO ) );

	/* Find the requested attribute and return a pointer to it */
	attributePtr = findAttributeField( certInfoPtr->attributes,
									   attributeType, CRYPT_ATTRIBUTE_NONE );
	if( attributePtr == NULL )
		{
		*attributeLength = 0;
		return( NULL );
		}
	*attributeLength = attributePtr->valueLength;
	return( attributePtr->value );
	}

/* Free a cert chain */

static void freeCertChain( CRYPT_CERTIFICATE *iCertChain,
						   const int certChainSize )
	{
	int i;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isWritePtrEx( iCertChain, CRYPT_CERTIFICATE, certChainSize ) );

	for( i = 0; i < certChainSize; i++ )
		{
		krnlSendNotifier( iCertChain[ i ], IMESSAGE_DESTROY );
		iCertChain[ i ] = CRYPT_ERROR;
		}
	}

/* Build up the parent/child pointers for a cert chain */

static int buildCertChainInfo( CERTCHAIN_INFO *certChainInfo,
							   const CRYPT_CERTIFICATE *iCertChain,
							   const int certChainSize )
	{
	int i;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isWritePtrEx( certChainInfo, CERTCHAIN_INFO, certChainSize ) );
	assert( isReadPtrEx( iCertChain, CRYPT_CERTIFICATE, certChainSize ) );

	/* Extract the subject and issuer DNs and key identifiers from each
	   certificate.  Maintaining an external pointer into the internal
	   structure is safe since the objects are reference-counted and won't be
	   destroyed until the encapsulating cert is destroyed */
	for( i = 0; i < certChainSize; i++ )
		{
		CERT_INFO *certChainPtr;
		int status;

		status = krnlGetObject( iCertChain[ i ], OBJECT_TYPE_CERTIFICATE, 
								( void ** ) &certChainPtr, 
								CRYPT_ERROR_SIGNALLED );
		if( cryptStatusError( status ) )
			return( status );
		certChainInfo[ i ].subjectDN = certChainPtr->subjectDNptr;
		certChainInfo[ i ].issuerDN = certChainPtr->issuerDNptr;
		certChainInfo[ i ].subjectDNsize = certChainPtr->subjectDNsize;
		certChainInfo[ i ].issuerDNsize = certChainPtr->issuerDNsize;
		certChainInfo[ i ].subjectKeyIdentifier = \
			getChainingAttribute( certChainPtr, CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
								  &certChainInfo[ i ].subjectKeyIDsize );
		certChainInfo[ i ].issuerKeyIdentifier = \
			getChainingAttribute( certChainPtr, CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER,
								  &certChainInfo[ i ].issuerKeyIDsize );
		certChainInfo[ i ].serialNumber = certChainPtr->serialNumber;
		certChainInfo[ i ].serialNumberSize = certChainPtr->serialNumberLength;
		krnlReleaseObject( certChainPtr->objectHandle );
		}

	return( CRYPT_OK );
	}

/* Find the leaf node in a (possibly unordered) cert chain by walking down
   the chain as far as possible.  The strategy we use is to pick an initial
   cert (which is usually the leaf cert anyway) and keep looking for certs 
   it (or its successors) have issued until we reach the end of the chain.
   Returns the position of the leaf node in the chain */

static int findLeafNode( const CERTCHAIN_INFO *certChainInfo,
						 const int certChainSize )
	{
	CHAINING_INFO chainingInfo;
	BOOLEAN certUsed[ MAX_CHAINLENGTH ];
	int lastCertPos, i;

	assert( certChainSize > 0 && certChainSize < MAX_CHAINLENGTH );
	assert( isReadPtrEx( certChainInfo, CERTCHAIN_INFO, certChainSize ) );

	/* We start our search at the first cert, which is often the leaf cert
	   anyway */
	memset( certUsed, 0, MAX_CHAINLENGTH * sizeof( BOOLEAN ) );
	getSubjectChainingInfo( &chainingInfo, &certChainInfo[ 0 ] );
	certUsed[ 0 ] = TRUE;
	lastCertPos = 0;

	/* Walk down the chain from the currently selected cert checking for
	   certs issued by it, until we can't go any further */
	do
		{
		/* Try and find a cert issued by the current cert */
		for( i = 0; i < certChainSize; i++ )
			if( !certUsed[ i ] && \
				isIssuer( &chainingInfo, &certChainInfo[ i ] ) )
				{
				/* There's another cert below the current one in the chain, 
				   mark the current one as used and move on to the next
				   one */
				getSubjectChainingInfo( &chainingInfo, &certChainInfo[ i ] );
				certUsed[ i ] = TRUE;
				lastCertPos = i;
				break;
				}
		}
	while( i != certChainSize );

	return( lastCertPos );
	}

/* Find a leaf node as identified by issuerAndSerialNumber.  Returns the 
   position of the leaf node in the chain */

⌨️ 快捷键说明

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