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

📄 chk_cert.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:

/* Check name constraints placed by an issuer, checked if complianceLevel >=
   CRYPT_COMPLIANCELEVEL_PKIX_FULL */

int checkNameConstraints( const CERT_INFO *subjectCertInfoPtr,
						  const ATTRIBUTE_LIST *issuerAttributes,
						  const BOOLEAN isExcluded,
						  CRYPT_ATTRIBUTE_TYPE *errorLocus, 
						  CRYPT_ERRTYPE_TYPE *errorType )
	{
	const ATTRIBUTE_LIST *subjectAttributes = subjectCertInfoPtr->attributes;
	const CRYPT_ATTRIBUTE_TYPE constraintType = isExcluded ? \
		CRYPT_CERTINFO_EXCLUDEDSUBTREES : CRYPT_CERTINFO_PERMITTEDSUBTREES;
	ATTRIBUTE_LIST *attributeListPtr;
	BOOLEAN isMatch = FALSE;

	assert( isReadPtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isReadPtr( issuerAttributes, sizeof( ATTRIBUTE_LIST ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	/* If this is a PKIX path-kludge CA cert, the name constraints don't 
	   apply to it (PKIX section 4.2.1.11).  This is required in order to 
	   allow extra certs to be kludged into the path without violating the 
	   constraint.  For example with the chain:

		Issuer	Subject		Constraint
		------	-------		----------
		Root	CA			permitted = "EE"
		CA'		CA'
		CA		EE

	   the kludge cert CA' must be excluded from name constraint 
	   restrictions in order for the path to be valid.  Obviously this is 
	   only necessary for constraints set by the immediate parent, but PKIX 
	   says it's for constraints set by all certs in the chain (!!), thus 
	   making the pathkludge cert exempt from any name constraints, not just 
	   the one that would cause problems */
	if( isPathKludge( subjectCertInfoPtr ) )
		return( CRYPT_OK );

	/* Check the subject DN if constraints exist.  If it's an excluded 
	   subtree then none can match, if it's a permitted subtree then at 
	   least one must match */
	attributeListPtr = findAttributeField( issuerAttributes, constraintType, 
										   CRYPT_CERTINFO_DIRECTORYNAME );
	if( attributeListPtr != NULL )
		{
		while( attributeListPtr != NULL && !isMatch )
			{
			isMatch = compareDN( subjectCertInfoPtr->subjectName,
								 attributeListPtr->value, TRUE );
			attributeListPtr = findNextFieldInstance( attributeListPtr );
			}
		if( isExcluded == isMatch )
			{
			setErrorValues( CRYPT_CERTINFO_SUBJECTNAME, 
							CRYPT_ERRTYPE_CONSTRAINT );
			return( CRYPT_ERROR_INVALID );
			}
		}

	/* DN constraints apply to both the main subject DN and any other DNs 
	   that may be present as subject altNames, so after we've checked the 
	   main DN we check any altName DNs as well */
	if( !checkAltnameConstraints( subjectAttributes, issuerAttributes,
								  CRYPT_CERTINFO_DIRECTORYNAME, isExcluded ) )
		{
		setErrorValues( CRYPT_CERTINFO_SUBJECTALTNAME, 
						CRYPT_ERRTYPE_CONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	/* Compare the Internet-related names if constraints exist.  We don't
	   have to check for the special case of an email address in the DN 
	   since the cert import code transparently maps this to the 
	   appropriate altName component */
	if( !checkAltnameConstraints( subjectAttributes, issuerAttributes,
								  CRYPT_CERTINFO_RFC822NAME, isExcluded ) || \
		!checkAltnameConstraints( subjectAttributes, issuerAttributes,
								  CRYPT_CERTINFO_DNSNAME, isExcluded ) || \
		!checkAltnameConstraints( subjectAttributes, issuerAttributes,
								  CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, 
								  isExcluded ) )
		{
		setErrorValues( CRYPT_CERTINFO_SUBJECTALTNAME, 
						CRYPT_ERRTYPE_CONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	return( CRYPT_OK );
	}

/* Check policy constraints placed by an issuer, checked if complianceLevel 
   >= CRYPT_COMPLIANCELEVEL_PKIX_FULL */

int checkPolicyConstraints( const CERT_INFO *subjectCertInfoPtr,
							const ATTRIBUTE_LIST *issuerAttributes,
							const POLICY_TYPE policyType,
							CRYPT_ATTRIBUTE_TYPE *errorLocus, 
							CRYPT_ERRTYPE_TYPE *errorType )
	{
	const ATTRIBUTE_LIST *attributeListPtr = \
					findAttributeField( issuerAttributes, 
										CRYPT_CERTINFO_CERTPOLICYID, 
										CRYPT_ATTRIBUTE_NONE );
	const ATTRIBUTE_LIST *constrainedAttributeListPtr = \
					findAttributeField( subjectCertInfoPtr->attributes, 
										CRYPT_CERTINFO_CERTPOLICYID, 
										CRYPT_ATTRIBUTE_NONE );
	ATTRIBUTE_LIST *attributeCursor;
	BOOLEAN subjectHasPolicy, issuerHasPolicy;
	BOOLEAN subjectHasAnyPolicy, issuerHasAnyPolicy;

	assert( isReadPtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isReadPtr( issuerAttributes, sizeof( ATTRIBUTE_LIST ) ) );
	assert( policyType >= POLICY_NONE && policyType < POLICY_LAST );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	/* If there's a policy mapping present, neither the issuer nor subject
	   domain policies can be the wildcard anyPolicy (PKIX section 
	   4.2.1.6) */
	if( containsAnyPolicy( issuerAttributes, 
						   CRYPT_CERTINFO_ISSUERDOMAINPOLICY ) || \
		containsAnyPolicy( issuerAttributes, 
						   CRYPT_CERTINFO_SUBJECTDOMAINPOLICY ) )
		{
		setErrorValues( CRYPT_CERTINFO_POLICYMAPPINGS, 
						CRYPT_ERRTYPE_ISSUERCONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	/* If there's no requirement for a policy and none set, we're done */
	if( policyType == POLICY_NONE && constrainedAttributeListPtr == NULL )
		return( CRYPT_OK );

	/* Check the subject policy */
	if( !checkPolicyType( constrainedAttributeListPtr, &subjectHasPolicy,
						  &subjectHasAnyPolicy, 
						  ( policyType == POLICY_NONE_SPECIFIC || \
							policyType == POLICY_SUBJECT_SPECIFIC || \
							policyType == POLICY_BOTH_SPECIFIC ) ? \
							TRUE : FALSE ) )
		{
		setErrorValues( CRYPT_CERTINFO_CERTPOLICYID, 
						CRYPT_ERRTYPE_CONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	/* If there's no requirement for an issuer policy and none set by the 
	   issuer, we're done */
	if( ( ( policyType == POLICY_SUBJECT ) || \
		  ( policyType == POLICY_SUBJECT_SPECIFIC ) ) && \
		attributeListPtr == NULL )
		return( CRYPT_OK );

	/* Check the subject policy */
	if( !checkPolicyType( attributeListPtr , &issuerHasPolicy,
						  &issuerHasAnyPolicy, 
						  ( policyType == POLICY_BOTH_SPECIFIC ) ? \
							TRUE : FALSE ) )
		{
		setErrorValues( CRYPT_CERTINFO_CERTPOLICYID, 
						CRYPT_ERRTYPE_CONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	/* Both the issuer and subject have some sort of policy, if either are 
	   anyPolicy wildcards (introduced in RFC 3280 section 4.2.1.5) then 
	   it's considered a match */
	if( subjectHasAnyPolicy || issuerHasAnyPolicy )
		return( CRYPT_OK );

	/* An explicit policy is required, make sure that at least one of the 
	   issuer policies matches at least one of the subject policies.  Note
	   that there's no exception for PKIX path-kludge certs, this is an 
	   error in the RFC, for which the text at this point is unchanged from 
	   RFC 2459.  In fact this contradicts the path-processing pesudocode, 
	   but since that in turn contradicts the main text in a number of 
	   places we take the main text as definitive, not the buggy 
	   pseudocode */
	for( attributeCursor = ( ATTRIBUTE_LIST * ) attributeListPtr; \
		 attributeCursor != NULL; \
		 attributeCursor = findNextFieldInstance( attributeCursor ) )
		{
		ATTRIBUTE_LIST *constrainedAttributeCursor;	

		assert( attributeCursor->fieldID == CRYPT_CERTINFO_CERTPOLICYID );

		for( constrainedAttributeCursor = \
					( ATTRIBUTE_LIST * ) constrainedAttributeListPtr; \
			 constrainedAttributeCursor != NULL; \
			 constrainedAttributeCursor = \
					findNextFieldInstance( constrainedAttributeCursor ) )
			{
			assert( constrainedAttributeCursor->fieldID == \
					CRYPT_CERTINFO_CERTPOLICYID );

			if( attributeCursor->valueLength == \
							constrainedAttributeCursor->valueLength && \
				!memcmp( attributeCursor->value, 
						 constrainedAttributeCursor->value, 
						 attributeCursor->valueLength ) )
				return( CRYPT_OK );
			}
		}

	/* We couldn't find a matching policy, report an error */
	setErrorValues( CRYPT_CERTINFO_CERTPOLICYID, CRYPT_ERRTYPE_CONSTRAINT );
	return( CRYPT_ERROR_INVALID );
	}

/* Check path constraints placed by an issuer, checked if complianceLevel 
   >= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL */

int checkPathConstraints( const CERT_INFO *subjectCertInfoPtr,
						  const ATTRIBUTE_LIST *issuerAttributes,
						  const int complianceLevel,
						  CRYPT_ATTRIBUTE_TYPE *errorLocus, 
						  CRYPT_ERRTYPE_TYPE *errorType )
	{
	ATTRIBUTE_LIST *attributeListPtr;

	assert( isReadPtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
	assert( isReadPtr( issuerAttributes, sizeof( ATTRIBUTE_LIST ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	/* If this is a PKIX path-kludge cert, the path length constraints don't 
	   apply to it (PKIX section 4.2.1.10).  This is required in order to 
	   allow extra certs to be kludged into the path without violating the 
	   name constraint */
	if( isPathKludge( subjectCertInfoPtr ) )
		return( CRYPT_OK );

	/* If the path length constraint hasn't been triggered yet, we're OK */
	if( issuerAttributes->intValue > 0 )
		return( CRYPT_OK );

	/* The path length constraint is in effect, the next cert down the chain 
	   must be an end-entity cert */
	attributeListPtr = findAttributeField( subjectCertInfoPtr->attributes, 
										   CRYPT_CERTINFO_CA, 
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL && attributeListPtr->intValue )
		{
		setErrorValues( CRYPT_CERTINFO_PATHLENCONSTRAINT,
						CRYPT_ERRTYPE_ISSUERCONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Check a Certificate	Object						*
*																			*
****************************************************************************/

/* Check the validity of a CRL based on an issuer cert */

static int checkCRL( const CERT_INFO *crlInfoPtr,
					 const CERT_INFO *issuerCertInfoPtr,
					 const int complianceLevel,
					 CRYPT_ATTRIBUTE_TYPE *errorLocus, 
					 CRYPT_ERRTYPE_TYPE *errorType )
	{
	ATTRIBUTE_LIST *attributeListPtr;

	/* If it's a delta CRL, make sure that the CRL numbers make sense (that 
	   is, that the delta CRL was issued after the full CRL) */
	attributeListPtr = findAttributeField( crlInfoPtr->attributes,
										   CRYPT_CERTINFO_DELTACRLINDICATOR, 
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL )
		{
		const int deltaCRLindicator = ( int ) attributeListPtr->intValue;

		attributeListPtr = findAttributeField( crlInfoPtr->attributes,
											   CRYPT_CERTINFO_CRLNUMBER, 
											   CRYPT_ATTRIBUTE_NONE  );
		if( attributeListPtr != NULL && \
			attributeListPtr->intValue >= deltaCRLindicator )
			{
			setErrorValues( CRYPT_CERTINFO_DELTACRLINDICATOR,
							CRYPT_ERRTYPE_CONSTRAINT );
			return( CRYPT_ERROR_INVALID );
			}
		}

	/* If it's a standalone CRL entry used purely as a container for 
	   revocation data, don't try and perform any issuer-based checking */
	if( issuerCertInfoPtr == NULL )
		return( CRYPT_OK );

	/* Make sure that the issuer can sign CRLs and the issuer cert in
	   general is in order */
	return( checkKeyUsage( issuerCertInfoPtr, 
						   CHECKKEY_FLAG_CA | CHECKKEY_FLAG_GENCHECK, 
						   CRYPT_KEYUSAGE_CRLSIGN, complianceLevel, 
						   errorLocus, errorType ) );
	}

/* Check the validity of a subject cert based on an issuer cert, with the 
   level of checking performed depending on the complianceLevel setting.  If
   the shortCircuitCheck flag is set (used for cert issuer : subject pairs 
   that may already have been checked) we skip the constant-result checks if 
   the combination has already been checked at this compliance level */

int checkCert( CERT_INFO *subjectCertInfoPtr,
			   const CERT_INFO *issuerCertInfoPtr,
			   const BOOLEAN shortCircuitCheck,
			   CRYPT_ATTRIBUTE_TYPE *errorLocus, 
			   CRYPT_ERRTYPE_TYPE *errorType )
	{
	const ATTRIBUTE_LIST *subjectAttributes = subjectCertInfoPtr->attributes;
	const ATTRIBUTE_LIST *issuerAttributes = \
			( issuerCertInfoPtr != NULL ) ? issuerCertInfoPtr->attributes : NULL;
	const ATTRIBUTE_LIST *attributeListPtr;
	const BOOLEAN subjectSelfSigned = \
					( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ? \
					TRUE : FALSE;
	BOOLEAN subjectIsCA = FALSE, issuerIsCA = FALSE;
	const time_t currentTime = getTime();
	int complianceLevel, status;

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

	/* Determine how much checking we need to perform.  If this is a 
	   currently-under-construction cert we use the maximum compliance level 
	   to ensure that cryptlib never produces broken certs */
	if( subjectCertInfoPtr->certificate == NULL )
		complianceLevel = CRYPT_COMPLIANCELEVEL_PKIX_FULL;
	else
		{
		status = krnlSendMessage( subjectCertInfoPtr->ownerHandle, 
								  IMESSAGE_GETATTRIBUTE, &complianceLevel, 
								  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If it's some form of certificate request or an OCSP object (which 
	   means that it isn't signed by an issuer in the normal sense), there's 

⌨️ 快捷键说明

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