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

📄 ca_issue.c

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

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

#ifdef USE_DBMS

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

/* Get the issue type (new request, renewal, etc) for a particular 
   certificate request or certificate */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int getCertIssueType( INOUT DBMS_INFO *dbmsInfo,
							 IN_HANDLE const CRYPT_CERTIFICATE iCertificate,
							 OUT_ENUM_OPT( CERTADD ) CERTADD_TYPE *issueType,
							 const BOOLEAN isCert )
	{
	BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
	BYTE certData[ MAX_QUERY_RESULT_SIZE + 8 ];
	char certID[ ENCODED_DBXKEYID_SIZE + 8 ];
	int certIDlength, length, status;

	assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
	assert( isWritePtr( issueType, sizeof( CERTADD_TYPE ) ) );
	
	REQUIRES( isHandleRangeValid( iCertificate ) );

	/* Clear return value */
	*issueType = CERTADD_NONE;

	/* Get the certID of the request that resulted in the certificate 
	   creation */
	status = getKeyID( certID, ENCODED_DBXKEYID_SIZE, &certIDlength, 
					   iCertificate, CRYPT_CERTINFO_FINGERPRINT_SHA );
	if( cryptStatusOK( status ) && isCert )
		{
		/* If it's a certificate we have to apply an extra level of 
		   indirection to get the request that resulted in its creation */
		initBoundData( boundDataPtr );
		setBoundData( boundDataPtr, 0, certID, certIDlength );
		status = dbmsQuery(
			"SELECT reqCertID FROM certLog WHERE certID = ?",
							certData, MAX_QUERY_RESULT_SIZE, &length, 
							boundDataPtr, DBMS_CACHEDQUERY_NONE, 
							DBMS_QUERY_NORMAL );
		if( cryptStatusOK( status ) )
			{
			if( length > ENCODED_DBXKEYID_SIZE )
				length = ENCODED_DBXKEYID_SIZE;
			memcpy( certID, certData, length );
			certIDlength = length;
			}
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Find out whether this was a certificate update by checking whether it 
	   was added as a standard or renewal request, then set the update type
	   appropriately.  The comparison for the action type is a bit odd since
	   some back-ends will return the action as text and some as a binary
	   numeric value, rather than relying on the back-end glue code to
	   perform the appropriate conversion we just check for either value
	   type */
	initBoundData( boundDataPtr );
	setBoundData( boundDataPtr, 0, certID, certIDlength );
	status = dbmsQuery(
		"SELECT action FROM certLog WHERE certID = ?",
						certData, MAX_QUERY_RESULT_SIZE, &length, 
						boundDataPtr, DBMS_CACHEDQUERY_NONE, 
						DBMS_QUERY_NORMAL );
	if( cryptStatusError( status ) )
		return( status );
	switch( certData[ 0 ] )
		{
		case CRYPT_CERTACTION_REQUEST_CERT:
		case TEXTCH_CERTACTION_REQUEST_CERT:
			*issueType = CERTADD_PARTIAL;
			return( CRYPT_OK );

		case CRYPT_CERTACTION_REQUEST_RENEWAL:
		case TEXTCH_CERTACTION_REQUEST_RENEWAL:
			*issueType = CERTADD_PARTIAL_RENEWAL;
			return( CRYPT_OK );

		default:
			assert( DEBUG_WARN );
		}

	return( CRYPT_ERROR_NOTFOUND );
	}

/* Sanitise a new certificate of potentially dangerous attributes by 
   creating a template of the disallowed values and setting them as blocked 
   attributes.  For our use we clear all CA and CA-equivalent attributes to 
   prevent users from submitting requests that turn them into CAs */

CHECK_RETVAL \
static int sanitiseCertAttributes( IN_HANDLE const CRYPT_CERTIFICATE iCertificate )
	{
	CRYPT_CERTIFICATE iTemplateCertificate;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	int value, status;

	REQUIRES( isHandleRangeValid( iCertificate ) );

	setMessageCreateObjectInfo( &createInfo, CRYPT_CERTTYPE_CERTIFICATE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );
	iTemplateCertificate = createInfo.cryptHandle;

	/* Add as disallowed values the CA flag, CA-equivalent values (in this 
	   case the old Netscape usage flags, which (incredibly) are still used 
	   today by some CAs in place of the X.509 keyUsage extension), and the 
	   CA keyUsages */
	status = krnlSendMessage( iTemplateCertificate, IMESSAGE_SETATTRIBUTE,
							  MESSAGE_VALUE_TRUE, CRYPT_CERTINFO_CA );
	if( cryptStatusOK( status ) )
		{
		value = CRYPT_NS_CERTTYPE_SSLCA | CRYPT_NS_CERTTYPE_SMIMECA | \
				CRYPT_NS_CERTTYPE_OBJECTSIGNINGCA;
		status = krnlSendMessage( iTemplateCertificate, IMESSAGE_SETATTRIBUTE,
								  &value, CRYPT_CERTINFO_NS_CERTTYPE );
		}
	if( cryptStatusOK( status ) )
		{
		value = CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN;
		status = krnlSendMessage( iTemplateCertificate, IMESSAGE_SETATTRIBUTE,
								  &value, CRYPT_CERTINFO_KEYUSAGE );
		}
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCertificate, IMESSAGE_SETATTRIBUTE,
								  ( void * ) &iTemplateCertificate,
								  CRYPT_IATTRIBUTE_BLOCKEDATTRS );
	if( status == CRYPT_ERROR_INVALID )
		{
		/* If the request would have resulted in the creation of an invalid 
		   certificate, report it as an error with the request */
		status = CAMGMT_ARGERROR_REQUEST;
		}
	krnlSendNotifier( iTemplateCertificate, IMESSAGE_DECREFCOUNT );

	return( status );
	}

