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

📄 chk_use.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
		if( algorithmType & ALGO_TYPE_KEYAGREEMENT )
			nsUsage |= certTypeInfo[ i ].keyUsageFlags & USAGE_KEYAGREEMENT_MASK;

		/* If there's no key usage consistent with the Netscape 
		   certificate-type, return an error */
		if( nsUsage == 0 )
			{
			*errorLocus = CRYPT_CERTINFO_NS_CERTTYPE;
			return( CRYPT_ERROR_INVALID );
			}

		keyUsage |= nsUsage;
		}
	ENSURES( i < FAILSAFE_ARRAYSIZE( certTypeInfo, CERT_TYPE_INFO ) );

	return( keyUsage );
	}

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
int getKeyUsageFromExtKeyUsage( const CERT_INFO *certInfoPtr,
								OUT_FLAGS_Z( CRYPT_KEYUSAGE ) int *keyUsage,
								OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
									CRYPT_ATTRIBUTE_TYPE *errorLocus, 
								OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
									CRYPT_ERRTYPE_TYPE *errorType )
	{
	int algorithmType = ALGO_TYPE_NONE, localKeyUsage;

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

	/* Clear return value */
	*keyUsage = CRYPT_KEYUSAGE_NONE;

	/* If there are not attributes present, there's nothing to do */
	if( certInfoPtr->attributes == NULL )
		return( CRYPT_OK );

	/* 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;
	ENSURES( algorithmType != ALGO_TYPE_NONE );

	/* Get the key usage flags for the given extended/Netscape usage type(s)
	   and algorithm type */
	localKeyUsage = getExtendedKeyUsageFlags( certInfoPtr->attributes,
											  algorithmType, errorLocus );
	localKeyUsage |= getNetscapeCertTypeFlags( certInfoPtr->attributes, 
											   algorithmType, errorLocus );
	if( cryptStatusError( localKeyUsage ) )
		{
		/* 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 );
		}
	*keyUsage = localKeyUsage;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Check Key/Certificate Usage						*
*																			*
****************************************************************************/

/* Check that a certificate/key is valid for a particular purpose.  This 
   function is used in one of two ways:

	1. Check that a key can be used for a particular purpose, regardless of
	   whether the certificate extensions that define the usage make any 
	   sense or not.  This is used when performing an object usage check 
	   such as whether a key can be used for signing or encryption.

	2. Check that the key usage is consistent.  This is used when performing
	   a certificate validity check, indicated by setting the 
	   CHECKKEY_FLAG_GENCHECK  check flag.

   Processing is done in three phases:
   
	1. Fix up usage flags at lower compliance levels if necessary.
	2. Check for strict usability even if the flags don't make sense.
	3. Check consistency as per the PKIX and X.509 specs */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5, 6 ) ) \
