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

📄 certschk.c

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

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

/****************************************************************************
*																			*
*								Utility Routines							*
*																			*
****************************************************************************/

/* Generate a nameID or issuerID.  These are needed when storing/retrieving a
   certificate to/from an database keyset, which can't handle the awkward
   heirarchical IDs usually used in certificates.  There are two types of 
   IDs, the nameID which is an SHA-1 hash of the DN and is used for 
   certificates, and the issuerID which is an SHA-1 hash of the 
   IssuerAndSerialNumber and is used for CRLs and CMS */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int generateCertID( IN_BUFFER( dnLength ) const void *dn, 
						   IN_LENGTH_SHORT const int dnLength,
						   IN_BUFFER_OPT( serialNumberLength ) \
								const void *serialNumber,
						   IN_LENGTH_SHORT_Z const int serialNumberLength, 
						   OUT_BUFFER( certIdMaxLength, KEYID_SIZE ) \
								BYTE *certID, 
						   IN_LENGTH_SHORT_MIN( KEYID_SIZE ) \
								const int certIdMaxLength )
	{
	HASHFUNCTION_ATOMIC hashFunctionAtomic;
	HASHFUNCTION hashFunction;
	HASHINFO hashInfo;
	STREAM stream;
	BYTE buffer[ MAX_SERIALNO_SIZE + 8 + 8 ];
	int status;

	assert( isReadPtr( dn, dnLength ) );
	assert( ( serialNumber == NULL && serialNumberLength == 0 ) || \
			( isReadPtr( serialNumber, serialNumberLength ) && \
			  serialNumberLength <= MAX_SERIALNO_SIZE ) );
	assert( isWritePtr( certID, certIdMaxLength ) );

	REQUIRES( ( serialNumber == NULL && serialNumberLength == 0 ) || \
			  ( serialNumber != NULL && \
			    serialNumberLength > 0 && \
				serialNumberLength <= MAX_SERIALNO_SIZE ) );
	REQUIRES( certIdMaxLength >= KEYID_SIZE && \
			  certIdMaxLength < MAX_INTLENGTH_SHORT );

	/* Clear return value */
	memset( certID, 0, min( 16, certIdMaxLength ) );

	/* Get the hash algorithm information */
	getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, NULL );
	getHashParameters( CRYPT_ALGO_SHA1, &hashFunction, NULL );

	/* If it's a pure DN hash we don't have to perform any encoding */
	if( serialNumber == NULL )
		{
		hashFunctionAtomic( certID, certIdMaxLength, dn, dnLength );

		return( CRYPT_OK );
		}

	/* Write the relevant information to a buffer and hash the data to get
	   the ID */
	sMemOpen( &stream, buffer, MAX_SERIALNO_SIZE + 8 );
	status = writeSequence( &stream, 
							dnLength + sizeofInteger( serialNumber, \
													  serialNumberLength ) );
	if( cryptStatusError( status ) )
		{
		sMemClose( &stream );
		return( status );
		}
	hashFunction( hashInfo, NULL, 0, buffer, stell( &stream ), 
				  HASH_STATE_START );
	hashFunction( hashInfo, NULL, 0, dn, dnLength, HASH_STATE_CONTINUE );
	sseek( &stream, 0 );
	status = writeInteger( &stream, serialNumber, serialNumberLength,
						   DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		{
		hashFunction( hashInfo, certID, certIdMaxLength, buffer, 
					  stell( &stream ), HASH_STATE_END );
		}
	sMemClose( &stream );

	return( status );
	}

/****************************************************************************
*																			*
*							Validity/Revocation Checking 					*
*																			*
****************************************************************************/

