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

📄 ca_clean.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*					  cryptlib DBMS CA Cleanup Interface					*
*						Copyright Peter Gutmann 1996-2007					*
*																			*
****************************************************************************/

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

/* When we iterate through the entries in the certificate store we have to 
   protect ourselves against repeatedly fetching the same value over and 
   over again if there's a problem with the certificate store, which we do 
   by remembering data from the previous certificate that we fetched.  The 
   following value defines the amount of certificate data that we record 
   (since this doesn't protect against Byzantine failures, we also maintain
   an iteration counter that bails out after a certain number of iterations
   are exceeded) */

#define MAX_PREVCERT_DATA	128

#ifdef USE_DBMS

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Get a partially-issued certificate.  We have to perform the import
   ourselves since it's marked as an incompletely-issued certificate and so 
   is invisible to accesses performed via the standard certificate fetch 
   routines */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int getNextPartialCert( INOUT DBMS_INFO *dbmsInfo,
							   OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
							   INOUT_BUFFER_FIXED( prevCertDataMaxLen ) \
								BYTE *prevCertData, 
							   IN_LENGTH_SHORT const int prevCertDataMaxLen, 
							   const BOOLEAN isRenewal )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	BYTE certificate[ MAX_QUERY_RESULT_SIZE + 8 ];
	char encodedCertData[ MAX_QUERY_RESULT_SIZE + 8 ];
	void *certPtr = hasBinaryBlobs( dbmsInfo ) ? \
					( void * ) certificate : encodedCertData;
	int certSize, status;			/* Cast needed for gcc */

	assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
	assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
	assert( isWritePtr( prevCertData, prevCertDataMaxLen ) );

	REQUIRES( prevCertDataMaxLen > 0 && \
			  prevCertDataMaxLen < MAX_INTLENGTH_SHORT );

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

	/* Find the next certificate and import it.  Although this would appear 
	   to be fetching the same certificate over and over again, the caller 
	   will be deleting the currently-fetched certificate after we return it 
	   to them so in practice it fetches a new certificate each time (we
	   also perform a loop check on the prevCertData once we've fetched the
	   next certificate so we'll detect any looping fairly quickly) */
	status = dbmsQuery( isRenewal ? \
				"SELECT certData FROM certificates WHERE keyID LIKE '" KEYID_ESC2 "%'" : \
				"SELECT certData FROM certificates WHERE keyID LIKE '" KEYID_ESC1 "%'",
						certPtr, MAX_QUERY_RESULT_SIZE, &certSize, NULL, 
						DBMS_CACHEDQUERY_NONE, DBMS_QUERY_NORMAL );
	if( cryptStatusError( status ) )
		return( status );
	if( !hasBinaryBlobs( dbmsInfo ) )
		{
		status = base64decode( certificate, MAX_CERT_SIZE, &certSize,
							   encodedCertData, certSize, 
							   CRYPT_CERTFORMAT_NONE );
		if( cryptStatusError( status ) )
			{
			assert( DEBUG_WARN );
			return( status );
			}
		}
	ENSURES( certSize > 0 && certSize <= MAX_CERT_SIZE );

	/* If we're stuck in a loop fetching the same value over and over, make
	   an emergency exit */
	if( !memcmp( prevCertData, certificate, \
				 min( certSize, prevCertDataMaxLen ) ) )
		{
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_DUPLICATE );
		}
	memcpy( prevCertData, certificate, prevCertDataMaxLen );

	/* Reset the first byte of the certificate data from the not-present 
	   magic value to allow it to be imported and create a certificate from 
	   it */
	certificate[ 0 ] = BER_SEQUENCE;
	setMessageCreateObjectIndirectInfo( &createInfo, certificate, certSize,
										CRYPT_CERTTYPE_CERTIFICATE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
							  &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusOK( status ) )
		*iCertificate = createInfo.cryptHandle;
	return( status );
	}

/****************************************************************************
*																			*
*								CA Cleanup Functions						*
*																			*
****************************************************************************/

