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

📄 certschk.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
									CRYPT_CERTTYPE_RTCS_REQUEST : \
									CRYPT_CERTTYPE_OCSP_REQUEST );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );
	status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
					&certInfoPtr->objectHandle, CRYPT_CERTINFO_CERTIFICATE );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptSession, IMESSAGE_SETATTRIBUTE,
					&createInfo.cryptHandle, CRYPT_SESSINFO_REQUEST );
	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		return( status );

	/* Activate the session and get the response info */
	status = krnlSendMessage( iCryptSession, IMESSAGE_SETATTRIBUTE,
							  MESSAGE_VALUE_TRUE, CRYPT_SESSINFO_ACTIVE );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptSession, IMESSAGE_GETATTRIBUTE,
								  &cryptResponse, CRYPT_SESSINFO_RESPONSE );
	if( cryptStatusError( status ) )
		return( status );
	if( type == SUBTYPE_SESSION_RTCS )
		{
		int certStatus;

		status = krnlSendMessage( cryptResponse, IMESSAGE_GETATTRIBUTE,
								  &certStatus, CRYPT_CERTINFO_CERTSTATUS );
		if( cryptStatusOK( status ) && \
			( certStatus != CRYPT_CERTSTATUS_VALID ) )
			status = CRYPT_ERROR_INVALID;
		}
	else
		{
		int revocationStatus;

		status = krnlSendMessage( cryptResponse, IMESSAGE_GETATTRIBUTE,
								  &revocationStatus,
								  CRYPT_CERTINFO_REVOCATIONSTATUS );
		if( cryptStatusOK( status ) && \
			( revocationStatus != CRYPT_OCSPSTATUS_NOTREVOKED ) )
			status = CRYPT_ERROR_INVALID;
		}
	krnlSendNotifier( cryptResponse, IMESSAGE_DECREFCOUNT );

	return( status );
	}

/* Check a certificate against a CRL */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkCRL( INOUT CERT_INFO *certInfoPtr, 
					 IN_HANDLE const CRYPT_CERTIFICATE iCryptCRL )
	{
	CERT_INFO *crlInfoPtr;
	int i, status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );

	REQUIRES( isHandleRangeValid( iCryptCRL ) );

	/* Check that the CRL is a complete signed CRL and not a newly-created
	   CRL object */
	status = krnlAcquireObject( iCryptCRL, OBJECT_TYPE_CERTIFICATE,
								( void ** ) &crlInfoPtr,
								CRYPT_ARGERROR_VALUE );
	if( cryptStatusError( status ) )
		return( status );
	if( crlInfoPtr->certificate == NULL )
		{
		krnlReleaseObject( crlInfoPtr->objectHandle );
		return( CRYPT_ERROR_NOTINITED );
		}

	/* Check the base certificate against the CRL.  If it's been revoked or 
	   there's only a single certificate present, exit */
	status = checkRevocation( certInfoPtr, crlInfoPtr );
	if( cryptStatusError( status ) || \
		certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN )
		{
		krnlReleaseObject( crlInfoPtr->objectHandle );
		return( status );
		}

	/* It's a certificate chain, check every remaining certificate in the 
	   chain against the CRL.  In theory this is pointless because a CRL can 
	   only contain information for a single certificate in the chain, 
	   however the caller may have passed us a CRL for an intermediate 
	   certificate (in which case the check for the leaf certificate was 
	   pointless).  In any case it's easier to just do the check for all 
	   certificates than to determine which certificate the CRL applies to 
	   so we check for all certificates */
	for( i = 0; i < certInfoPtr->cCertCert->chainEnd && \
				i < MAX_CHAINLENGTH; i++ )
		{
		CERT_INFO *certChainInfoPtr;

		/* Check this certificate against the CRL */
		status = krnlAcquireObject( certInfoPtr->cCertCert->chain[ i ],
									OBJECT_TYPE_CERTIFICATE,
									( void ** ) &certChainInfoPtr,
									CRYPT_ERROR_SIGNALLED );
		if( cryptStatusOK( status ) )
			{
			status = checkRevocation( certChainInfoPtr, crlInfoPtr );
			krnlReleaseObject( certChainInfoPtr->objectHandle );
			}

		/* If the certificate has been revoked remember which one is the 
		   revoked certificate and exit */
		if( cryptStatusError( status ) )
			{
			certInfoPtr->cCertCert->chainPos = i;
			break;
			}
		}
	ENSURES( i < MAX_CHAINLENGTH );

	krnlReleaseObject( crlInfoPtr->objectHandle );
	return( status );
	}

