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

📄 sign.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
		{
		setMechanismSignInfo( &mechanismInfo, signatureData, 
							  signatureDataLength, iHashContext, 
							  iHashContext2, iSigCheckContext );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
								  IMESSAGE_DEV_SIGCHECK, &mechanismInfo, 
								  ( signatureType == SIGNATURE_SSL ) ? \
									MECHANISM_SIG_SSL : \
									MECHANISM_SIG_PKCS1 );
		if( cryptStatusError( status ) )
			/* The mechanism messages place the acted-on object (in this case 
			   the hash context) first while the higher-level functions place 
			   the signature context next to the signature data, in other 
			   words before the hash context.  Because of this we have to 
			   reverse parameter error values when translating from the 
			   mechanism to the signature function level */
			status = ( status == CRYPT_ARGERROR_NUM1 ) ? \
						CRYPT_ARGERROR_NUM2 : \
					 ( status == CRYPT_ARGERROR_NUM2 ) ? \
						CRYPT_ARGERROR_NUM1 : status;

		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
		}

   This is complicated by a variety of b0rken PKI protocols that couldn't
   quite manage a cut & paste of two lines of text, adding all sorts of 
   unnecessary extra tagging and wrappers to the signature.  To handle the
   tagging and presence of extra data, we allow two extra parameters, a 
   tag/wrapper formatting info specifier and an extra data length value (with
   the data being appended by the caller).  If the tag/wrapper is a small
   integer value, it's treated as [n] { ... }; if it has the 7th bit set 
   (0x80), it's treated as [n] { SEQUENCE { ... }} */

int createX509signature( void *signedObject, int *signedObjectLength,
						 const int sigMaxLength,
						 const void *object, const int objectLength,
						 const CRYPT_CONTEXT signContext, 
						 const CRYPT_ALGO_TYPE hashAlgo,
						 const int formatInfo, const int extraDataLength )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
#if INT_MAX > 32767
	int startOffset = ( objectLength > 64500 ) ? 5 : 4;
#else
	int startOffset = 4;
#endif /* 32-bit ints */
	BYTE *payloadStart = ( BYTE * ) signedObject + startOffset;
	int sigWrapperSize = ( formatInfo == CRYPT_UNUSED ) ? 0 : 16;
	int signatureLength, totalSigLength, delta, status;

	/* Hash the data to be signed */
	setMessageCreateObjectInfo( &createInfo, hashAlgo );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH, 
					 ( void * ) object, objectLength );
	krnlSendMessage( createInfo.cryptHandle, 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 that 
	   the size can vary by a few bytes depending on what values the integers
	   that 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 that 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:

		 startOfs			objLength		sigLength
			v					v				v
		+---+-------------------+-------+-------+
		|	|		object		|wrapper|  sig	|
		+---+-------------------+-------+-------+
			|							^
		payloadStart			  sigWrapperSize */
	status = createSignature( payloadStart + objectLength + sigWrapperSize, 
							  &signatureLength, 
							  sigMaxLength - ( startOffset + objectLength + \
											   sigWrapperSize ), 
							  signContext, createInfo.cryptHandle, 
							  CRYPT_UNUSED, SIGNATURE_X509 );
	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		return( status );
	if( formatInfo == CRYPT_UNUSED )
		totalSigLength = signatureLength + extraDataLength;
	else
		if( !( formatInfo & 0x80 ) )
			totalSigLength = ( int ) \
				sizeofObject( signatureLength + extraDataLength );
		else
			totalSigLength = ( int ) \
				sizeofObject( sizeofObject( signatureLength + extraDataLength ) );
	sMemOpen( &stream, signedObject, startOffset );
	writeSequence( &stream, objectLength + totalSigLength );
	delta = startOffset - stell( &stream );
	sMemDisconnect( &stream );
	if( delta > 0 )
		{
		payloadStart -= delta;
		startOffset -= delta;
		}
	memcpy( payloadStart, object, objectLength );
	if( sigWrapperSize > 0 )
		{
		const int oldSigWrapperSize = sigWrapperSize;

		sMemOpen( &stream, payloadStart + objectLength, sigWrapperSize );
		if( !( formatInfo & 0x80 ) )
			writeConstructed( &stream, signatureLength + extraDataLength, 
							  formatInfo );
		else
			{
			writeConstructed( &stream, 
						sizeofObject( signatureLength + extraDataLength ), 
						formatInfo & 0x7F );
			writeSequence( &stream, signatureLength + extraDataLength );
			}
		sigWrapperSize = stell( &stream );
		sMemDisconnect( &stream );
		memmove( payloadStart + objectLength + sigWrapperSize,
				 payloadStart + objectLength + oldSigWrapperSize,
				 signatureLength );
		}
	if( delta > 0 )
		memmove( payloadStart + objectLength, 
				 payloadStart + delta + objectLength, 
				 sigWrapperSize + signatureLength );
	*signedObjectLength = startOffset + objectLength + sigWrapperSize + \
						  signatureLength;

	return( status );
	}