/* Perform a cleanup operation on the certificate store, removing 
   incomplete, expired, and otherwise leftover certificates.  Since we're 
   cleaning up the certificate store we try and continue even if an error 
   occurs, at least up to a limit.  In addition to protect against Byzantine
   failures we include an iteration counter and bail out after a certain 
   number of iterations.  This is a tradeoff between DoS protection and
   bailing out too early, using FAILSAFE_ITERATIONS_LARGE is a reasonable
   compromise */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int caCleanup( INOUT DBMS_INFO *dbmsInfo, 
			   IN_ENUM( CRYPT_CERTACTION ) const CRYPT_CERTACTION_TYPE action,
			   INOUT ERROR_INFO *errorInfo )
	{
	BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
	BYTE prevCertData[ MAX_PREVCERT_DATA + 8 ];
	char certID[ MAX_QUERY_RESULT_SIZE + 8 ];
	const time_t currentTime = getTime();
	int certIDlength, errorCount, iterationCount, status;

	assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );

	REQUIRES( action == CRYPT_CERTACTION_EXPIRE_CERT || \
			  action == CRYPT_CERTACTION_CLEANUP );
	REQUIRES( errorInfo != NULL );

	/* If the time is screwed up we can't perform time-based cleanup
	   actions */
	if( action == CRYPT_CERTACTION_EXPIRE_CERT && \
		currentTime <= MIN_TIME_VALUE )
		retIntError();

	/* Rumble through the certificate store either deleting leftover 
	   requests or expiring every certificate which is no longer current */
	memset( prevCertData, 0, MAX_PREVCERT_DATA );
	for( status = CRYPT_OK, errorCount = 0, iterationCount = 0;
		 status != CRYPT_ERROR_NOTFOUND && \
			errorCount < FAILSAFE_ITERATIONS_SMALL && \
			iterationCount < FAILSAFE_ITERATIONS_LARGE;
		 iterationCount++ )
		{
		/* Find the certificate ID of the next expired certificate or next 
		   certificate request (revocation requests are handled later by 
		   completing the revocation).  Note that the select requires that 
		   the database glue code be capable of returning a single result 
		   and then finishing the query, for some back-ends there may be a 
		   need to explicitly cancel the query after the first result is 
		   returned if the database returns an entire result set */
		if( action == CRYPT_CERTACTION_EXPIRE_CERT )
			{
			initBoundData( boundDataPtr );
			setBoundDataDate( boundDataPtr, 0, &currentTime );
			status = dbmsQuery(
						"SELECT certID FROM certificates WHERE validTo < ?",
								certID, MAX_QUERY_RESULT_SIZE, &certIDlength, 
								boundDataPtr, DBMS_CACHEDQUERY_NONE, 
								DBMS_QUERY_NORMAL );
			}
		else
			{
			status = dbmsQuery(
						"SELECT certID FROM certRequests WHERE type = "
							TEXT_CERTTYPE_REQUEST_CERT,
								certID, MAX_QUERY_RESULT_SIZE, &certIDlength, 
								NULL, DBMS_CACHEDQUERY_NONE, 
								DBMS_QUERY_NORMAL );
			}
		if( cryptStatusError( status ) )
			{
			/* If we've processed all of the entries this isn't an error */
			if( status == CRYPT_ERROR_NOTFOUND )
				resetErrorInfo( dbmsInfo );
			else
				errorCount++;
			continue;
			}
		if( certIDlength > MAX_PREVCERT_DATA )
			{
			assert( DEBUG_WARN );
			certIDlength = MAX_PREVCERT_DATA;
			}
		if( !memcmp( prevCertData, certID, certIDlength ) )
			{
			/* We're stuck in a loop fetching the same value over and over,
			   make an emergency exit */
			assert( DEBUG_WARN );
			break;
			}
		memcpy( prevCertData, certID, certIDlength );

		/* Clean up/expire the certificate.  Since CRYPT_CERTACTION_CLEANUP 
		   is a composite action that encompasses a whole series of 
		   operations we replace it with a more specific action code */
		status = updateCertLog( dbmsInfo,
								( action == CRYPT_CERTACTION_CLEANUP ) ? \
								CRYPT_CERTACTION_RESTART_CLEANUP : action,
								NULL, 0, NULL, 0, certID, certIDlength, 
								NULL, 0, DBMS_UPDATE_BEGIN );
		if( cryptStatusOK( status ) )
			{
			initBoundData( boundDataPtr );
			setBoundData( boundDataPtr, 0, certID, certIDlength );
			status = dbmsUpdate( ( action == CRYPT_CERTACTION_EXPIRE_CERT ) ? \
				"DELETE FROM certificates WHERE certID = ?" : \
				"DELETE FROM certRequests WHERE certID = ?",
								 boundDataPtr, DBMS_UPDATE_COMMIT );
			}
		else
			{
			/* Something went wrong, abort the transaction */
			dbmsUpdate( NULL, NULL, DBMS_UPDATE_ABORT );
			errorCount++;
			}
		}
	if( errorCount >= FAILSAFE_ITERATIONS_SMALL || \
		iterationCount >= FAILSAFE_ITERATIONS_LARGE )
		{
		/* It's hard to tell what type of error an iterationCount-exceeded
		   situation really is, in theory it's a software error (either in
		   cryptlib's fetch logic or in the dabatase) but because we could be
		   cleaning up a large number of entries (for example if it's 
		   cleaning up the result of an app going into and endless loop and
		   requesting a large number of certificates) it's entirely possible 
		   that this is isn't an abnormal situation. Because of this we 
		   don't flag it as an internal error but simply warn in the debug 
		   build, although we do bail out after a fixed limit */
		assert( DEBUG_WARN );
		}

	/* If we ran into a problem, perform a fallback general delete of
	   entries that caused the problem */
	if( status != CRYPT_ERROR_NOTFOUND )
		{
		if( action == CRYPT_CERTACTION_EXPIRE_CERT )
			{
			updateCertErrorLogMsg( dbmsInfo, status, "Expire operation "
								   "failed, performing fallback straight "

⌨️ 快捷键说明

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