/****************************************************************************
*																			*
*							Signature Checking Functions					*
*																			*
****************************************************************************/

/* Check a certificate against an issuer certificate.  The trustAnchorCheck 
   flag is used when we're checking an explicit trust anchor, for which we
   only need to check the signature if it's self-signed.  The 
   shortCircuitCheck flag is used when checking subject:issuer pairs inside 
   certificate chains, which have already been checked by the chain-handling 
   code so a full (re-)check isn't necessary any more */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 7, 8 ) ) \
int checkCertDetails( INOUT CERT_INFO *subjectCertInfoPtr,
					  INOUT_OPT CERT_INFO *issuerCertInfoPtr,
					  IN_HANDLE_OPT const CRYPT_CONTEXT iIssuerPubKey,
					  IN_OPT const X509SIG_FORMATINFO *formatInfo,
					  const BOOLEAN trustAnchorCheck,
					  const BOOLEAN shortCircuitCheck,
					  OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
						CRYPT_ATTRIBUTE_TYPE *errorLocus,
					  OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
						CRYPT_ERRTYPE_TYPE *errorType )
	{
	int status;

	assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
	assert( issuerCertInfoPtr == NULL || \
			isWritePtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
	assert( formatInfo == NULL || \
			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	REQUIRES( iIssuerPubKey == CRYPT_UNUSED || \
			  isHandleRangeValid( iIssuerPubKey ) );

	/* If there's an issuer certificate present check the validity of the
	   subject certificate based on it.  If it's not present all that we can 
	   do is perform a pure signature check with the context */
	if( issuerCertInfoPtr != NULL )
		{
		status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr, 
							shortCircuitCheck, errorLocus, errorType );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If the signature has already been checked or there's no signature-
	   check key present we're done.  The latter can occur when we're
	   checking a data-only certificate in a cert chain chain.  This is safe 
	   because these certificates can only occur when we're reading them 
	   from an (implicitly trusted) private key store */
	if( ( subjectCertInfoPtr->flags & CERT_FLAG_SIGCHECKED ) || \
		iIssuerPubKey == CRYPT_UNUSED )
		return( CRYPT_OK );

	/* If we're checking an explicit trust anchor and the certificate isn't 
	   self-signed there's nothing further left to check */
	if( trustAnchorCheck && issuerCertInfoPtr != NULL && \
		!( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
		return( CRYPT_OK );

	/* If we're performing a standard check and it's an explicitly-trusted 
	   certificate we're done.  If we're performing a check of a certificate 
	   chain then the chain-handling code will have performed its own 
	   handling of trusted certificates/trust anchors so we don't peform a 
	   second check here */
	if( !shortCircuitCheck )
		{
		if( cryptStatusOK( \
				krnlSendMessage( subjectCertInfoPtr->ownerHandle, 
								 IMESSAGE_USER_TRUSTMGMT,
								 &subjectCertInfoPtr->objectHandle,
								 MESSAGE_TRUSTMGMT_CHECK ) ) )
			return( CRYPT_OK );
		}

	/* Check the signature on the certificate.  If there's a problem with 
	   the issuer's public key it'll be reported as a CRYPT_ARGERROR_NUM1,
	   which the caller has to convert into an appropriate error code */
	status = checkX509signature( subjectCertInfoPtr->certificate, 
								 subjectCertInfoPtr->certificateSize,
								 iIssuerPubKey, formatInfo );
	if( cryptStatusError( status ) )
		{
		MESSAGE_DATA msgData;
		BYTE subjectIssuerID[ CRYPT_MAX_HASHSIZE + 8 ];
		BYTE issuerSubjectID[ CRYPT_MAX_HASHSIZE + 8 ];
		int subjectIDlength, issuerIDlength;

		/* There's on special-case situation in which we can get a 
		   signature-check failure that looks like data corruption and 
		   that's when a CA quietly changes its issuing key without changing 
		   anything else so the certificates chain but the signature check 
		   produces garbage as output due to the use of the incorrect key.  
		   Although it could be argued that a CA that does this is broken, 
		   we try and accomodate it by performing a backup check using 
		   keyIDs if the signature check produces garbled output.  Because 
		   of the complete chaos present in keyIDs we can't do this by 
		   default (it would result in far too many false positives) but 
		   it's safe as a fallback at this point since we're about to report 
		   an error anyway and the worst that can happen is that we return 
		   a slightly inappropriate error message.
		   
		   If there's no issuer certificate provided we also have to exit at 
		   this point because we can't go any further without it */
		if( status != CRYPT_ERROR_BADDATA || issuerCertInfoPtr == NULL )
			return( status );

		/* Get the subject certificate's issuerID and the issuer cert's 
		   subjectID.  We don't bother with the alternative awkward 
		   DN-based ID since what we're really interested in is the ID of 
		   the signing key and it's not worth the extra pain of dealing with 
		   these awkward cert IDs just to try and fix up a slight difference 
		   in error codes */
		setMessageData( &msgData, subjectIssuerID, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( subjectCertInfoPtr->objectHandle, 
								  IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER );
		if( cryptStatusError( status ) )
			return( CRYPT_ERROR_BADDATA );
		issuerIDlength = msgData.length;
		setMessageData( &msgData, issuerSubjectID, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( issuerCertInfoPtr->objectHandle, 
								  IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
		if( cryptStatusError( status ) )
			return( CRYPT_ERROR_BADDATA );
		subjectIDlength = msgData.length;

		/* If the keyIDs don't match then it's a signature error due to 
		   false-positive chaining rather than a data corruption error */
		return( ( ( issuerIDlength != subjectIDlength ) || \
				  memcmp( subjectIssuerID, issuerSubjectID, \
						  issuerIDlength ) ) ? \
				CRYPT_ERROR_SIGNATURE : CRYPT_ERROR_BADDATA );
		}

	/* The signature is OK, we don't need to check it again.  There is a
	   theoretical situation in which this can lead to a false positive
	   which requires first checking the certificate using the correct 
	   issuing CA (which will set the CERT_FLAG_SIGCHECKED flag) and then 
	   checking it again using a second CA cert identical to the first but 
	   with a different key.  In other words the issuer DN chains correctly 
	   but the issuer key is different.  The appropriate behaviour here is 
	   somewhat unclear.  It could be argued that a CA that uses two
	   otherwise identical certificates but with different keys is broken 
	   and therefore behaviour in this situation is undefined.  However we 
	   need to do something with the resulting check and returning the 
	   result of the check with the correct CA certificate even if we're 
	   later passed a second incorrect certificate from the CA seems to be 
	   the most appropriate action since it has in the past been validated 
	   by a certificate from the same CA.  If we want to force the check to 
	   be done with a specific CA key (rather than just the issuing CA's 
	   certificate in general) we could store the fingerprint of the 
	   signing key alongside the CERT_FLAG_SIGCHECKED flag */
	subjectCertInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
	
	return( CRYPT_OK );
	}

/* Check a self-signed certificate object like a cert request or a 
   self-signed certificate */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkSelfSignedCert( INOUT CERT_INFO *certInfoPtr,
								IN_OPT const X509SIG_FORMATINFO *formatInfo )
	{
	CRYPT_CONTEXT iCryptContext = CRYPT_UNUSED;
	CERT_INFO *issuerCertInfoPtr;
	BOOLEAN trustedCertAcquired = FALSE;
	int status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( formatInfo == NULL || \
			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );

	/* Since there's no signer certificate provided it has to be either 
	   explicitly self-signed or signed by a trusted certificate */
	if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
		{
		if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
			iCryptContext = certInfoPtr->iPubkeyContext;
		issuerCertInfoPtr = certInfoPtr;

⌨️ 快捷键说明

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