/* Check the entries in an RTCS or OCSP response object against a 
   certificate store.  The semantics for this one are a bit odd, the source 
   information for the check is from a request but the destination 
   information is in a response.  Since we don't have a copy-and-verify 
   function we do the checking from the response even though technically 
   it's the request data that's being checked */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkRTCSResponse( INOUT CERT_INFO *certInfoPtr,
							  IN_HANDLE const CRYPT_KEYSET iCryptKeyset )
	{
	VALIDITY_INFO *validityInfo;
	BOOLEAN isInvalid = FALSE;

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

	REQUIRES( isHandleRangeValid( iCryptKeyset ) );

	/* Walk down the list of validity entries fetching status information
	   on each one from the certificate store */
	for( validityInfo = certInfoPtr->cCertVal->validityInfo;
		 validityInfo != NULL; validityInfo = validityInfo->next )
		{
		MESSAGE_KEYMGMT_INFO getkeyInfo;
		int status;

		/* Determine the validity of the object */
		setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID,
							   validityInfo->data, KEYID_SIZE, NULL, 0,
							   KEYMGMT_FLAG_CHECK_ONLY );
		status = krnlSendMessage( iCryptKeyset, IMESSAGE_KEY_GETKEY,
								  &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
		if( cryptStatusOK( status ) )
			{
			/* The certificate is present and OK, we're done */
			validityInfo->status = TRUE;
			validityInfo->extStatus = CRYPT_CERTSTATUS_VALID;
			}
		else
			{
			/* The certificate isn't present/OK, record the fact that we've 
			   seen at least one invalid certificate */
			validityInfo->status = FALSE;
			validityInfo->extStatus = CRYPT_CERTSTATUS_NOTVALID;
			isInvalid = TRUE;
			}
		}

	/* If at least one certificate was invalid indicate this to the caller.  
	   Note that if there are multiple certificates present in the query 
	   it's up to the caller to step through the list to find out which ones 
	   were invalid */
	return( isInvalid ? CRYPT_ERROR_INVALID : CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int checkOCSPResponse( INOUT CERT_INFO *certInfoPtr,
					   IN_HANDLE const CRYPT_KEYSET iCryptKeyset )
	{
	REVOCATION_INFO *revocationInfo;
	BOOLEAN isRevoked = FALSE;

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

	REQUIRES( isHandleRangeValid( iCryptKeyset ) );

	/* Walk down the list of revocation entries fetching status information
	   on each one from the certificate store */
	for( revocationInfo = certInfoPtr->cCertRev->revocations;
		 revocationInfo != NULL; revocationInfo = revocationInfo->next )
		{
		CRYPT_KEYID_TYPE idType = revocationInfo->idType;
		MESSAGE_KEYMGMT_INFO getkeyInfo;
		CERT_INFO *crlEntryInfoPtr;
		REVOCATION_INFO *crlRevocationInfo;
		const BYTE *idPtr = revocationInfo->idPtr;
		int status;

		ENSURES( revocationInfo->idType == CRYPT_KEYID_NONE || \
				 revocationInfo->idType == CRYPT_IKEYID_CERTID || \
				 revocationInfo->idType == CRYPT_IKEYID_ISSUERID );

		/* If it's an OCSPv1 ID and there's no alternate ID information 
		   present we can't really do anything with it because the one-way 
		   hashing process required by the standard destroys the certificate
		   identifying information */
		if( idType == CRYPT_KEYID_NONE )
			{
			if( revocationInfo->altIdType == CRYPT_KEYID_NONE )
				{
				revocationInfo->status = CRYPT_OCSPSTATUS_UNKNOWN;
				continue;
				}

			/* There's an alternate ID present, use that instead */
			idType = revocationInfo->altIdType;
			idPtr = revocationInfo->altID;
			}

		/* Determine the revocation status of the object.  Unfortunately
		   because of the way OCSP returns status information we can't just
		   return a yes/no response but have to perform multiple queries to
		   determine whether a certificate is not revoked, revoked, or 
		   unknown.  Optimising the query strategy is complicated by the 
		   fact that although in theory the most common status will be 
		   not-revoked we could also get a large number of status-unknown 
		   queries, for example if a widely-deployed implementation which is 
		   pointed at a cryptlib-based server gets its ID-hashing wrong and 
		   submits huge numbers of queries with IDs that match no known 
		   certificate.  The best we can do is assume that a not-revoked 
		   status will be the most common and if that fails fall back to a 
		   revoked status check */
		setMessageKeymgmtInfo( &getkeyInfo, idType, idPtr, KEYID_SIZE, 
							   NULL, 0, KEYMGMT_FLAG_CHECK_ONLY );
		status = krnlSendMessage( iCryptKeyset, IMESSAGE_KEY_GETKEY,
								  &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
		if( cryptStatusOK( status ) )
			{
			/* The certificate is present and not revoked/OK, we're done */
			revocationInfo->status = CRYPT_OCSPSTATUS_NOTREVOKED;
			continue;
			}

		/* The certificate isn't a currently active cert, if it weren't for 
		   the need to return the CRL-based OCSP status values we could just 
		   return not-OK now but as it is we have to differentiate between 
		   revoked and unknown so we perform a second query, this time of 
		   the revocation information */
		setMessageKeymgmtInfo( &getkeyInfo, idType, idPtr, KEYID_SIZE, 
							   NULL, 0, KEYMGMT_FLAG_NONE );
		status = krnlSendMessage( iCryptKeyset, IMESSAGE_KEY_GETKEY,
								  &getkeyInfo, KEYMGMT_ITEM_REVOCATIONINFO );
		if( cryptStatusError( status ) )
			{
			/* No revocation information found, status is unknown */
			revocationInfo->status = CRYPT_OCSPSTATUS_UNKNOWN;
			continue;
			}

		/* The certificate has been revoked, copy the revocation information 
		   across from the CRL entry */
		status = krnlAcquireObject( getkeyInfo.cryptHandle,
									OBJECT_TYPE_CERTIFICATE,
									( void ** ) &crlEntryInfoPtr,
									CRYPT_ERROR_SIGNALLED );
		if( cryptStatusError( status ) )
			return( status );
		crlRevocationInfo = crlEntryInfoPtr->cCertRev->revocations;
		if( crlRevocationInfo != NULL )
			{
			revocationInfo->revocationTime = \
									crlRevocationInfo->revocationTime;
			if( crlRevocationInfo->attributes != NULL )
				{
				/* We don't check for problems in copying the attributes 
				   since bailing out at this late stage is worse than 
				   missing a few obscure annotations to the revocation */
				( void ) copyRevocationAttributes( &revocationInfo->attributes,
												   crlRevocationInfo->attributes );
				}
			}
		krnlReleaseObject( crlEntryInfoPtr->objectHandle );
		krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT );

		/* Record the fact that we've seen at least one revoked certificate */
		revocationInfo->status = CRYPT_OCSPSTATUS_REVOKED;
		isRevoked = TRUE;
		}

	/* If at least one certificate was revoked indicate this to the caller.  
	   Note that if there are multiple certificates present in the query then 
	   it's up to the caller to step through the list to find out which ones 
	   were revoked */
	return( isRevoked ? CRYPT_ERROR_INVALID : CRYPT_OK );
	}

/* Check a certificate using an RTCS or OCSP responder */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkResponder( INOUT CERT_INFO *certInfoPtr,
						   IN_HANDLE const CRYPT_SESSION iCryptSession )
	{
	CRYPT_CERTIFICATE cryptResponse = DUMMY_INIT;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	int type, status;

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

	REQUIRES( isHandleRangeValid( iCryptSession) );

	status = krnlSendMessage( iCryptSession, IMESSAGE_GETATTRIBUTE, &type,
							  CRYPT_IATTRIBUTE_SUBTYPE );
	if( cryptStatusError( status ) )
		return( status );

	ENSURES( ( type == SUBTYPE_SESSION_RTCS ) || \
			 ( type == SUBTYPE_SESSION_OCSP ) );

	/* Create the request, add the certificate, and add the request to the
	   session */
	setMessageCreateObjectInfo( &createInfo,
							    ( type == SUBTYPE_SESSION_RTCS ) ? \

⌨️ 快捷键说明

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