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

📄 certchn.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
		}

	/* If we're at the 0-th cert we don't have to perform any constraint
	   checking since the check for (leaf, [0]) is performed by checkCert().
	   If it's a self-signed cert, the constraints don't apply to itself (a 
	   Smith and Wesson beats four aces) */
	if( certIndex < 0 || ( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
		return( CRYPT_OK );

	/* If there aren't any name or policy constraint present, we're done */
	if( !checkAttributePresent( issuerCertInfoPtr->attributes, \
								CRYPT_CERTINFO_NAMECONSTRAINTS ) && \
		!checkAttributePresent( issuerCertInfoPtr->attributes, \
								CRYPT_CERTINFO_POLICYCONSTRAINTS ) )
		return( CRYPT_OK );
	
	/* Check that the name/policy constraints are satisfied for all certs 
	   below this one */
	nameAttributeListPtr = findAttribute( issuerCertInfoPtr->attributes, \
										  CRYPT_CERTINFO_NAMECONSTRAINTS, FALSE );
	policyAttributeListPtr = findAttribute( issuerCertInfoPtr->attributes, \
											CRYPT_CERTINFO_POLICYCONSTRAINTS, FALSE );
	hasExcludedSubtrees = findAttributeField( nameAttributeListPtr, \
											  CRYPT_CERTINFO_EXCLUDEDSUBTREES, 
											  CRYPT_ATTRIBUTE_NONE ) != NULL;
	hasPermittedSubtrees = findAttributeField( nameAttributeListPtr, \
											   CRYPT_CERTINFO_PERMITTEDSUBTREES, 
											   CRYPT_ATTRIBUTE_NONE ) != NULL;
	hasPolicy = findAttributeField( policyAttributeListPtr, \
									CRYPT_CERTINFO_CERTPOLICYID, 
								    CRYPT_ATTRIBUTE_NONE ) != NULL;

	/* Check whether there's a requireExplicitPolicy attribute.  The 
	   handling of this is very ambiguous since other parts of the path 
	   validation requirements stipulate that policies should be checked 
	   anyway (even if requireExplicitPolicy isn't set), and no-one knows 
	   what to do if multiple requireExplicitPolicy settings are present in 
	   a chain (for example due to reparenting).  This implementation 
	   handles it by returning an error if a second requireExplicitPolicy
	   attribute that contradicts the first one is encountered */
	attributeListPtr = findAttributeField( policyAttributeListPtr,
										   CRYPT_CERTINFO_REQUIREEXPLICITPOLICY, 
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL )
		{
		requireExplicitPolicyLevel = ( int ) attributeListPtr->intValue;
		requireExplicitPolicyPresent = TRUE;
		}

	/* Walk down the chain checking each cert against the issuer */
	do
		{
		CERT_INFO *subjectCertInfoPtr;

		/* Get the next cert in the chain */
		certIndex--;
		status = getNextCert( certInfoPtr, &subjectCertInfoPtr, certIndex );
		if( status == OK_SPECIAL )
			/* We've reached the end of the chain, exit */
			break;

		/* If there's a second policy constraint present further down the 
		   chain, make sure that it doesn't contradict the current one */
		attributeListPtr = findAttributeField( certInfoPtr->attributes,
											   CRYPT_CERTINFO_REQUIREEXPLICITPOLICY, 
											   CRYPT_ATTRIBUTE_NONE );
		if( attributeListPtr != NULL && requireExplicitPolicyPresent && \
			attributeListPtr->intValue != requireExplicitPolicyLevel )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_REQUIREEXPLICITPOLICY,
						  CRYPT_ERRTYPE_ISSUERCONSTRAINT );
			status = CRYPT_ERROR_INVALID;
			break;
			}

		/* If there's a requireExplicitPolicy skip count, decrement it for 
		   each cert */
		if( requireExplicitPolicyLevel > CRYPT_ERROR )
			requireExplicitPolicyLevel--;

		/* Check that the current cert obeys the constraints set by the 
		   issuer */
		if( hasExcludedSubtrees && \
			cryptStatusError( checkNameConstraints( subjectCertInfoPtr,
										nameAttributeListPtr, TRUE,
										&subjectCertInfoPtr->errorLocus, 
										&subjectCertInfoPtr->errorType ) ) );
			status = CRYPT_ERROR_INVALID;
		if( hasPermittedSubtrees && \
			cryptStatusError( checkNameConstraints( subjectCertInfoPtr,
										nameAttributeListPtr, FALSE,
										&subjectCertInfoPtr->errorLocus, 
										&subjectCertInfoPtr->errorType ) ) );
			status = CRYPT_ERROR_INVALID;
		if( hasPolicy && requireExplicitPolicyLevel == CRYPT_ERROR && \
			cryptStatusError( checkPolicyConstraints( subjectCertInfoPtr,
										policyAttributeListPtr,
										&subjectCertInfoPtr->errorLocus, 
										&subjectCertInfoPtr->errorType ) ) );
			status = CRYPT_ERROR_INVALID;
		krnlReleaseObject( subjectCertInfoPtr->objectHandle );
		}
	while( cryptStatusOK( status ) );
	if( status == CRYPT_OK || status == OK_SPECIAL )
		return( CRYPT_OK );

	/* Remember which cert in the chain caused the problem */
	*subjectCertIndex = certIndex;
	return( status );
	}