/* Make sure that an about-to-be-issued certificate hasn't been added to the 
   certificate store yet.  In theory we wouldn't need to do this since the 
   keyID uniqueness constraint will catch duplicates, however duplicates are 
   allowed for updates and won't automatically be caught for partial adds 
   because the keyID has to be added in a special form to enable the 
   completion of the partial add to work.  What we therefore need to check 
   for is that a partial add (which will add the keyID in special form) 
   won't in the future clash with a keyID in standard form.  The checking 
   for a keyID clash in special form happens automagically through the 
   uniqueness constraint.

   There are two special cases in which the issue can fail during the 
   completion rather than initial add phase, one is during an update (which 
   can't be avoided, since clashes are legal for this and we can't resolve 
   things until the completion phase) and the other is through a race 
   condition caused by the following sequence of updates:

	1: check keyID -> OK
	2: check keyID -> OK
	1: add as ESC1+keyID
	1: issue as keyID
	2: add as ESC1+keyID
	2: issue -> fails

   This condition will be fairly rare.  Note that in neither case are the 
   integrity constraints of the certificate issuing process violated, the 
   only thing that happens is that a failure due to duplicates is detected 
   at a later stage than it normally would be */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkDuplicateAdd( INOUT DBMS_INFO *dbmsInfo,
							  IN_HANDLE const CRYPT_CERTIFICATE iLocalCertificate, 
							  IN_ENUM( CERTADD ) const CERTADD_TYPE issueType )
	{
	BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
	char keyID[ ENCODED_DBXKEYID_SIZE + 8 ];
	int keyIDlength, status;

	assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
	
	REQUIRES( isHandleRangeValid( iLocalCertificate ) );
	REQUIRES( issueType > CERTADD_NONE && issueType < CERTADD_LAST );

	/* If it's a normal certificate issue then there's no problem with the
	   potential presence of pseudo-duplicates */
	if( issueType != CERTADD_PARTIAL )
		return( CRYPT_OK );

	/* Check whether a certificate with this keyID is already present in the 
	   store */
	status = getCertKeyID( keyID, ENCODED_DBXKEYID_SIZE, &keyIDlength, 
						   iLocalCertificate );
	if( cryptStatusError( status ) )
		return( status );
	initBoundData( boundDataPtr );
	setBoundData( boundDataPtr, 0, keyID, keyIDlength );
	status = dbmsQuery( \
				"SELECT certData FROM certificates WHERE keyID = ?",
						NULL, 0, NULL, boundDataPtr, 
						DBMS_CACHEDQUERY_NONE, DBMS_QUERY_CHECK );
	resetErrorInfo( dbmsInfo );
	return( cryptStatusOK( status ) ? CRYPT_ERROR_DUPLICATE : CRYPT_OK );
	}

