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

📄 dbx_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*							cryptlib DBMS 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 */

#ifdef USE_DBMS

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

/* The most common query types can be performed using cached access plans 
   and query data.  The following function determines whether a particular
   query can be performed using cached information, returning the cache 
   entry for the query if so */

CHECK_RETVAL_ENUM( DBMS_CACHEDQUERY ) \
static DBMS_CACHEDQUERY_TYPE getCachedQueryType( IN_ENUM_OPT( KEYMGMT_ITEM ) \
													const KEYMGMT_ITEM_TYPE itemType,
												 IN_KEYID_OPT \
													const CRYPT_KEYID_TYPE keyIDtype )
	{
	REQUIRES_EXT( ( itemType == KEYMGMT_ITEM_NONE || \
					itemType == KEYMGMT_ITEM_REQUEST || \
					itemType == KEYMGMT_ITEM_PKIUSER || \
					itemType == KEYMGMT_ITEM_PUBLICKEY || \
					itemType == KEYMGMT_ITEM_REVOCATIONINFO ), 
				  DBMS_CACHEDQUERY_NONE );
				  /* KEYMGMT_ITEM_NONE is for ongoing queries */
	REQUIRES_EXT( ( itemType == KEYMGMT_ITEM_NONE && \
					keyIDtype == CRYPT_KEYID_NONE ) || \
				  ( keyIDtype > CRYPT_KEYID_NONE && \
					keyIDtype <= CRYPT_KEYID_LAST ), DBMS_CACHEDQUERY_NONE );
				  /* { KEYMGMT_ITEM_NONE, CRYPT_KEYID_NONE } is for ongoing 
				     queries */

	/* If we're not reading from the standard certificates table the query 
	   won't be cached */
	if( itemType != KEYMGMT_ITEM_PUBLICKEY )
		return( DBMS_CACHEDQUERY_NONE );

	/* Check whether we're querying on a cacheable key value type.  An ID 
	   type of CRYPT_KEYID_LAST is a special case which denotes that we're
	   doing a query on a name ID, this is used for getNext() and is very 
	   common (it follows most certificate reads and is used to see if we 
	   can build a chain) so we make it cacheable */
	switch( keyIDtype )
		{
		case CRYPT_KEYID_URI:
			return( DBMS_CACHEDQUERY_URI );

		case CRYPT_IKEYID_ISSUERID:
			return( DBMS_CACHEDQUERY_ISSUERID );

		case CRYPT_IKEYID_CERTID:
			return( DBMS_CACHEDQUERY_CERTID );

		case CRYPT_KEYID_LAST:
			return( DBMS_CACHEDQUERY_NAMEID );
		}

	return( DBMS_CACHEDQUERY_NONE );
	}

/* Get the SQL string to fetch data from a given table */

CHECK_RETVAL_PTR \
static char *getSelectString( IN_ENUM( KEYMGMT_ITEM ) \
								const KEYMGMT_ITEM_TYPE itemType )
	{
	REQUIRES_N( itemType == KEYMGMT_ITEM_REQUEST || \
				itemType == KEYMGMT_ITEM_PKIUSER || \
				itemType == KEYMGMT_ITEM_PUBLICKEY || \
				itemType == KEYMGMT_ITEM_REVOCATIONINFO );

	switch( itemType )
		{
		case KEYMGMT_ITEM_REQUEST:
			return( "SELECT certData FROM certRequests WHERE " );

		case KEYMGMT_ITEM_PKIUSER:
			return( "SELECT certData FROM pkiUsers WHERE " );

		case KEYMGMT_ITEM_PUBLICKEY:
			return( "SELECT certData FROM certificates WHERE " );

		case KEYMGMT_ITEM_REVOCATIONINFO:
			return( "SELECT certData FROM CRLs WHERE " );
		}

	retIntError_Null();
	}