int checkX509signature( const void *signedObject, const int signedObjectLength,
						void **object, int *objectLength, 
						const CRYPT_CONTEXT sigCheckContext,
						const int formatInfo )
	{
	CRYPT_ALGO_TYPE signAlgo, sigCheckAlgo, hashAlgo;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
	void *objectPtr, *sigPtr;
	int status, length, signatureLength;

	/* Check the start of the object and record the start and size of the 
	   encapsulated signed object, with special handling for unsually long
	   data in mega-CRLs.  The use of the length from readSequence() is safe 
	   here because the data has to be DER if it's signed */
	sMemConnect( &stream, signedObject, signedObjectLength );
#if INT_MAX > 32767
	readLongSequence( &stream, NULL );
#else
	readSequence( &stream, NULL );
#endif /* Non-16-bit systems */
	objectPtr = sMemBufPtr( &stream );
#if INT_MAX > 32767
	if( signedObjectLength >= 32767 )
		{
		long longLength;

		status = readLongSequence( &stream, &longLength );
		if( cryptStatusOK( status ) )
			{
			/* If it's an (invalid) indefinite-length encoding we can't do 
			   anything with it */
			if( longLength == CRYPT_UNUSED )
				status = CRYPT_ERROR_BADDATA;
			else
				length = ( int ) longLength;
			}
		}
	else
#endif /* Non-16-bit systems */
		status = readSequence( &stream, &length );
	if( cryptStatusOK( status ) )
		{
		status = sSkip( &stream, length );		/* Move past the object */
		length = ( int ) sizeofObject( length );/* Include header size */
		}
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}
	if( objectLength != NULL )
		*objectLength = length;
	if( object != NULL )
		*object = objectPtr;

	/* Make sure that the signing parameters are in order and create a hash 
	   context from the algorithm identifier of the signature */
	status = krnlSendMessage( sigCheckContext, IMESSAGE_GETATTRIBUTE,
							  &sigCheckAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		{
		/* If it's a broken signature, process the extra encapsulation */
		if( formatInfo != CRYPT_UNUSED )
			{
			if( !( formatInfo & 0x80 ) )
				readConstructed( &stream, NULL, formatInfo );
			else
				{
				readConstructed( &stream, NULL, formatInfo & 0x7F );
				readSequence( &stream, NULL );
				}
			}
		sigPtr = sMemBufPtr( &stream );
		status = readAlgoIDex( &stream, &signAlgo, &hashAlgo, NULL );
		}
	signatureLength = sMemDataLeft( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );
	if( sigCheckAlgo != signAlgo )
		/* The signature algorithm isn't what we expected, the best we can do
		   is report a signature error */
		return( CRYPT_ERROR_SIGNATURE );
	setMessageCreateObjectInfo( &createInfo, hashAlgo );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
							  IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
							  OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );

	/* Hash the signed data and check the signature on the object */
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH, 
					 objectPtr, length );
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH, 
					 objectPtr, 0 );
	status = checkSignature( sigPtr, signatureLength, sigCheckContext, 
							 createInfo.cryptHandle, CRYPT_UNUSED, 
							 SIGNATURE_X509 );

	/* Clean up */
	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
	return( status );
	}

/****************************************************************************
*																			*
*							PKI Protocol Signature Functions 				*
*																			*
****************************************************************************/

/* The various cert management protocols are built using the twin design 
   guidelines that nothing should use a standard style of signature and no
   two protocols should use the same nonstandard format, the only way to 
   handle these (without creating dozens of new signature types, each with
   their own special-case handling) is to process most of the signature 
   information at the protocol level and just check the raw signature here */

int createRawSignature( void *signature, int *signatureLength,
						const int sigMaxLength, 
						const CRYPT_CONTEXT iSignContext,
						const CRYPT_CONTEXT iHashContext )
	{
	return( createSignature( signature, signatureLength, sigMaxLength, 
							 iSignContext, iHashContext, CRYPT_UNUSED, 
							 SIGNATURE_RAW ) );
	}

int checkRawSignature( const void *signature, const int signatureLength,
					   const CRYPT_CONTEXT iSigCheckContext,
					   const CRYPT_CONTEXT iHashContext )
	{
	return( checkSignature( signature, signatureLength, iSigCheckContext, 
							iHashContext, CRYPT_UNUSED, SIGNATURE_RAW ) );
	}

/****************************************************************************
*																			*
*							Create/Check a CMS Signature 					*
*																			*
****************************************************************************/

/* CMS version */

#define CMS_VERSION		1

/* The maximum size for the encoded CMS signed attributes */

#define ENCODED_ATTRIBUTE_SIZE	512

/* Write CMS signer information:

	SignerInfo ::= SEQUENCE {
		version					INTEGER (1),
		issuerAndSerialNumber	IssuerAndSerialNumber,
		digestAlgorithm			AlgorithmIdentifier,
		signedAttrs		  [ 0 ]	IMPLICIT SET OF Attribute OPTIONAL,
		signatureAlgorithm		AlgorithmIdentifier,
		signature				OCTET STRING,
		unsignedAttrs	  [ 1 ]	IMPLICIT SET OF Attribute OPTIONAL
		} */

static int writeCmsSignerInfo( STREAM *stream, 
							   const CRYPT_CERTIFICATE certificate,
							   const CRYPT_ALGO_TYPE hashAlgorithm,
							   const void *attributes, const int attributeSize,
							   const void *signature, const int signatureSize,
							   const CRYPT_HANDLE unsignedAttrObject )
	{
	RESOURCE_DATA msgData;
	DYNBUF iAndSDB;
	int timeStampSize, unsignedAttributeSize = 0;
	int status;

	/* Get the signerInfo information */
	status = dynCreate( &iAndSDB, certificate, 
						CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
	if( cryptStatusError( status ) )
		return( status );
	if( unsignedAttrObject != CRYPT_UNUSED )
		{
		setMessageData( &msgData, NULL, 0 );
		status = krnlSendMessage( unsignedAttrObject, IMESSAGE_GETATTRIBUTE_S, 
								  &msgData, CRYPT_IATTRIBUTE_ENC_TIMESTAMP );
		timeStampSize = msgData.length;

⌨️ 快捷键说明

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