/* Replace one certificate (usually a partially-issued one) with another 
   (usually its completed form).  The types of operations and their 
   corresponding add-type values are:

	ESC1 -> std		CERTADD_PARTIAL				Completion of partial
	ESC1 -> ESC2	CERTADD_PARTIAL_RENEWAL		First half of renewal
	ESC2 -> std		CERTADD_RENEWAL_COMPLETE	Second half of renewal */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int completeCert( INOUT DBMS_INFO *dbmsInfo,
						 IN_HANDLE const CRYPT_CERTIFICATE iCertificate,
						 IN_ENUM( CERTADD ) const CERTADD_TYPE addType,
						 INOUT ERROR_INFO *errorInfo )
	{
	BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
	char certID[ ENCODED_DBXKEYID_SIZE + 8 ];
	int certIDlength, status;

	assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
	
	REQUIRES( isHandleRangeValid( iCertificate ) );
	REQUIRES( addType == CERTADD_PARTIAL || \
			  addType == CERTADD_PARTIAL_RENEWAL || \
			  addType == CERTADD_RENEWAL_COMPLETE );
	REQUIRES( errorInfo != NULL );

	status = getKeyID( certID, ENCODED_DBXKEYID_SIZE, &certIDlength, 
					   iCertificate, CRYPT_CERTINFO_FINGERPRINT_SHA );
	if( cryptStatusError( status ) )
		return( status );
	status = addCert( dbmsInfo, iCertificate, CRYPT_CERTTYPE_CERTIFICATE,
					  ( addType == CERTADD_PARTIAL_RENEWAL ) ? \
						CERTADD_PARTIAL_RENEWAL : CERTADD_NORMAL,
					  DBMS_UPDATE_BEGIN, errorInfo );
	if( cryptStatusOK( status ) )
		{
		char specialCertID[ ENCODED_DBXKEYID_SIZE + 8 ];

		/* Turn the general certID into the form required for special-case
		   certificate data */
		memcpy( specialCertID, certID, certIDlength );
		memcpy( specialCertID,
				( addType == CERTADD_RENEWAL_COMPLETE ) ? \
				KEYID_ESC2 : KEYID_ESC1, KEYID_ESC_SIZE );
		initBoundData( boundDataPtr );
		setBoundData( boundDataPtr, 0, specialCertID, certIDlength );
		status = dbmsUpdate( 
			"DELETE FROM certificates WHERE certID = ?",
							 boundDataPtr,
							 ( addType == CERTADD_PARTIAL_RENEWAL ) ? \
							 DBMS_UPDATE_COMMIT : DBMS_UPDATE_CONTINUE );
		}
	if( cryptStatusOK( status ) )
		{
		if( addType != CERTADD_PARTIAL_RENEWAL )
			{
			status = updateCertLog( dbmsInfo,
									CRYPT_CERTACTION_CERT_CREATION_COMPLETE,
									NULL, 0, NULL, 0, certID, certIDlength, 
									NULL, 0, DBMS_UPDATE_COMMIT );
			}
		}
	else
		{
		/* Something went wrong, abort the transaction */
		dbmsUpdate( NULL, NULL, DBMS_UPDATE_ABORT );
		}

	/* If the operation failed, record the details */
	if( cryptStatusError( status ) )
		{
		updateCertErrorLog( dbmsInfo, status,
							"Certificate creation - completion operation "
							"failed", NULL, 0, NULL, 0, 
							certID, certIDlength, NULL, 0 );
		retExtErr( status, 
				   ( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
					 "Certificate creation - completion operation "
					 "failed: " ) );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Certificate Issue Functions						*
*																			*
****************************************************************************/

/* Complete a certificate renewal operation by revoking the certificate to 
   be replaced and replacing it with the newly-issued certificate */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int completeCertRenewal( INOUT DBMS_INFO *dbmsInfo,
						 IN_HANDLE const CRYPT_CERTIFICATE iReplaceCertificate,
						 INOUT ERROR_INFO *errorInfo )
	{
	CRYPT_CERTIFICATE iOrigCertificate = DUMMY_INIT;
	char keyID[ ENCODED_DBXKEYID_SIZE + 8 ];
	int keyIDlength, dummy, status;

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

	REQUIRES( isHandleRangeValid( iReplaceCertificate ) );
	REQUIRES( errorInfo != NULL );

	/* Extract the key ID from the new certificate and use it to fetch the 
	   existing certificate issued for the same key */
	status = getCertKeyID( keyID, ENCODED_DBXKEYID_SIZE, &keyIDlength, 

⌨️ 快捷键说明

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