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

📄 dbxdca.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						  cryptlib DBMS CA Interface						*
*						Copyright Peter Gutmann 1996-2003					*
*																			*
****************************************************************************/

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "keyset.h"
  #include "dbxdbx.h"
  #include "asn1_rw.h"
  #include "rpc.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../keyset/keyset.h"
  #include "../keyset/dbxdbx.h"
  #include "../misc/asn1_rw.h"
  #include "../misc/rpc.h"
#else
  #include "crypt.h"
  #include "keyset/keyset.h"
  #include "keyset/dbxdbx.h"
  #include "misc/asn1_rw.h"
  #include "misc/rpc.h"
#endif /* Compiler-specific includes */

#ifdef USE_DBMS

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

#if 0

/* Get the ultimate successor cert for one that has been superseded */

static int getSuccessorCert( DBMS_INFO *dbmsInfo,
							 CRYPT_CERTIFICATE *iCertificate,
							 const char *initialCertID )
	{
	char certID[ DBXKEYID_BUFFER_SIZE ];
	int status;

	/* Walk through the chain of renewals in the cert log until we find the
	   ultimate successor cert to the current one */
	strcpy( certID, initialCertID );
	do
		{
		BYTE keyCertID[ DBXKEYID_SIZE ];
		char sqlBuffer[ MAX_SQL_QUERY_SIZE ];
		char certData[ MAX_CERT_SIZE ];
		int certDataLength, dummy;

		/* Find the request to renew this certificate */
		dbmsFormatSQL( sqlBuffer,
			"SELECT certID FROM certLog WHERE subjCertID = '$' "
				"AND action = " TEXT_CERTACTION_REQUEST_RENEWAL,
					   certID );
		status = dbmsQuery( sqlBuffer, certData, &certDataLength, 0,
							DBMS_QUERY_NORMAL );
		if( cryptStatusError( status ) )
			return( status );

		/* Find the resulting certificate */
		memcpy( certID, certData,
				min( certDataLength, MAX_ENCODED_DBXKEYID_SIZE ) );
		dbmsFormatSQL( sqlBuffer,
			"SELECT certID FROM certLog WHERE reqCertID = '$' "
				"AND action = " TEXT_CERTACTION_CERT_CREATION,
					   certID );
		status = dbmsQuery( sqlBuffer, certData, &certDataLength, 0,
							DBMS_QUERY_NORMAL );
		if( cryptStatusError( status ) )
			return( status );
		base64decode( keyCertID, certData,
					  min( certDataLength, MAX_ENCODED_DBXKEYID_SIZE ),
					  CRYPT_CERTFORMAT_NONE );

		/* Try and get the replacement cert */
		status = getItemData( dbmsInfo, iCertificate, &dummy,
							  getKeyName( CRYPT_IKEYID_CERTID ), keyCertID,
							  KEYMGMT_ITEM_PUBLICKEY, KEYMGMT_FLAG_NONE );
		}
	while( status == CRYPT_ERROR_NOTFOUND );

	return( status );
	}
#endif /* 0 */

/* Get the PKI user that originally authorised the issuance of a cert.  This
   can involve chaining back through multiple generations of certificates, 
   for example to check authorisation on a revocation request we might have
   to go through:

	rev_req:	get reqCertID = update_req
	update_req:	get reqCertID = cert_req
	cert_req:	get reqCertID = init_req
	init_req:	get reqCertID = pki_user */