int checkKeyUsage( const CERT_INFO *certInfoPtr,
				   IN_FLAGS_Z( CHECKKEY ) const int flags, 
				   IN_FLAGS_Z( CRYPT_KEYUSAGE ) const int specificUsage,
				   IN_RANGE( CRYPT_COMPLIANCELEVEL_OBLIVIOUS, \
							 CRYPT_COMPLIANCELEVEL_LAST - 1 ) \
						const int complianceLevel,
				   OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
						CRYPT_ATTRIBUTE_TYPE *errorLocus,
				   OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
						CRYPT_ERRTYPE_TYPE *errorType )
	{
	ATTRIBUTE_LIST *attributeListPtr;
	const BOOLEAN isGeneralCheck = ( flags & CHECKKEY_FLAG_GENCHECK ) ? \
								   TRUE : FALSE;
	BOOLEAN keyUsageCritical = 0, isCA = FALSE;
	const int trustedUsage = \
				( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
				  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN ) ? \
				certInfoPtr->cCertCert->trustedUsage : CRYPT_UNUSED;
	int keyUsage, rawKeyUsage, extKeyUsage, rawExtKeyUsage, caKeyUsage;
	int status;

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

	REQUIRES( flags >= CHECKKEY_FLAG_NONE && \
			  flags < CHECKKEY_FLAG_MAX );
	REQUIRES( specificUsage >= CRYPT_KEYUSAGE_FLAG_NONE && \
			  specificUsage < CRYPT_KEYUSAGE_FLAG_MAX );
	REQUIRES( complianceLevel >= CRYPT_COMPLIANCELEVEL_OBLIVIOUS && \
			  complianceLevel < CRYPT_COMPLIANCELEVEL_LAST );
	REQUIRES( ( ( 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_KEYUSAGE_NONE ) ) ) );

	/* 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 certificate's actual key usage and check only the 
	   requested against trusted usage */
	if( specificUsage != CRYPT_KEYUSAGE_NONE && \
		trustedUsage != CRYPT_UNUSED && !( 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 );

	/* Phase 1: Fix up values if required */

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

	/* If it's a v1 self-signed certificate the CA status and key usage are 
	   implicit/undefined */
	if( certInfoPtr->version == 1 && \
		( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
		{
		/* If it's claiming to be a CA certificate by virtue of being a v1 
		   self-signed certificate there can't be any v3 CA attributes (or 
		   any v3 attributes for that matter) present.  Unfortunately we 
		   can't just check for the complete non-presence of attributes 
		   because the certificate-import code will have converted an email 
		   address in the DN into the appropriate altName component, 
		   creating at least one valid (in this case) attribute */
		if( isGeneralCheck && \
			( checkAttributePresent( certInfoPtr->attributes, 
									 CRYPT_CERTINFO_BASICCONSTRAINTS ) || \
			  checkAttributePresent( certInfoPtr->attributes, 
									 CRYPT_CERTINFO_KEYUSAGE ) || \
			  extKeyUsage != 0 ) )
			{
			setErrorValues( CRYPT_CERTINFO_VERSION, 
							CRYPT_ERRTYPE_ATTR_VALUE );
			return( CRYPT_ERROR_INVALID );
			}

		/* It's a v1 self-signed certificate with no keyUsage present, don't
		   perform any usage-specific checks */
		return( CRYPT_OK );
		}

	/* Get the certificate's keyUsage.  If we're running at a reduced 
	   compliance level and the CA flag is set and keyUsage isn't or vice 
	   versa we synthesise the required value from the other value in order 
	   to pass the checks that follow */
	attributeListPtr = findAttributeField( certInfoPtr->attributes,
										   CRYPT_CERTINFO_KEYUSAGE, 
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL )
		{
		keyUsage = attributeListPtr->intValue;
		keyUsageCritical = \
			( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) ? TRUE : FALSE;

		/* If the CA key usages are set make sure that the CA flag is set in
		   an appropriate manner */
		if( complianceLevel < CRYPT_COMPLIANCELEVEL_STANDARD && \
			( keyUsage & specificUsage & ( CRYPT_KEYUSAGE_CRLSIGN | \
										   CRYPT_KEYUSAGE_KEYCERTSIGN ) ) && \
			!isCA )
			isCA = TRUE;
		}
	else
		{
		/* There's no keyUsage information present, start with no usage
		   available */
		keyUsage = 0;

		/* If the CA flag is set make sure that the keyUsage is set in an
		   appropriate manner */
		if( complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL && isCA )
			keyUsage = CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN;

		/* Some broken certificates don't have any keyUsage present, which 
		   is meant to imply that the certificate can be used for any usage 
		   that the key is capable of modulo the magic usages keyCertSign 
		   and crlSign.  To handle this we map the algorithm type to the 
		   matching usage types.  In theory the usage may be further 
		   modified by the certificate policy, extKeyUsage, and who knows 
		   what else but in the presence of a certificate like that it's up 
		   to the user to sort out what they want to do with it.
		
		   Some even more broken certificates indicate their usage via a 
		   Netscape key usage (even though they use X.509 flags everywhere 
		   else) which means that we fail them if we're strictly applying 
		   the PKIX requirements at a higher compliance level.  At this 
		   lower level, fixAttributes() will have mapped the Netscape usage 
		   to the equivalent X.509 usage so there's always a keyUsage 
		   present */
		if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
			keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
		if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
			keyUsage |= CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
						CRYPT_KEYUSAGE_NONREPUDIATION;
		if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
			keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
		}
	caKeyUsage = keyUsage & ( CRYPT_KEYUSAGE_CRLSIGN | \
							  CRYPT_KEYUSAGE_KEYCERTSIGN );

	/* Apply the trusted-usage restrictions if necessary */
	rawKeyUsage = keyUsage;
	rawExtKeyUsage = extKeyUsage;
	if( trustedUsage != CRYPT_UNUSED )
		{
		keyUsage &= trustedUsage;
		extKeyUsage &= trustedUsage;
		}

	/* Phase 2: Strict usability check */

	/* If we're looking for a CA certificate make sure that the 
	   basicConstraints CA flag is set and the keyUsage indicates a CA usage 
	   (PKIX sections 4.2.1.3 and 4.2.1.10).  RFC 2459 left this open, it 

⌨️ 快捷键说明

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