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

📄 cryptcrt.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*					cryptlib Certificate Management Routines				*
*						Copyright Peter Gutmann 1996-2004					*
*																			*
****************************************************************************/

/* "By the power vested in me, I now declare this text string and this bit
	string 'name' and 'key'.  What RSA has joined, let no man put asunder".
											-- Bob Blakley */
#include <ctype.h>
#include "crypt.h"
#ifdef INC_ALL
  #include "cert.h"
  #include "asn1.h"
  #include "asn1_ext.h"
#else
  #include "cert/cert.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */

/* The minimum size for an OBJECT IDENTIFIER expressed as ASCII characters */

#define MIN_ASCII_OIDSIZE	7

#ifdef USE_CERTIFICATES

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

/* Compare values to data in a certificate */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN compareCertInfo( const CERT_INFO *certInfoPtr, 
								IN_ENUM( MESSAGE_COMPARE ) \
									const MESSAGE_COMPARE_TYPE compareType,
								IN_BUFFER_OPT( dataLength ) const void *data,
								IN_LENGTH_SHORT_Z const int dataLength,
								IN_HANDLE_OPT const CRYPT_CERTIFICATE iCryptCert )
	{
	int status;

	assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( ( data == NULL && dataLength == 0 ) || \
			isReadPtr( data, dataLength ) );

	REQUIRES_B( compareType > MESSAGE_COMPARE_NONE && \
				compareType < MESSAGE_COMPARE_LAST );
	REQUIRES_B( ( data == NULL && dataLength == 0 && \
				  isHandleRangeValid( iCryptCert ) ) || \
				( data != NULL && \
				  dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT && \
				  iCryptCert == CRYPT_UNUSED ) );

	switch( compareType )
		{
		case MESSAGE_COMPARE_SUBJECT:
			if( dataLength != certInfoPtr->subjectDNsize || \
				memcmp( data, certInfoPtr->subjectDNptr,
						certInfoPtr->subjectDNsize ) )
				return( FALSE );
			return( TRUE );

		case MESSAGE_COMPARE_ISSUERANDSERIALNUMBER:
			{
			STREAM stream;
			void *dataPtr = DUMMY_INIT_PTR;
			int dataLeft = DUMMY_INIT, serialNoLength, length;

			if( certInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
				certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN )
				return( FALSE );

			/* Comparing an iAndS can get quite tricky because of assorted 
			   braindamage in encoding methods so that two dissimilar 
			   iAndSs aren't necessarily supposed to be regarded as non-
			   equal.  First we try a trivial reject check, if that passes 
			   we compare the issuerName and serialNumber with corrections 
			   for common encoding braindamage.  Note that even this 
			   comparison can fail since older versions of the Entegrity 
			   toolkit rewrote T61Strings in certificates as 
			   PrintableStrings in recipientInfo which means that any kind 
			   of straight comparison on these would fail.  We don't bother 
			   handling this sort of thing,and it's likely that most other 
			   software won't either (this situation only occurs when a 
			   certificate issuerName contains PrintableString text 
			   incorrectly encoded as T61String, which is rare enough that 
			   it required artifically-created certificates just to 
			   reproduce the problem).  In addition the trivial reject check 
			   can also fail since in an extreme encoding braindamage case a 
			   BMPString rewritten as a PrintableString would experience a 
			   large enough change in length to fail the check, but as with 
			   the Entegrity problem this is a level of brokenness up with 
			   which we will not put */
			length = ( int ) sizeofObject( \
						certInfoPtr->issuerDNsize + \
						sizeofObject( certInfoPtr->cCertCert->serialNumberLength ) );
			if( length < dataLength - 2 || length > dataLength + 2 )
				{
				/* Trivial reject, the lengths are too dissimilar for any 
				   fixup attempts to work */
				return( FALSE );
				}

			/* We also disallow obviously-invalid lengths at this point to 
			   ensure that we don't try and do anything with invalid data */
			if( length < 16 || length > MAX_INTLENGTH_SHORT || \
				dataLength < 16 || dataLength > MAX_INTLENGTH_SHORT )
				return( FALSE );

			/* We got past the trivial reject check, try a more detailed check, 
			   first the issuerName */
			sMemConnect( &stream, data, dataLength );
			status = readSequence( &stream, NULL );
			if( cryptStatusOK( status ) )
				{
				dataLeft = dataLength - stell( &stream );
				status = sMemGetDataBlock( &stream, &dataPtr, dataLeft );
				}
			if( cryptStatusOK( status ) )			
				status = getObjectLength( dataPtr, dataLeft, &length );
			if( cryptStatusOK( status ) )			
				status = readUniversal( &stream );
			if( cryptStatusError( status ) || \
				length != certInfoPtr->issuerDNsize || \
				memcmp( dataPtr, certInfoPtr->issuerDNptr,
						certInfoPtr->issuerDNsize ) )
				{
				sMemDisconnect( &stream );
				return( FALSE );
				}

			/* Compare the serialNumber */
			status = readGenericHole( &stream, &serialNoLength, 1, 
									  BER_INTEGER );
			if( cryptStatusOK( status ) )
				{
				dataLeft = dataLength - stell( &stream );
				status = sMemGetDataBlock( &stream, &dataPtr, dataLeft );
				}
			if( cryptStatusOK( status ) )			
				status = sSkip( &stream, serialNoLength );
			sMemDisconnect( &stream );
			if( cryptStatusError( status ) )
				return( FALSE );
			if( !compareSerialNumber( certInfoPtr->cCertCert->serialNumber,
									  certInfoPtr->cCertCert->serialNumberLength,
									  dataPtr, serialNoLength ) )
				return( FALSE );

			return( TRUE );
			}

		case MESSAGE_COMPARE_FINGERPRINT:
		case MESSAGE_COMPARE_CERTOBJ:
			{
			MESSAGE_DATA msgData;
			BYTE fingerPrint[ CRYPT_MAX_HASHSIZE + 8 ];
			int fingerPrintLength;

			/* If the certificate hasn't been signed yet we can't compare 
			   the fingerprint */
			if( certInfoPtr->certificate == NULL )
				return( FALSE );
			
			/* Get the certificate fingerprint and compare it to what we've 
			   been given */
			status = getCertComponent( ( CERT_INFO * ) certInfoPtr, 
									   CRYPT_CERTINFO_FINGERPRINT_SHA,
									   fingerPrint, CRYPT_MAX_HASHSIZE, 
									   &fingerPrintLength );
			if( cryptStatusError( status ) )
				return( FALSE );

			/* If it's a straight fingerprint compare, compare the 
			   certificate fingerprint to the user-supplied value */
			if( compareType == MESSAGE_COMPARE_FINGERPRINT )
				{
				return( ( dataLength == fingerPrintLength && \
						  !memcmp( data, fingerPrint, fingerPrintLength ) ) ? \
						TRUE : FALSE );
				}

			/* It's a full certificate compare, compare the encoded 
			   certificate data via the fingerprints */
			setMessageData( &msgData, fingerPrint, fingerPrintLength );
			status = krnlSendMessage( iCryptCert, IMESSAGE_COMPARE, &msgData,
									  MESSAGE_COMPARE_FINGERPRINT );
			return( cryptStatusOK( status ) ? TRUE : FALSE );
			}
		}

	retIntError_Boolean();
	}