/* Walk down a chain checking each certificate */

static int checkLeafCertTrust( CERT_INFO *certInfoPtr, 
							   CRYPT_CERTIFICATE *iIssuerCert )
	{
	SELECTION_STATE savedState;
	int status;

	/* Clear return value */
	*iIssuerCert = CRYPT_ERROR;

	/* Explicitly select the leaf cert by making it appear that the cert 
	   chain is empty.  This is required in order to ensure that we check 
	   the leaf rather than the currently-selected cert */
	saveSelectionState( savedState, certInfoPtr );
	certInfoPtr->certChainPos = CRYPT_ERROR;

	/* If the leaf cert is implicitly trusted, there's nothing to do */
	status = krnlSendMessage( certInfoPtr->ownerHandle, IMESSAGE_SETATTRIBUTE,
							  &certInfoPtr->objectHandle, 
							  CRYPT_IATTRIBUTE_CERT_CHECKTRUST );
	if( cryptStatusOK( status ) )
		status = OK_SPECIAL;
	else
		{
		/* If the leaf cert's issuer is implicitly trusted, we only need to 
		   check the signature on the leaf cert */
		*iIssuerCert = certInfoPtr->objectHandle;
		status = krnlSendMessage( certInfoPtr->ownerHandle, 
								  IMESSAGE_SETATTRIBUTE, iIssuerCert, 
								  CRYPT_IATTRIBUTE_CERT_TRUSTEDISSUER );
		}

	/* Restore the cert chain info */
	restoreSelectionState( savedState, certInfoPtr );

	return( status );
	}

