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

📄 sign_x509.c

📁 cryptlib安全工具包
💻 C
字号:
/****************************************************************************
*																			*
*							X.509/PKI Signature Routines					*
*						Copyright Peter Gutmann 1993-2007					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "mech.h"
  #include "asn1.h"
  #include "asn1_ext.h"
  #include "misc_rw.h"
#else
  #include "crypt.h"
  #include "mechs/mech.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
  #include "misc/misc_rw.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*							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.  These odds and
   ends are specified in the formatInfo structure */

CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 4 ) ) \
int createX509signature( OUT_BUFFER_OPT( sigMaxLength, *signedObjectLength ) \
							void *signedObject, 
						 IN_LENGTH_Z const int sigMaxLength, 
						 OUT_LENGTH_Z int *signedObjectLength,
						 IN_BUFFER( objectLength ) const void *object, 
						 IN_LENGTH const int objectLength,
						 IN_HANDLE const CRYPT_CONTEXT iSignContext,
						 IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
						 IN_OPT const X509SIG_FORMATINFO *formatInfo )
	{
	CRYPT_CONTEXT iHashContext;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
	BYTE dataSignature[ CRYPT_MAX_PKCSIZE + 128 + 8 ];
	int signatureLength, totalSigLength, status;

	assert( ( signedObject == NULL && sigMaxLength == 0 ) || \
			isWritePtr( signedObject, sigMaxLength ) );
	assert( isWritePtr( signedObjectLength, sizeof( int ) ) );
	assert( isReadPtr( object, objectLength ) && \
			!cryptStatusError( checkObjectEncoding( object, \
													objectLength ) ) );
	assert( formatInfo == NULL || \
			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );

	REQUIRES( ( signedObject == NULL && sigMaxLength == 0 ) || \
			  ( signedObject != NULL && \
				sigMaxLength > MIN_CRYPT_OBJECTSIZE && \
				sigMaxLength < MAX_INTLENGTH ) );
	REQUIRES( objectLength > 0 && objectLength < MAX_INTLENGTH );
	REQUIRES( isHandleRangeValid( iSignContext ) );
	REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
			  hashAlgo <= CRYPT_ALGO_LAST_HASH );
	REQUIRES( formatInfo == NULL || \
			  ( ( formatInfo->tag >= 0 && \
				  formatInfo->tag < MAX_CTAG_VALUE ) && \
				( formatInfo->extraLength >= 0 && \
				  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );

	/* Clear return values */
	if( signedObject != NULL )
		memset( signedObject, 0, min( 16, sigMaxLength ) );
	*signedObjectLength = 0;

	/* 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 );
	iHashContext = createInfo.cryptHandle;
	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, 
							  ( void * ) object, objectLength );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
	if( cryptStatusError( status ) )
		return( status );

	/* Create the signature and calculate the overall length of the payload, 
	   optional signature wrapper, and signature data */
	status = createSignature( dataSignature, CRYPT_MAX_PKCSIZE + 128, 
							  &signatureLength, iSignContext, 
							  createInfo.cryptHandle, CRYPT_UNUSED, 
							  SIGNATURE_X509 );
	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		return( status );
	if( formatInfo == NULL )
		totalSigLength = signatureLength;
	else
		{
		/* It's a nonstandard format, figure out the size due to the 
		   additional signature wrapper and other odds and ends */
		if( formatInfo->isExplicit )
			{
			totalSigLength = ( int ) \
				sizeofObject( \
					sizeofObject( signatureLength + \
								  formatInfo->extraLength ) );
			}
		else
			{
			totalSigLength = ( int ) \
				sizeofObject( signatureLength + formatInfo->extraLength );
			}
		}
	ENSURES( totalSigLength > 40 && totalSigLength < MAX_INTLENGTH );

	/* If we're not just performing a length check, make sure that there's 
	   enough room for the signed object in the output buffer.  This will be
	   checked by the stream handling anyway but we make it explicit here */
	if( signedObject != NULL && \
		sizeofObject( objectLength + totalSigLength ) > sigMaxLength )
		return( CRYPT_ERROR_OVERFLOW );

	/* Write the outer SEQUENCE wrapper and copy the payload into place 
	   behind it */
	sMemOpenOpt( &stream, signedObject, sigMaxLength );
	writeSequence( &stream, objectLength + totalSigLength );
	swrite( &stream, object, objectLength );

	/* If it's a nonstandard (b0rken PKI protocol) signature we have to 
	   kludge in a variety of additional wrappers and other junk around the 
	   signature */
	if( formatInfo != NULL )
		{
		if( formatInfo->isExplicit )
			{
			writeConstructed( &stream, 
							  sizeofObject( signatureLength + \
											formatInfo->extraLength ),
							  formatInfo->tag );
			writeSequence( &stream, 
						   signatureLength + formatInfo->extraLength );
			}
		else
			{
			writeConstructed( &stream, 
							  signatureLength + formatInfo->extraLength,
							  formatInfo->tag );
			}
		}

	/* Finally, append the signature */
	status = swrite( &stream, dataSignature, signatureLength );
	if( cryptStatusOK( status ) )
		*signedObjectLength = stell( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

	assert( ( formatInfo != NULL && formatInfo->extraLength > 0 ) || \
			!cryptStatusError( checkObjectEncoding( signedObject, \
													*signedObjectLength ) ) );
	return( CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int checkX509signature( IN_BUFFER( signedObjectLength ) const void *signedObject, 
						IN_LENGTH const int signedObjectLength,
						IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
						IN_OPT const X509SIG_FORMATINFO *formatInfo )
	{
	CRYPT_ALGO_TYPE signAlgo, sigCheckAlgo, hashAlgo;
	CRYPT_CONTEXT iHashContext;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
	void *objectPtr = DUMMY_INIT_PTR, *sigPtr;
	long length;
	int status, sigLength;

	assert( isReadPtr( signedObject, signedObjectLength ) );
	assert( formatInfo == NULL || \
			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );

	REQUIRES( signedObjectLength > 0 && signedObjectLength < MAX_INTLENGTH );
	REQUIRES( isHandleRangeValid( iSigCheckContext ) );
	REQUIRES( formatInfo == NULL || \
			  ( ( formatInfo->tag >= 0 && \
				  formatInfo->tag < MAX_CTAG_VALUE ) && \
				( formatInfo->extraLength >= 0 && \
				  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );

	/* Make sure that the signing parameters are in order */
	status = krnlSendMessage( iSigCheckContext, IMESSAGE_GETATTRIBUTE,
							  &sigCheckAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( status );

	/* Check the start of the object and record the start and size of the
	   encapsulated signed object.  We have to use the long-length form of
	   the length functions to handle mega-CRLs */
	sMemConnect( &stream, signedObject, signedObjectLength );
	readLongSequence( &stream, NULL );
	status = getLongStreamObjectLength( &stream, &length );
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( &stream, &objectPtr, length );
	if( cryptStatusOK( status ) )
		status = sSkip( &stream, length );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}

	/* If it's a broken signature, process the extra encapsulation */
	if( formatInfo != NULL )
		{
		if( formatInfo->isExplicit )
			{
			readConstructed( &stream, NULL, formatInfo->tag );
			status = readSequence( &stream, NULL );
			}
		else
			status = readConstructed( &stream, NULL, formatInfo->tag );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( status );
			}
		}

	/* Remember the location and size of the signature data */
	status = sMemGetDataBlockRemaining( &stream, &sigPtr, &sigLength );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}
	status = readAlgoIDext( &stream, &signAlgo, &hashAlgo );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

	/* If the signature algorithm isn't what we expected the best that we 
	   can do is report a signature error */
	if( sigCheckAlgo != signAlgo )
		return( CRYPT_ERROR_SIGNATURE );

	/* Create a hash context from the algorithm identifier of the
	   signature */
	setMessageCreateObjectInfo( &createInfo, hashAlgo );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
							  OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	iHashContext = createInfo.cryptHandle;

	/* Hash the signed data and check the signature on the object */
	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, 
							  objectPtr, length );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, 
								  "", 0 );
	if( cryptStatusOK( status ) )
		{
		status = checkSignature( sigPtr, sigLength, iSigCheckContext,
								 iHashContext, CRYPT_UNUSED,
								 SIGNATURE_X509 );
		}
	krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );

	return( status );
	}

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

/* The various PKIX 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 */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int createRawSignature( OUT_BUFFER( sigMaxLength, *signatureLength ) \
							void *signature, 
						IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
							const int sigMaxLength, 
						OUT_LENGTH_SHORT_Z int *signatureLength, 
						IN_HANDLE const CRYPT_CONTEXT iSignContext,
						IN_HANDLE const CRYPT_CONTEXT iHashContext )
	{
	assert( isWritePtr( signature, sigMaxLength ) );
	assert( isWritePtr( signatureLength, sizeof( int ) ) );

	REQUIRES( sigMaxLength >= MIN_CRYPT_OBJECTSIZE && \
			  sigMaxLength < MAX_INTLENGTH_SHORT );
	REQUIRES( isHandleRangeValid( iSignContext ) );
	REQUIRES( isHandleRangeValid( iHashContext ) );

	return( createSignature( signature, sigMaxLength, signatureLength, 
							 iSignContext, iHashContext, CRYPT_UNUSED,
							 SIGNATURE_RAW ) );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int checkRawSignature( IN_BUFFER( signatureLength ) const void *signature, 
					   IN_LENGTH_SHORT const int signatureLength,
					   IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
					   IN_HANDLE const CRYPT_CONTEXT iHashContext )
	{
	assert( isReadPtr( signature, signatureLength ) );

	REQUIRES( signatureLength > 0 && signatureLength < MAX_INTLENGTH_SHORT );
	REQUIRES( isHandleRangeValid( iSigCheckContext ) );
	REQUIRES( isHandleRangeValid( iHashContext ) );

	return( checkSignature( signature, signatureLength, iSigCheckContext,
							iHashContext, CRYPT_UNUSED, SIGNATURE_RAW ) );
	}

⌨️ 快捷键说明

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