static int getIssuingUser( DBMS_INFO *dbmsInfo, CRYPT_CERTIFICATE *iPkiUser,
						   const char *initialCertID )
	{
	BYTE keyCertID[ DBXKEYID_SIZE ];
	char certID[ DBXKEYID_BUFFER_SIZE ];
	int chainingLevel, dummy, status;

	/* Walk through the chain of updates in the cert log until we find the
	   PKI user that authorised the first cert issue */
	strcpy( certID, initialCertID );
	for( chainingLevel = 0; chainingLevel < 25; chainingLevel++ )
		{
		char sqlBuffer[ MAX_SQL_QUERY_SIZE ];
		char certData[ MAX_CERT_SIZE ];
		int certDataLength;

		/* Find out whether this is a PKI user.  The comparison for the 
		   action type is a bit odd since some backends will return the 
		   action as text and some as a binary numeric value, rather than 
		   relying on the backend glue code to perform the appropriate 
		   conversion we just check for either value type */
		dbmsFormatSQL( sqlBuffer,
			"SELECT action FROM certLog WHERE certID = '$'",
					   certID );
		status = dbmsQuery( sqlBuffer, certData, &certDataLength, 0,
							DBMS_QUERY_NORMAL );
		if( cryptStatusError( status ) )
			return( status );
		if( certData[ 0 ] == CRYPT_CERTACTION_ADDUSER || \
			certData[ 0 ] == TEXTCH_CERTACTION_ADDUSER )
			{
			/* We've found the PKI user, extract the ID and exit */
			base64decode( keyCertID, certData,
						  min( certDataLength, MAX_ENCODED_DBXKEYID_SIZE ),
						  CRYPT_CERTFORMAT_NONE );
			break;
			}

		/* Find the certificate that was issued, recorded either as a 
		   CERTACTION_CERT_CREATION for a multi-phase CMP-based cert 
		   creation or a CERTACTION_ISSUE_CERT for a one-step creation */
		dbmsFormatSQL( sqlBuffer,
			"SELECT reqCertID FROM certLog WHERE certID = '$'",
					   certID );
		status = dbmsQuery( sqlBuffer, certData, &certDataLength, 0,
							DBMS_QUERY_NORMAL );
		if( cryptStatusError( status ) )
			return( status );
		memcpy( certID, certData,
				min( certDataLength, MAX_ENCODED_DBXKEYID_SIZE ) );

		/* Find the request to issue this certificate.  For a CMP-based issue
		   this will have an authorising object (found in the next iteration
		   through the loop), for a one-step issue it won't */
		dbmsFormatSQL( sqlBuffer,
			"SELECT reqCertID FROM certLog WHERE certID = '$'",
					   certID );
		status = dbmsQuery( sqlBuffer, certData, &certDataLength, 0,
							DBMS_QUERY_NORMAL );
		if( cryptStatusError( status ) )
			return( status );
		memcpy( certID, certData,
				min( certDataLength, MAX_ENCODED_DBXKEYID_SIZE ) );
		}

	/* If we've chained through too many entries, bail out */
	if( chainingLevel >= 25 )
		return( CRYPT_ERROR_FAILED );

	/* We've found the original PKI user, get the user info */
	return( getItemData( dbmsInfo, iPkiUser, &dummy,
						 getKeyName( CRYPT_IKEYID_CERTID ), certID,
						 KEYMGMT_ITEM_PKIUSER, KEYMGMT_FLAG_NONE ) );
	}

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

static int getNextPartialCert( DBMS_INFO *dbmsInfo,
							   CRYPT_CERTIFICATE *iCertificate,
							   BYTE *prevCertData, const BOOLEAN isRenewal )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	BYTE certificate[ MAX_CERT_SIZE ];
	char encodedCertData[ MAX_ENCODED_CERT_SIZE ];
	void *certPtr = hasBinaryBlobs( dbmsInfo ) ? \
					( void * ) certificate : encodedCertData;
	int certSize, status;

	*iCertificate = CRYPT_ERROR;

	/* Find the next cert and import it */
	status = dbmsQuery( isRenewal ? \
				"SELECT certData FROM certificates WHERE keyID LIKE '++%'" : \
				"SELECT certData FROM certificates WHERE keyID LIKE '--%'",
						certPtr, &certSize, 0, DBMS_QUERY_NORMAL );
	if( cryptStatusOK( status ) && !hasBinaryBlobs( dbmsInfo ) )
		{
		certSize = base64decode( certificate, encodedCertData, certSize,
								 CRYPT_CERTFORMAT_NONE );
		if( certSize <= 0 )
			status = CRYPT_ERROR_BADDATA;
		}
	if( cryptStatusError( status ) )
		return( status );

	/* If we're stuck in a loop fetching the same value over and over, make
	   an emergency exit */
	if( !memcmp( prevCertData, certificate, 128 ) )
		return( CRYPT_ERROR_DUPLICATE );
	memcpy( prevCertData, certificate, 128 );

	/* 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 ] = 0x30;
	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 );
	}

/****************************************************************************
*																			*
*								Logging Functions							*
*																			*
****************************************************************************/

/* Add an entry to the CA log */