int checkCertChain( CERT_INFO *certInfoPtr )
	{
	CRYPT_CERTIFICATE iIssuerCert;
	CERT_INFO *issuerCertInfoPtr = certInfoPtr, *subjectCertInfoPtr;
	BOOLEAN isTrusted = TRUE;
	int certIndex = certInfoPtr->certChainEnd - 1, complianceLevel, i, status;

	assert( isWritePtr( certInfoPtr, CERT_INFO ) );

	krnlSendMessage( certInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
					 &complianceLevel, CRYPT_OPTION_CERT_COMPLIANCELEVEL );

	/* Check whether the leaf cert is either implicitly trusted or signed by 
	   a trusted cert */
	status = checkLeafCertTrust( certInfoPtr, &iIssuerCert );
	if( status == OK_SPECIAL )
		/* The leaf is implicitly trusted, there's nothing more to do */
		return( CRYPT_OK );
	if( cryptStatusOK( status ) )
		/* The leaf is signed by a trusted cert, no need to check the cert 
		   chain */
		certIndex = CRYPT_ERROR;
	else
		{
		/* Walk up the chain from the leaf cert's issuer to the root checking
		   for an implicitly trusted cert */
		for( i = 0; i <= certIndex; i++ )
			{
			status = krnlGetObject( certInfoPtr->certChain[ i ], 
									OBJECT_TYPE_CERTIFICATE, 
									( void ** ) &issuerCertInfoPtr, 
									CRYPT_ERROR_SIGNALLED );
			if( cryptStatusError( status ) )
				break;
			iIssuerCert = issuerCertInfoPtr->objectHandle;
			status = krnlSendMessage( certInfoPtr->ownerHandle, 
									  IMESSAGE_SETATTRIBUTE, &iIssuerCert, 
									  CRYPT_IATTRIBUTE_CERT_TRUSTEDISSUER );
			if( cryptStatusOK( status ) )
				break;
			if( i != certIndex )
				krnlReleaseObject( issuerCertInfoPtr->objectHandle );
			}
		certIndex = i;	/* Remember how far we got */

		/* If we didn't end up at an implicitly trusted cert, check whether
		   we should implicitly trust a self-signed root */
		if( cryptStatusError( status ) )
			{
			/* We didn't end up at a trusted key, either there's a missing 
			   link in the chain (CRYPT_ERROR_STUART) and it was truncated 
			   before we got to a trusted cert, or it goes to a root cert 
			   but it isn't trusted */
			certInfoPtr->certChainPos = certInfoPtr->certChainEnd - 1;
			if( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED )
				{
				/* We got a root cert but it's not trusted */
				setErrorInfo( issuerCertInfoPtr, CRYPT_CERTINFO_TRUSTED_IMPLICIT,
							  CRYPT_ERRTYPE_ATTR_ABSENT );
				}
			else
				/* There's a missing link in the chain and it stops at this 
				   cert */
				setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
							  CRYPT_ERRTYPE_ATTR_ABSENT );
			krnlReleaseObject( issuerCertInfoPtr->objectHandle );

			return( CRYPT_ERROR_INVALID );
			}
		}

	/* Walk down the chain from the trusted cert checking each link in turn */
	subjectCertInfoPtr = ( CERT_INFO * ) issuerCertInfoPtr;
	do
		{
		CRYPT_CONTEXT iPubkeyContext = iIssuerCert;

		/* If the issuing cert for this one isn't implicitly trusted, check
		   the chaining from issuer to subject */
		if( !isTrusted )
			{
			iPubkeyContext = issuerCertInfoPtr->iPubkeyContext;
			status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr,
								TRUE, &subjectCertInfoPtr->errorLocus, 
								&subjectCertInfoPtr->errorType);
			if( cryptStatusOK( status ) )
				subjectCertInfoPtr->maxCheckLevel = complianceLevel;
			}
		isTrusted = FALSE;

		/* Check the signature on the subject cert unless it's a data-only
		   cert for which there isn't a context present.  This is OK since
		   the only time we can have a data-only chain is when we're reading
		   from an (implicitly trusted) private key store */
		if( cryptStatusOK( status ) && !cryptStatusError( iPubkeyContext ) )
			status = checkX509signature( subjectCertInfoPtr->certificate, 
										 subjectCertInfoPtr->certificateSize,
										 NULL, NULL, iPubkeyContext, 
										 CRYPT_UNUSED );

		/* Check any constraints that the issuer cert may place on the rest 
		   of the chain */
		if( cryptStatusOK( status ) && \
			complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_FULL && \
			issuerCertInfoPtr != subjectCertInfoPtr )
			status = checkConstraints( certInfoPtr, issuerCertInfoPtr,
									   &certIndex );

		/* Move on to the next cert */
		if( issuerCertInfoPtr != subjectCertInfoPtr )
			krnlReleaseObject( issuerCertInfoPtr->objectHandle );
		issuerCertInfoPtr = subjectCertInfoPtr;
		certIndex--;
		}
	while( cryptStatusOK( status ) && \
		   ( status = getNextCert( certInfoPtr, &subjectCertInfoPtr,
								   certIndex ) ) == CRYPT_OK );
	if( status != OK_SPECIAL )
		{
		/* We stopped before we processed all the certs in the chain, if
		   the last cert that we processed wasn't the leaf, unlock it and
		   select the one that caused the problem */
		if( issuerCertInfoPtr != certInfoPtr )
			krnlReleaseObject( issuerCertInfoPtr->objectHandle );
		certInfoPtr->certChainPos = certIndex + 1;
		}
	else
		/* We successfully reached the end of the chain */
		status = CRYPT_OK;

	return( status );
	}