/* Check the usage of a certificate against a MESSAGE_CHECK_TYPE check */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkCertUsage( INOUT CERT_INFO *certInfoPtr, 
						   IN_ENUM( MESSAGE_CHECK ) \
							const MESSAGE_CHECK_TYPE checkType )
	{
	int complianceLevel, keyUsageValue, checkKeyFlag = CHECKKEY_FLAG_NONE;
	int status;

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

	REQUIRES( checkType > MESSAGE_CHECK_NONE && \
			  checkType < MESSAGE_CHECK_LAST );

	/* Map the check type to a key usage that we check for */
	switch( checkType )
		{
		case MESSAGE_CHECK_PKC_PRIVATE:
			/* This check type can be encountered when checking a private 
			   key with a certificate attached */
			keyUsageValue = CRYPT_KEYUSAGE_NONE;
			checkKeyFlag = CHECKKEY_FLAG_PRIVATEKEY;
			break;

		case MESSAGE_CHECK_PKC_ENCRYPT:
		case MESSAGE_CHECK_PKC_ENCRYPT_AVAIL:
			keyUsageValue = CRYPT_KEYUSAGE_KEYENCIPHERMENT;
			break;

		case MESSAGE_CHECK_PKC_DECRYPT:
		case MESSAGE_CHECK_PKC_DECRYPT_AVAIL:
			keyUsageValue = CRYPT_KEYUSAGE_KEYENCIPHERMENT;
			checkKeyFlag = CHECKKEY_FLAG_PRIVATEKEY;
			break;

		case MESSAGE_CHECK_PKC_SIGN:
		case MESSAGE_CHECK_PKC_SIGN_AVAIL:
			keyUsageValue = CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
							CRYPT_KEYUSAGE_NONREPUDIATION | \
							CRYPT_KEYUSAGE_KEYCERTSIGN | \
							CRYPT_KEYUSAGE_CRLSIGN;
			checkKeyFlag = CHECKKEY_FLAG_PRIVATEKEY;
			break;

		case MESSAGE_CHECK_PKC_SIGCHECK:
		case MESSAGE_CHECK_PKC_SIGCHECK_AVAIL:
			keyUsageValue = CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
							CRYPT_KEYUSAGE_NONREPUDIATION | \
							CRYPT_KEYUSAGE_KEYCERTSIGN | \
							CRYPT_KEYUSAGE_CRLSIGN;
			break;

		case MESSAGE_CHECK_PKC_KA_EXPORT:
		case MESSAGE_CHECK_PKC_KA_EXPORT_AVAIL:
			/* exportOnly usage falls back to plain keyAgreement if 
			   necessary */
			keyUsageValue = CRYPT_KEYUSAGE_KEYAGREEMENT | \
							CRYPT_KEYUSAGE_ENCIPHERONLY;
			break;

		case MESSAGE_CHECK_PKC_KA_IMPORT:
		case MESSAGE_CHECK_PKC_KA_IMPORT_AVAIL:
			/* importOnly usage falls back to plain keyAgreement if 
			   necessary */
			keyUsageValue = CRYPT_KEYUSAGE_KEYAGREEMENT | \
							CRYPT_KEYUSAGE_DECIPHERONLY;
			break;

		case MESSAGE_CHECK_CA:
		case MESSAGE_CHECK_CACERT:
			/* A special-case version of MESSAGE_CHECK_PKC_SIGN/
			   MESSAGE_CHECK_PKC_SIGCHECK that applies only to 
			   certificates */
			keyUsageValue = CRYPT_KEYUSAGE_KEYCERTSIGN;
			checkKeyFlag = CHECKKEY_FLAG_CA;
			break;
			
		case MESSAGE_CHECK_PKC:
			/* If we're just checking for generic PKC functionality then 
			   any kind of usage is OK */
			return( CRYPT_OK );

		default:
			retIntError();
		}
	ENSURES( keyUsageValue != CRYPT_KEYUSAGE_NONE || \
			 checkKeyFlag != CHECKKEY_FLAG_NONE );

	/* Certificate requests are special-case objects in that the key they 
	   contain is usable only for signature checking of the self-signature 
	   on the object (it can't be used for general-purpose usages, which 
	   would make it equivalent to a trusted self-signed certificate).  This 
	   is problematic because the keyUsage may indicate that the key is 
	   valid for other things as well, or not valid for signature checking.  
	   To get around this we indicate that the key has a single trusted 
	   usage, signature checking, and disallow any other usage regardless of 
	   what the keyUsage says.  The actual keyUsage usage is only valid once 
	   the request has been converted into a certificate */
	if( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
		certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
		{
		if( checkType == MESSAGE_CHECK_PKC_SIGCHECK || \
			checkType == MESSAGE_CHECK_PKC_SIGCHECK_AVAIL )
			return( CRYPT_OK );
		setErrorInfo( certInfoPtr, CRYPT_CERTINFO_TRUSTED_USAGE, 
					  CRYPT_ERRTYPE_CONSTRAINT );
		return( CRYPT_ERROR_INVALID );
		}

	/* Only certificate objects with associated public keys are valid for 
	   check messages (which are checking the capabilities of the key) */
	REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
			  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
			  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );

	/* Certificate collections are pure container objects for which the base 
	   certificate object doesn't correspond to an actual certificate */
	REQUIRES( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) );

	/* Check the key usage for the certificate */
	status = krnlSendMessage( certInfoPtr->ownerHandle, 
							  IMESSAGE_GETATTRIBUTE, &complianceLevel, 
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		return( status );
	status = checkKeyUsage( certInfoPtr, checkKeyFlag, keyUsageValue, 
							complianceLevel, &certInfoPtr->errorLocus, 
							&certInfoPtr->errorType );
	if( cryptStatusError( status ) )
		{
		/* Convert the status value to the correct form */
		return( CRYPT_ARGERROR_OBJECT );
		}

	return( CRYPT_OK );
	}