int updateCertLog( DBMS_INFO *dbmsInfo, const int action, const char *certID, 
				   const char *reqCertID, const char *subjCertID, 
				   const void *data, const int dataLength,
				   const DBMS_UPDATE_TYPE updateType )
	{
	char sqlFormatBuffer[ MAX_SQL_QUERY_SIZE ];
	char sqlBuffer[ MAX_SQL_QUERY_SIZE ], actionString[ 5 ];
	char certIDbuffer[ DBXKEYID_BUFFER_SIZE ];
	char encodedCertData[ MAX_ENCODED_CERT_SIZE ];
	char *certIDptr = ( char * ) certID;
	const void *param1ptr, *param2ptr = "", *param3ptr = "";
	const time_t boundDate = getApproxTime();

	/* Build up the necessary SQL format string required to insert the log
	   entry.  This is complicated somewhat by the fact that some of the
	   values may be NULL, so we have to insert them by naming the columns
	   (some databases allow the use of the DEFAULT keyword but this isn't
	   standardised enough to be safe) */
	strcpy( sqlFormatBuffer,
			"INSERT INTO certLog (action, actionTime, certID" );
	if( reqCertID != NULL )
		strcat( sqlFormatBuffer, ", reqCertID" );
	if( subjCertID != NULL )
		strcat( sqlFormatBuffer, ", subjCertID" );
	if( data != NULL )
		strcat( sqlFormatBuffer, ", certData" );
	strcat( sqlFormatBuffer, ") VALUES ($, ?, '$'" );
	if( reqCertID != NULL )
		strcat( sqlFormatBuffer, ", '$'" );
	if( subjCertID != NULL )
		strcat( sqlFormatBuffer, ", '$'" );
	if( data != NULL )
		strcat( sqlFormatBuffer, hasBinaryBlobs( dbmsInfo ) ? ", ?" : ", '$'" );
	strcat( sqlFormatBuffer, ")" );

	/* Set up the appropriate parameter pointers to build the SQL command */
	if( reqCertID == NULL )
		{
		if( subjCertID == NULL )
			param1ptr = encodedCertData;
		else
			{
			param1ptr = subjCertID;
			param2ptr = encodedCertData;
			}
		}
	else
		{
		param1ptr = reqCertID;
		if( subjCertID == NULL )
			param2ptr = encodedCertData;
		else
			{
			param2ptr = subjCertID;
			param3ptr = encodedCertData;
			}
		}

	/* If we're not worried about the certID, we just insert a nonce value
	   which is used to meet the constraints for a unique entry.  In order
	   to ensure that it doesn't clash with a real certID, we set the first
	   four characters to an out-of-band value */
	if( certID == NULL )
		{
		RESOURCE_DATA msgData;
		BYTE nonce[ KEYID_SIZE ];
		int status;

		certIDptr = certIDbuffer;
		setMessageData( &msgData, nonce, KEYID_SIZE );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, 
								  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		if( cryptStatusError( status ) )
			return( status );
		base64encode( certIDptr, nonce, DBXKEYID_SIZE, CRYPT_CERTTYPE_NONE );
		certIDptr[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
		memset( certIDptr, '-', 4 );
		}

	/* Update the cert log */
	sPrintf( actionString, "%d", action );
	if( !hasBinaryBlobs( dbmsInfo ) )
		base64encode( encodedCertData, data, dataLength, CRYPT_CERTTYPE_NONE );
	dbmsFormatSQL( sqlBuffer, sqlFormatBuffer, actionString, certIDptr,
				   param1ptr, param2ptr, param3ptr );
	return( dbmsUpdate( sqlBuffer, hasBinaryBlobs( dbmsInfo ) ? \
						data : NULL, dataLength, boundDate, updateType ) );
	}

static int updateCertErrorLog( DBMS_INFO *dbmsInfo, const int errorStatus,
							   const char *errorString, const char *certID,
							   const char *reqCertID, const char *subjCertID,
							   const void *data, const int dataLength )
	{
	STREAM stream;
	BYTE errorData[ MAX_CERT_SIZE ];
	const int errorStringLength = strlen( errorString );
	int errorDataLength;

	assert( data == NULL );

	/* Encode the error information:
		SEQUENCE {
			errorStatus	INTEGER,
			errorString	UTF8String,
			certData	ANY OPTIONAL
			} */
	sMemOpen( &stream, errorData, MAX_CERT_SIZE );
	writeSequence( &stream, sizeofShortInteger( -errorStatus ) + \
							( int ) sizeofObject( errorStringLength ) );
	writeShortInteger( &stream, -errorStatus, DEFAULT_TAG );
	writeCharacterString( &stream, errorString, errorStringLength,
						  BER_STRING_UTF8 );
	errorDataLength = stell( &stream );
	sMemDisconnect( &stream );

	/* Update the cert log with the error information as the data value */
	return( updateCertLog( dbmsInfo, CRYPT_CERTACTION_ERROR, certID,
						   reqCertID, subjCertID, errorData,

⌨️ 快捷键说明

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