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

📄 chk_chn.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*					  Certificate Chain Checking Routines					*
*						Copyright Peter Gutmann 1996-2007					*
*																			*
****************************************************************************/

/* This module and chk_cert.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).  For
   simplicity we use the more compact form of RFC 2459 rather than the 18
   page long one from RFC 3280.

	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 require explicit policy state variable is less than or 
			equal to n, a policy identifier in the certificate must be in 
			the initial policy set.
*		(2) If the policy mapping state variable is less than or equal to n, 
			the policy identifier may not be mapped.
		(3) RFC 3280 addition: If the inhibitAnyPolicy state variable is 
			less than or equal to n, the anyPolicy policy is no longer 
			considered a match (this also extends into (e) and (g) below).

	(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:

	(f) Step (f) is missing in the original, it should probably be: Verify 
		that the current path length is less than the path length constraint.  
		If a path length constraint is present in the certificate, update it 
		as for policy constraints in (l).  RFC 3280 addition: If the 
		certificate is a PKIX path kludge certificate it doesn't count for 
		path length constraint purposes.

	(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:

		For any of { requireExplicitPolicy, inhibitPolicyMapping, 
		inhibitAnyPolicy }, if the constraint value is present and has value 
		r, the 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) 

	(m) If a key usage extension is marked critical, ensure that the 
		keyCertSign bit is set */

#if defined( INC_ALL )
  #include "cert.h"
#else
  #include "cert/cert.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Get certificate information for a certificate in the chain */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int getCertInfo( const CERT_INFO *certInfoPtr,
						INOUT_PTR CERT_INFO **certChainPtr, 
						IN_RANGE( -2, MAX_CHAINLENGTH ) const int certChainIndex )
	{
	assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isWritePtr( certChainPtr, sizeof( CERT_INFO * ) ) );

	REQUIRES( certChainIndex >= -2 && \
			  certChainIndex < certInfoPtr->cCertCert->chainEnd && \
			  certChainIndex < MAX_CHAINLENGTH );

	/* Clear return value */
	*certChainPtr = NULL;

	/* If it's an index into the certificate chain, return info for the 
	   certificate at that position */
	if( certChainIndex >= 0 && \
		certChainIndex < certInfoPtr->cCertCert->chainEnd )
		{
		return( krnlAcquireObject( certInfoPtr->cCertCert->chain[ certChainIndex ], 
								   OBJECT_TYPE_CERTIFICATE, 
								   ( void ** ) certChainPtr, 
								   CRYPT_ERROR_SIGNALLED ) );
		}

	/* The -1th certificate is the leaf itself */
	if( certChainIndex == -1 )
		{
		*certChainPtr = ( CERT_INFO * ) certInfoPtr;
		return( CRYPT_OK );
		}

	/* We've reached the end of the chain */
	*certChainPtr = NULL;
	return( CRYPT_ERROR_NOTFOUND );
	}

