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

📄 lib_sign.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*							cryptlib Signature Routines						*
*						Copyright Peter Gutmann 1993-2002					*
*																			*
****************************************************************************/

#include <string.h>
#include <stdlib.h>
#include "crypt.h"
#ifdef INC_ALL
  #include "asn1.h"
  #include "asn1objs.h"
  #include "asn1oid.h"
#else
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1objs.h"
  #include "keymgmt/asn1oid.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*							Low-level Signature Functions 					*
*																			*
****************************************************************************/

/* Generic signature creation and checking functions.  In theory these
   could be handled via messages with parameters ( signature, signContext, 
   hashContext, type ) with operations dev_sign + writeSig() or readSig() + 
   dev_sigcheck, however it's unclear at what level of abstraction these 
   messages operate since they're above the level of the crypto mechanisms 
   provided by device objects.  In addition there's nothing much the kernel
   can do with the message except pass it straight through (all the security 
   checks take place at a much lower level and the only possible target for 
   the message is the system object) so there's not much point in handling
   these operations as messages.  Because of this they're currently 
   implemented as functions called from higher-level functions within this 
   module, with two external wrapper points for X.509 and raw signatures */

static int createSignature( void *signature, int *signatureLength,
							const CRYPT_CONTEXT iSignContext,
							const CRYPT_CONTEXT iHashContext,
							const SIGNATURE_TYPE signatureType )
	{
	CRYPT_ALGO signAlgo, hashAlgo;
	MECHANISM_SIGN_INFO mechanismInfo;
	BYTE signatureData[ CRYPT_MAX_PKCSIZE ];
	int length, status;

	/* Extract general information */
	status = krnlSendMessage( iSignContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
							  &signAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE, 
								  &hashAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're just doing a length check, write dummy data to a null stream
	   and return its length */
	if( signature == NULL )
		{
 		STREAM nullStream;

		assert( signatureType != SIGNATURE_PGP );

		/* Determine how long the signature will be.  In the case of the DLP-
		   based PKC's written in cryptlib format it's just an estimate since 
		   it can change by up to two bytes depending on whether the 
		   signature values have the high bit set or not, which requires 
		   zero-padding of the ASN.1-encoded integers.  This is rather nasty 
		   because it means we can't tell how large a signature will be 
		   without actually creating it.

		   The 6/10 bytes at the start are for the ASN.1 SEQUENCE and 2 * 
		   INTEGER encoding */
		if( signAlgo == CRYPT_ALGO_DSA )
			length = ( signatureType == SIGNATURE_PGP ) ? \
					 2 * 20 : 6 + ( 2 * ( 20 + 1 ) );	/* 20 = SHA hash size */
		else
			{
			/* Calculate the eventual signature size */
			setMechanismSignInfo( &mechanismInfo, NULL, 0, iHashContext, 
								  iSignContext );
			status = krnlSendMessage( iSignContext, RESOURCE_IMESSAGE_DEV_SIGN, 
									  &mechanismInfo, MECHANISM_PKCS1 );
			length = mechanismInfo.signatureLength;
			clearMechanismInfo( &mechanismInfo );
			if( cryptStatusError( status ) )
				return( status );
			}

		/* Write the data to a null stream to determine its size */
		sMemOpen( &nullStream, NULL, 0 );
		status = writeSignature( &nullStream, iSignContext, hashAlgo, 
								 signAlgo, signatureData, length, 
								 signatureType );
		*signatureLength = ( int ) stell( &nullStream );
		sMemClose( &nullStream );

		return( status );
		}

	/* DLP signatures are handled somewhat specially */
	if( isDlpAlgo( signAlgo ) )
		{
		DLP_PARAMS dlpParams;
		RESOURCE_DATA msgData;
		BYTE hash[ CRYPT_MAX_HASHSIZE ];

		/* Extract the hash value from the context */
		setResourceData( &msgData, hash, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CTXINFO_HASHVALUE );
		if( cryptStatusError( status ) )
			return( status );

		/* DSA is only defined for hash algorithms with a block size of 160
		   bits */
		if( msgData.length != 20 )
			return( CRYPT_ARGERROR_NUM1 );

		/* Sign the data */
		setDLPParams( &dlpParams, hash, 20, signatureData, CRYPT_MAX_PKCSIZE );
		if( signatureType == SIGNATURE_PGP )
			dlpParams.formatType = CRYPT_FORMAT_PGP;			
		status = krnlSendMessage( iSignContext, RESOURCE_IMESSAGE_CTX_SIGN, 
								  &dlpParams, sizeof( DLP_PARAMS ) );
		length = dlpParams.outLen;
		}
	else
		{
		setMechanismSignInfo( &mechanismInfo, signatureData, CRYPT_MAX_PKCSIZE,
							  iHashContext, iSignContext );
		status = krnlSendMessage( iSignContext, RESOURCE_IMESSAGE_DEV_SIGN, 
								  &mechanismInfo, MECHANISM_PKCS1 );
		length = mechanismInfo.signatureLength;
		clearMechanismInfo( &mechanismInfo );
		}

	/* Write the signature record to the output */
	if( cryptStatusOK( status ) )
		{
		STREAM stream;

		sMemOpen( &stream, signature, STREAMSIZE_UNKNOWN );
		status = writeSignature( &stream, iSignContext, hashAlgo, 
								 signAlgo, signatureData, length, 
								 signatureType );
		*signatureLength = ( int ) stell( &stream );
		sMemDisconnect( &stream );
		}

	/* Clean up */
	zeroise( signatureData, CRYPT_MAX_PKCSIZE );
	return( status );
	}

static int checkSignature( const void *signature, const int signatureLength,
						   const CRYPT_CONTEXT iSigCheckContext,
						   const CRYPT_CONTEXT iHashContext,
						   const SIGNATURE_TYPE signatureType )
	{
	CRYPT_ALGO signAlgo, hashAlgo;
	MECHANISM_SIGN_INFO mechanismInfo;
	QUERY_INFO signatureInfo;
	STREAM stream;
	SIGNATURE_TYPE sigType = signatureType;
	void *signatureData;
	int signatureDataLength, status;

	/* Extract general information */
	status = krnlSendMessage( iSigCheckContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
							  &signAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE, 
								  &hashAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the signature record up to the start of the signature itself and
	   make sure we've been given the correct hash algorithm.  Raw 
	   signatures specify the algorithm at the start of the signed data 
	   rather than in the signature algorithm OID, so the check is done 
	   elsewhere */
	sMemConnect( &stream, signature, signatureLength );
	status = readSignature( &stream, &signatureInfo, sigType, signAlgo );
	sMemDisconnect( &stream );
	if( cryptStatusOK( status ) && \
		sigType != SIGNATURE_RAW && sigType != SIGNATURE_PGP && \
		hashAlgo != signatureInfo.hashAlgo )
		status = CRYPT_ERROR_SIGNATURE;
	if( cryptStatusError( status ) )
		{
		zeroise( &signatureInfo, sizeof( QUERY_INFO ) );
		return( status );
		}

	/* Make sure we've been given the correct key if the signature format
	   supports this type of check.  SIGNATURE_CMS supports a check with 
	   RESOURCE_MESSAGE_COMPARE_ISSUERANDSERIALNUMBER but this has already
	   been done while procesing the other CMS data before we were called
	   so we don't need to do it again */
	if( sigType == SIGNATURE_CRYPTLIB )
		{
		RESOURCE_DATA msgData;

		setResourceData( &msgData, signatureInfo.keyID, 
						 signatureInfo.keyIDlength );
		if( krnlSendMessage( iSigCheckContext, RESOURCE_IMESSAGE_COMPARE,
							 &msgData, RESOURCE_MESSAGE_COMPARE_KEYID ) != CRYPT_OK )
			{
			zeroise( &signatureInfo, sizeof( QUERY_INFO ) );
			return( CRYPT_ERROR_WRONGKEY );
			}
		}
	signatureData = signatureInfo.dataStart;
	signatureDataLength = signatureInfo.dataLength;
	zeroise( &signatureInfo, sizeof( QUERY_INFO ) );

	/* DLP signatures are handled somewhat specially */
	if( isDlpAlgo( signAlgo ) )
		{
		DLP_PARAMS dlpParams;
		RESOURCE_DATA msgData;
		BYTE hash[ CRYPT_MAX_HASHSIZE ];

		/* Extract the hash value from the context */
		setResourceData( &msgData, hash, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CTXINFO_HASHVALUE );
		if( cryptStatusError( status ) )
			return( status );

		/* DSA is only defined for hash algorithms with a block size of 160 
		   bits */
		if( msgData.length != 20 )
			return( CRYPT_ARGERROR_NUM1 );

		/* Check the signature validity using the encoded signature data and
		   hash */
		setDLPParams( &dlpParams, hash, 20, NULL, 0 );
		dlpParams.inParam2 = signatureData;
		dlpParams.inLen2 = signatureDataLength;
		if( sigType == SIGNATURE_PGP )
			dlpParams.formatType = CRYPT_FORMAT_PGP;
		status = krnlSendMessage( iSigCheckContext, 
								  RESOURCE_IMESSAGE_CTX_SIGCHECK,
								  &dlpParams, sizeof( DLP_PARAMS ) );
		}
	else
		{
		setMechanismSignInfo( &mechanismInfo, signatureData, 
							  signatureDataLength, iHashContext, 
							  iSigCheckContext );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
								  RESOURCE_IMESSAGE_DEV_SIGCHECK, 
								  &mechanismInfo, MECHANISM_PKCS1 );
		clearMechanismInfo( &mechanismInfo );
		}

	return( status );
	}

/****************************************************************************
*																			*
*							X.509-style Signature Functions 				*
*																			*
****************************************************************************/

/* Create/check an X.509-style signature.  These work with objects of the
   form:

	signedObject ::= SEQUENCE {
		object				ANY,
		signatureAlgorithm	AlgorithmIdentifier,
		signature			BIT STRING
		} */

int createX509signature( void *signedObject, int *signedObjectLength,
						 const void *object, const int objectLength,
						 CRYPT_CONTEXT signContext, const CRYPT_ALGO hashAlgo )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
#if INT_MAX > 32767
	const BOOLEAN largeObject = ( objectLength > 64500 ) ? TRUE : FALSE;
	int startOffset = largeObject ? 5 : 4;
#else
	int startOffset = 4;
#endif /* 32-bit ints */
	BYTE *payloadStart = ( BYTE * ) signedObject + startOffset;
	int signatureLength, delta, status;

	/* Hash the data to be signed */
	setMessageCreateObjectInfo( &createInfo, hashAlgo );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
							  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	krnlSendMessage( createInfo.cryptHandle, RESOURCE_IMESSAGE_CTX_HASH, 
					 ( void * ) object, objectLength );
	krnlSendMessage( createInfo.cryptHandle, RESOURCE_IMESSAGE_CTX_HASH, 
					 ( void * ) object, 0 );

	/* Create the wrapped-up signed object.  This gets somewhat ugly because
	   the only way we can find out how long the signature will be is by
	   actually creating it, since the ASN.1 encoding constraints mean the
	   size can vary by a few bytes depending on what values the integers
	   which make up the signature take.  Because of this, we first generate
	   the signature a reasonable distance back from the start of the buffer,
	   write the header and data to sign at the start, and finally move the
	   signature down to the end of the header if required.  startOffset is
	   the initial estimate of the length of the encapsulating SEQUENCE and
	   covers a payload length of 256-64K bytes, delta is the difference
	   between the estimate and the actual size which we later need to 
	   correct for.  Since the combination of data to sign and signature are 
	   virtually always in the range 256-64K bytes, the data move is almost 
	   never performed */
	status = createSignature( payloadStart + objectLength, &signatureLength, 
							  signContext, createInfo.cryptHandle, 
							  SIGNATURE_X509 );

⌨️ 快捷键说明

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