/****************************************************************************
*																			*
*						Read Certificate-bagging Records					*
*																			*
****************************************************************************/

/* Read a collection of certs in a cert chain into a cert object */

static int buildCertChain( CRYPT_CERTIFICATE *iLeafCert, 
						   CRYPT_CERTIFICATE *iCertChain, int certChainEnd,
						   const CRYPT_KEYID_TYPE keyIDtype,
						   const void *keyID, const int keyIDlength )
	{
	CERTCHAIN_INFO certChainInfo[ MAX_CHAINLENGTH ];
	CERT_INFO *certChainPtr;
	CHAINING_INFO chainingInfo;
	int leafNodePos, selfSigned, status;

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

	/* We've now got a collection of certs in unknown order (although in most
	   cases the first cert is the leaf).  Extract the chaining info and
	   search the chain for the leaf node */
	status = buildCertChainInfo( certChainInfo, iCertChain, certChainEnd );
	if( cryptStatusError( status ) )
		{
		freeCertChain( iCertChain, certChainEnd );
		return( status );
		}
	if( keyID != NULL )
		leafNodePos = findIdentifiedLeafNode( certChainInfo, certChainEnd,
											  keyIDtype, keyID, keyIDlength );
	else
		leafNodePos = findLeafNode( certChainInfo, certChainEnd );
	if( cryptStatusError( leafNodePos ) )
		return( leafNodePos );

	/* Now that we have the leaf node, clear its entry in the chain to make
	   sure that it isn't used for further processing, order the remaining 
	   certs up to the root, and discard any unneeded certs */
	*iLeafCert = iCertChain[ leafNodePos ];
	getIssuerChainingInfo( &chainingInfo, &certChainInfo[ leafNodePos ] );
	memset( &certChainInfo[ leafNodePos ], 0, sizeof( CERTCHAIN_INFO ) );
	status = sortCertChain( iCertChain, certChainInfo, certChainEnd,
							CRYPT_UNUSED, &chainingInfo );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( *iLeafCert, IMESSAGE_DECREFCOUNT );
		freeCertChain( iCertChain, certChainEnd );
		return( status );
		}
	certChainEnd = status;
	if( certChainEnd <= 0 )
		/* There's only one cert in the chain, either due to the chain 
		   containing only a single cert or due to all other certs being 
		   discarded, leave it as a standalone cert rather than turning it 
		   into a chain */
		return( CRYPT_OK );

	/* Finally, we've got the leaf cert and a chain up to the root.  Make the
	   leaf a cert-chain type and copy in the chain */
	status = krnlGetObject( *iLeafCert, OBJECT_TYPE_CERTIFICATE, 
							( void ** ) &certChainPtr, 
							CRYPT_ERROR_SIGNALLED );
	if( cryptStatusError( status ) )
		return( status );
	memcpy( certChainPtr->certChain, iCertChain,
			certChainEnd * sizeof( CRYPT_CERTIFICATE ) );
	certChainPtr->certChainEnd = certChainEnd;
	certChainPtr->type = CRYPT_CERTTYPE_CERTCHAIN;

	/* If the root is self-signed, the entire chain counts as self-
	   signed */
	status = krnlSendMessage( certChainPtr->certChain[ certChainEnd - 1 ], 
							  IMESSAGE_GETATTRIBUTE, &selfSigned,

⌨️ 快捷键说明

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