/* Find the trust anchor in a certificate chain.  The definition of a 
   "trusted certificate" is somewhat ambiguous and can have at least two 
   different interpretations:

	1. Trust the identified certificate in the chain and only verify from 
	   there on down.

	2. Trust the root of the chain that contains the identified certificate 
	   (for the purposes of verifying that particular chain only) and verify 
	   the whole chain.

   Situation 1 is useful where there's a requirement that things go up to an
   external CA somewhere but no-one particularly cares about (or trusts) the
   external CA.  This is probably the most common situation in general PKC 
   usage, in which the external CA requirement is more of an inconvenience
   than anything else.  In this case the end user can choose to trust the
   path at the point where it comes under their control (a local CA or 
   directly trusting the leaf certificates) without having to bother about 
   the external CA.

   Situation 2 is useful where there's a requirement to use the full PKI 
   model.  This can be enabled by having the user mark the root CA as
   trusted, although this means that all certificates issued by that CA also 
   have to be trusted, removing user control over certificate use.  This is 
   required by orthodox PKI theology, followed by all manner of hacks and
   kludges down the chain to limit what can actually be done with the 
   certificate(s).

   Est autem fides credere quod nondum vides; cuius fidei merces est videre 
   quod credis (St. Augustine) */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int findTrustAnchor( INOUT CERT_INFO *certInfoPtr, 
							OUT int *trustAnchorIndexPtr, 
							OUT_HANDLE_OPT CRYPT_CERTIFICATE *trustAnchorCertPtr )
	{
	CRYPT_CERTIFICATE iIssuerCert;
	CERT_CERT_INFO *certChainInfo = certInfoPtr->cCertCert;
	SELECTION_STATE savedState;
	int trustAnchorIndex, status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isWritePtr( trustAnchorIndexPtr, sizeof( int ) ) );
	assert( isWritePtr( trustAnchorCertPtr, sizeof( CRYPT_CERTIFICATE ) ) );

	/* Clear return value */
	*trustAnchorIndexPtr = CRYPT_ERROR;
	*trustAnchorCertPtr = CRYPT_ERROR;

	/* If the leaf certificate is implicitly trusted, exit.  To perform this 
	   check we have to explicitly select the leaf certificate by making it 
	   appear that the certificate chain is empty.  This is required in 
	   order to ensure that we check the leaf rather than the 
	   currently-selected certificate */
	saveSelectionState( savedState, certInfoPtr );
	certChainInfo->chainPos = CRYPT_ERROR;
	status = krnlSendMessage( certInfoPtr->ownerHandle, 
					IMESSAGE_USER_TRUSTMGMT, &certInfoPtr->objectHandle, 
					MESSAGE_TRUSTMGMT_CHECK );
	restoreSelectionState( savedState, certInfoPtr );
	if( cryptStatusOK( status ) )
		{
		/* Indicate that the leaf is trusted and there's nothing further to 
		   do */
		return( OK_SPECIAL );
		}

	/* Walk up the chain looking for a trusted certificate.  Note that the 
	   evaluated trust anchor certificate position is one past the current 
	   certificate position since we're looking for the issuer of the 
	   current certificate at position n, which will be located at position 
	   n+1.  This means that it may end up pointing past the end of the 
	   chain if the trust anchor is present in the trust database but not in 
	   the chain */
	iIssuerCert = certInfoPtr->objectHandle;
	status = krnlSendMessage( certInfoPtr->ownerHandle, 
							  IMESSAGE_USER_TRUSTMGMT, &iIssuerCert, 
							  MESSAGE_TRUSTMGMT_GETISSUER );
	for( trustAnchorIndex = 0;
		 cryptStatusError( status ) && \
			trustAnchorIndex < certChainInfo->chainEnd && \
			trustAnchorIndex < MAX_CHAINLENGTH ; )
		{
		iIssuerCert = certChainInfo->chain[ trustAnchorIndex++ ];
		status = krnlSendMessage( certInfoPtr->ownerHandle, 
								  IMESSAGE_USER_TRUSTMGMT, &iIssuerCert, 
								  MESSAGE_TRUSTMGMT_GETISSUER );
		}
	ENSURES( trustAnchorIndex < MAX_CHAINLENGTH );
	if( cryptStatusError( status ) || \
		trustAnchorIndex > certChainInfo->chainEnd )
		return( CRYPT_ERROR_NOTFOUND );
	*trustAnchorCertPtr = iIssuerCert;
	*trustAnchorIndexPtr = trustAnchorIndex;

	/* If there are more certificates in the chain beyond the one that we 
	   stopped at, check to see whether the next certificate is the same as 
	   the trust anchor.  If it is we use the copy of the certificate in 
	   the chain rather than the external one from the trust database */
	if( trustAnchorIndex < certChainInfo->chainEnd - 1 )
		{
		status = krnlSendMessage( certChainInfo->chain[ trustAnchorIndex ],
								  IMESSAGE_COMPARE, &iIssuerCert, 
								  MESSAGE_COMPARE_CERTOBJ );
		if( cryptStatusOK( status ) )
			*trustAnchorCertPtr = certChainInfo->chain[ trustAnchorIndex ];
		}
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Verify a Certificate Chain						*
*																			*
****************************************************************************/

/* Check constraints along a certificate chain in certInfoPtr from 
   startCertIndex on down, checked if complianceLevel >= 
   CRYPT_COMPLIANCELEVEL_PKIX_FULL.  There are three types of constraints 
   that can cover multiple certificates: path constraints, name constraints, 
   and policy constraints.

⌨️ 快捷键说明

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