/* Check an encoded certificate for a matching key usage.  The semantics of 
   key usage flags are vague in the sense that the query "Is this key valid 
   for X" is easily resolved but the query "Which key is appropriate for X" 
   is NP-hard due to the potential existence of unbounded numbers of
   certificates with usage semantics expressed in an arbitrary number of
   ways.  For now we distinguish between signing and encryption keys (this,
   at least, is feasible) by doing a quick check for keyUsage if we get
   multiple certificates with the same DN and choosing the one with the 
   appropriate key usage.

   Rather than performing a relatively expensive certificate import for each 
   certificate we find the keyUsage by doing an optimised search through the 
   certificate data for its encoded form.  The pattern that we look for is:

	OID				06 03 55 1D 0F + SEQUENCE at n-2
	BOOLEAN			(optional)
	OCTET STRING {
		BIT STRING	(value)

   Note that this function isn't security-critical because it doesn't perform
   an actual usage check, all it needs to do is find the key that's most 
   likely to be usable for purpose X.  If it gets it wrong the certificate-
   level checking will catch the problem */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN checkCertUsage( IN_BUFFER( certLength ) const BYTE *certificate, 
							   IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
								const int certLength,
							   IN_FLAGS( KEYMGMT ) const int requestedUsage )
	{
	const int keyUsageMask = ( requestedUsage & KEYMGMT_FLAG_USAGE_CRYPT ) ? \
								CRYPT_KEYUSAGE_KEYENCIPHERMENT : \
								CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
								CRYPT_KEYUSAGE_NONREPUDIATION;
	int i;

	assert( isReadPtr( certificate, certLength ) );
	
	REQUIRES( certLength >= MIN_CRYPT_OBJECTSIZE && \
			  certLength < MAX_INTLENGTH_SHORT );
	REQUIRES( requestedUsage > KEYMGMT_FLAG_NONE && \
			  requestedUsage < KEYMGMT_FLAG_MAX );
	REQUIRES( requestedUsage & KEYMGMT_MASK_USAGEOPTIONS );

	/* Scan the payload portion of the certificate for the keyUsage 
	   extension.  The certificate is laid out approximately as:

		[ junk ][ DN ][ times ][ DN ][ pubKey ][ attrs ][ sig ]

	   so we know there's at least 128 + MIN_PKCSIZE bytes at the start and
	   MIN_PKCSIZE bytes at the end that we don't have to bother poking 
	   around in */
	for( i = 128 + MIN_PKCSIZE; i < certLength - MIN_PKCSIZE; i++ )
		{
		STREAM stream;
		int keyUsage, status;

		/* Look for the OID.  This potentially skips two bytes at a time but 
		   this is safe because the preceding bytes can never contain either 
		   of these two values (they're 0x30 + 11...15) */
		if( certificate[ i++ ] != BER_OBJECT_IDENTIFIER || \
			certificate[ i++ ] != 3 )
			continue;
		if( certificate[ i - 4 ] != BER_SEQUENCE )
			continue;
		if( memcmp( certificate + i, "\x55\x1D\x0F", 3 ) )
			continue;
		i += 3;

		/* We've found the OID (with 2.8e-14 error probability), skip
		   the critical flag if necessary */
		if( certificate[ i ] == BER_BOOLEAN )
			i += 3;

		/* Read the OCTET STRING wrapper and BIT STRING */
		sMemConnect( &stream, certificate + i, 
					 certLength - ( i + MIN_PKCSIZE ) );
		readOctetStringHole( &stream, NULL, 4, DEFAULT_TAG );
		status = readBitString( &stream, &keyUsage );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			continue;

		/* Check whether the requested usage is allowed */
		return( ( keyUsage & keyUsageMask ) ? TRUE : FALSE );
		}

	/* No key usage found, assume that any usage is OK */
	return( TRUE );
	}

/****************************************************************************
*																			*
*							Database Fetch Routines							*
*																			*
****************************************************************************/

/* Fetch a sequence of certificates from a data source.  This is called in 
   one of two ways, either indirectly by the certificate code to fetch the 
   first and subsequent certificates in a chain or directly by the user 
   after submitting a query to the keyset (which doesn't return any data) 
   to read the results of the query.  The schema for calls is:

	state = NULL:		query( NULL, &data, CONTINUE );
	state, point query:	query( SQL, &data, NORMAL );
	state, multi-cert:	query( SQL, &data, START );
						( followed by 'query( NULL, &data, CONTINUE )') */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 9 ) ) \
int getItemData( INOUT DBMS_INFO *dbmsInfo, 
				 OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
				 OUT_OPT int *stateInfo, 
				 IN_ENUM_OPT( KEYMGMT_ITEM ) const KEYMGMT_ITEM_TYPE itemType, 
				 IN_KEYID_OPT const CRYPT_KEYID_TYPE keyIDtype, 
				 IN_BUFFER_OPT( keyValueLength ) const char *keyValue, 
				 IN_LENGTH_KEYID_Z const int keyValueLength,
				 IN_FLAGS_Z( KEYMGMT ) const int options,
				 INOUT ERROR_INFO *errorInfo )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	const DBMS_CACHEDQUERY_TYPE cachedQueryType = \
								getCachedQueryType( itemType, keyIDtype );
	BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
	BYTE certificate[ MAX_CERT_SIZE + 8 ];
	char sqlBuffer[ MAX_SQL_QUERY_SIZE + 8 ];
	const char *queryString;
	char certDataBuffer[ MAX_QUERY_RESULT_SIZE + 8 ];
	void *certDataPtr = hasBinaryBlobs( dbmsInfo ) ? \
						certificate : ( void * ) certDataBuffer;
						/* Cast needed for gcc */
	DBMS_QUERY_TYPE queryType;
	BOOLEAN multiCertQuery = ( options & KEYMGMT_MASK_USAGEOPTIONS ) ? \
							 TRUE : FALSE;
	int certDataLength = DUMMY_INIT, iterationCount, status;

	assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
	assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
	assert( ( stateInfo == NULL ) || \
			isWritePtr( stateInfo, sizeof( int ) ) );
	assert( ( keyValueLength > MIN_NAME_LENGTH && \
			  isReadPtr( keyValue, keyValueLength ) && \
			  ( keyIDtype > CRYPT_KEYID_NONE && \
				keyIDtype <= CRYPT_KEYID_LAST ) ) || \
			( keyValueLength == 0 && keyValue == NULL && \
			  keyIDtype == CRYPT_KEYID_NONE ) );

	REQUIRES( ( itemType == KEYMGMT_ITEM_NONE && \
				keyIDtype == CRYPT_KEYID_NONE && keyValue == NULL && \
				keyValueLength == 0 && stateInfo == NULL ) ||
			  /* This variant is for ongoing queries, for which information 
			     will have been submitted when the query was started */
			  ( itemType > KEYMGMT_ITEM_NONE && \

⌨️ 快捷键说明

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