/* Export the certificate's data contents in ASN.1-encoded form */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static int exportCertData( CERT_INFO *certInfoPtr, 
						   IN_ENUM( CRYPT_CERTFORMAT ) \
							const CRYPT_CERTFORMAT_TYPE certFormat,
						   OUT_BUFFER_OPT( certDataMaxLength, *certDataLength ) \
							void *certData,
						   IN_LENGTH_Z const int certDataMaxLength,
						   OUT_LENGTH_Z int *certDataLength )
	{
	int status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
	assert( ( certData == NULL && certDataMaxLength == 0 ) || \
			isWritePtr( certData, certDataMaxLength ) );
	assert( isWritePtr( certDataLength, sizeof( int ) ) );

	REQUIRES( certFormat > CRYPT_CERTFORMAT_NONE && \
			  certFormat < CRYPT_CERTFORMAT_LAST );
	REQUIRES( ( certData == NULL && certDataMaxLength == 0 ) || \
			  ( certData != NULL && \
				certDataMaxLength > 0 && \
				certDataMaxLength < MAX_INTLENGTH ) );

	/* Clear return value */
	*certDataLength = 0;

	/* Unsigned object types like CMS attributes aren't signed like other 
	   certificate objects so they aren't pre-encoded when we sign them and 
	   have the potential to change on each use if the same CMS attributes 
	   are reused for multiple signatures.  Because of this we write them 
	   out on export rather than copying the pre-encoded form from an 
	   internal buffer */
	if( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES )
		{
		WRITECERT_FUNCTION writeCertFunction;
		STREAM stream;

		REQUIRES( certFormat == CRYPT_ICERTFORMAT_DATA );

		writeCertFunction = \

⌨️ 快捷键说明

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