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

📄 sign_rw.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						  Signature Read/Write Routines						*
*						Copyright Peter Gutmann 1992-2004					*
*																			*
****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) 
  #include "pgp.h"
  #include "asn1.h"
  #include "mechanism.h"
  #include "asn1_ext.h"
  #include "misc_rw.h"
#elif defined( INC_CHILD )
  #include "../envelope/pgp.h"
  #include "mechanism.h"
  #include "../misc/asn1.h"
  #include "../misc/asn1_ext.h"
  #include "../misc/misc_rw.h"
#else
  #include "envelope/pgp.h"
  #include "mechs/mechanism.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
  #include "misc/misc_rw.h"
#endif /* Compiler-specific includes */

/* Context-specific tags for the SignerInfo record */

enum { CTAG_SI_SKI };

/* CMS version numbers for various objects */

#define SIGNATURE_VERSION		1
#define SIGNATURE_EX_VERSION	3

/****************************************************************************
*																			*
*							X.509 Signature Routines						*
*																			*
****************************************************************************/

/* Read/write raw signatures */

static int readRawSignature( STREAM *stream, QUERY_INFO *queryInfo )
	{
	int status;

	/* Read the start of the signature */
	status = readBitStringHole( stream, &queryInfo->dataLength, 
								DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		queryInfo->dataStart = sMemBufPtr( stream );
	return( status );
	}

static int writeRawSignature( STREAM *stream, const CRYPT_CONTEXT iSignContext,
							  const CRYPT_ALGO_TYPE hashAlgo, 
							  const CRYPT_ALGO_TYPE signAlgo, 
							  const BYTE *signature, 
							  const int signatureLength )
	{
	/* Write the BIT STRING wrapper and signature */
	writeBitStringHole( stream, signatureLength, DEFAULT_TAG );
	return( writeRawObject( stream, signature, signatureLength ) );
	}

/* Read/write X.509 signatures */

static int readX509Signature( STREAM *stream, QUERY_INFO *queryInfo )
	{
	int status;

	/* Read the signature/hash algorithm information followed by the start 
	   of the signature */
	status = readAlgoIDex( stream, &queryInfo->cryptAlgo,
						   &queryInfo->hashAlgo, NULL );
	if( cryptStatusError( status ) )
		return( status );
	status = readBitStringHole( stream, &queryInfo->dataLength, 
								DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		queryInfo->dataStart = sMemBufPtr( stream );
	return( status );
	}

static int writeX509Signature( STREAM *stream, 
							   const CRYPT_CONTEXT iSignContext,
							   const CRYPT_ALGO_TYPE hashAlgo, 
							   const CRYPT_ALGO_TYPE signAlgo, 
							   const BYTE *signature, 
							   const int signatureLength )
	{
	/* Write the hash+signature algorithm identifier followed by the BIT 
	   STRING wrapper and signature */
	writeContextAlgoID( stream, iSignContext, hashAlgo,
						ALGOID_FLAG_ALGOID_ONLY );
	writeBitStringHole( stream, signatureLength, DEFAULT_TAG );
	return( writeRawObject( stream, signature, signatureLength ) );
	}

/****************************************************************************
*																			*
*							CMS Signature Routines							*
*																			*
****************************************************************************/

/* Read/write PKCS #7/CMS (issuerAndSerialNumber) signatures */

static int readCmsSignature( STREAM *stream, QUERY_INFO *queryInfo )
	{
	long value, endPos;
	int status;

	value = getStreamObjectLength( stream );
	if( cryptStatusError( value ) )
		return( value );
	endPos = stell( stream ) + value;

	/* Read the header */
	readSequence( stream, NULL );
	status = readShortInteger( stream, &value );
	if( cryptStatusOK( status ) && value != SIGNATURE_VERSION )
		status = CRYPT_ERROR_BADDATA;
	if( cryptStatusError( status ) )
		return( status );

	/* Read the issuer and serial number and hash algorithm ID */
	value = getStreamObjectLength( stream );
	if( cryptStatusError( value ) )
		return( value );
	queryInfo->iAndSStart = sMemBufPtr( stream );
	queryInfo->iAndSLength = value;
	sSkip( stream, value );
	status = readAlgoID( stream, &queryInfo->hashAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the authenticated attributes if there are any present */
	if( peekTag( stream ) == MAKE_CTAG( 0 ) )
		{
		int length;

		queryInfo->attributeStart = sMemBufPtr( stream );
		status = readConstructed( stream, &length, 0 );
		if( cryptStatusError( status ) )
			return( status );
		queryInfo->attributeLength = ( int ) sizeofObject( length );
		sSkip( stream, length );
		}

	/* Read the CMS/cryptlib signature algorithm and start of the signature */
	readAlgoID( stream, &queryInfo->cryptAlgo );
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		{
		queryInfo->dataStart = sMemBufPtr( stream );
		status = sSkip( stream, queryInfo->dataLength );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Read the unauthenticated attributes if there are any present */
	if( stell( stream ) < endPos && peekTag( stream ) == MAKE_CTAG( 1 ) )
		{
		int length;

		queryInfo->unauthAttributeStart = sMemBufPtr( stream );
		status = readConstructed( stream, &length, 1 );
		if( cryptStatusError( status ) )
			return( status );
		queryInfo->unauthAttributeLength = ( int ) sizeofObject( length );
		status = sSkip( stream, length );
		}
	return( status );
	}

static int writeCmsSignature( STREAM *stream, 
							  const CRYPT_CONTEXT iSignContext,
							  const CRYPT_ALGO_TYPE hashAlgo, 
							  const CRYPT_ALGO_TYPE signAlgo, 
							  const BYTE *signature, 
							  const int signatureLength )
	{
	/* Write the signature algorithm identifier and signature data.  The 
	   handling of CMS signatures is non-orthogonal to readCmsSignature() 
	   because creating a CMS signature involves adding assorted additional 
	   data like iAndS and signed attributes which present too much 
	   information to pass into a basic writeSignature() call */
	writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE,
						ALGOID_FLAG_ALGOID_ONLY );
	return( writeOctetString( stream, signature, signatureLength, DEFAULT_TAG ) );
	}

/* Read/write cryptlib/CMS (keyID) signatures */

static int readCryptlibSignature( STREAM *stream, QUERY_INFO *queryInfo )
	{
	long value;
	int status;

	/* Read the header */
	readSequence( stream, NULL );
	status = readShortInteger( stream, &value );
	if( cryptStatusOK( status ) && value != SIGNATURE_EX_VERSION )
		status = CRYPT_ERROR_BADDATA;
	if( cryptStatusError( status ) )
		return( status );

	/* Read the key ID and hash algorithm identifier */
	readOctetStringTag( stream, queryInfo->keyID, &queryInfo->keyIDlength, 
						CRYPT_MAX_HASHSIZE, CTAG_SI_SKI );
	status = readAlgoID( stream, &queryInfo->hashAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the CMS/cryptlib signature algorithm and start of the signature */
	readAlgoID( stream, &queryInfo->cryptAlgo );
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		queryInfo->dataStart = sMemBufPtr( stream );
	return( status );
	}

static int writeCryptlibSignature( STREAM *stream, 
								   const CRYPT_CONTEXT iSignContext,
								   const CRYPT_ALGO_TYPE hashAlgo, 
								   const CRYPT_ALGO_TYPE signAlgo, 
								   const BYTE *signature, 
								   const int signatureLength )
	{
	RESOURCE_DATA msgData;
	BYTE keyID[ CRYPT_MAX_HASHSIZE ];

	/* Get the key ID */
	setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
	krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
					 &msgData, CRYPT_IATTRIBUTE_KEYID );

	/* Write the header */
	writeSequence( stream, ( int ) sizeofShortInteger( SIGNATURE_EX_VERSION ) + \
				   sizeofObject( msgData.length ) + \
				   sizeofContextAlgoID( iSignContext, CRYPT_ALGO_NONE, \
										ALGOID_FLAG_ALGOID_ONLY ) + \
				   sizeofAlgoID( hashAlgo ) + \
				   sizeofObject( signatureLength ) );

	/* Write the version, key ID and algorithm identifier */
	writeShortInteger( stream, SIGNATURE_EX_VERSION, DEFAULT_TAG );
	writeOctetString( stream, msgData.data, msgData.length, CTAG_SI_SKI );
	writeAlgoID( stream, hashAlgo );
	writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE,
						ALGOID_FLAG_ALGOID_ONLY );
	return( writeOctetString( stream, signature, signatureLength, DEFAULT_TAG ) );
	}

/****************************************************************************
*																			*
*							Misc Signature Routines							*
*																			*
****************************************************************************/

#ifdef USE_PGP

/* Read signature subpackets */

static int readSignatureSubpackets( STREAM *stream, QUERY_INFO *queryInfo,
									const int length, 
									const BOOLEAN isAuthenticated )
	{
	const int endPos = stell( stream ) + length;

	while( stell( stream ) < endPos )
		{
		const int subpacketLength = pgpReadShortLength( stream,
														PGP_CTB_OPENPGP );
		const int type = sgetc( stream );

		if( cryptStatusError( subpacketLength ) )
			return( subpacketLength );

		/* If it's an unrecognised subpacket with the critical flag set,
		   reject the signature.  The range check isn't complete since there
		   are a few holes in the range, but since the holes presumably exist
		   because of deprecated subpacket types, any new packets will be
		   added at the end so it's safe to use */
		if( ( type & 0x80 ) && ( ( type & 0x7F ) > PGP_SUBPACKET_LAST ) )
			return( CRYPT_ERROR_NOTAVAIL );

		/* If it's a key ID and we haven't already set this from a preceding
		   one-pass signature packet (which can happen with detached sigs),
		   set it now */
		if( type == PGP_SUBPACKET_KEYID && queryInfo->keyIDlength <= 0 )
			{
			sread( stream, queryInfo->keyID, PGP_KEYID_SIZE );
			queryInfo->keyIDlength = PGP_KEYID_SIZE;
			continue;
			}

		/* If it's a type-and-value packet, see whether it's one of
		   ours */
		if( type == PGP_SUBPACKET_TYPEANDVALUE )
			{
			BYTE nameBuffer[ 32 ];
			static const char *nameString = "issuerAndSerialNumber";
			int nameLength, valueLength;

			sSkip( stream, 4 );		/* Flags */
			nameLength = readUint16( stream );
			valueLength = readUint16( stream );
			if( nameLength != strlen( nameString ) || \
				valueLength < 16 || valueLength > 2048 )
				{
				sSkip( stream, nameLength + valueLength );
				continue;
				}
			sread( stream, nameBuffer, nameLength );
			if( memcmp( nameBuffer, nameString, nameLength ) )
				{
				sSkip( stream, valueLength );
				continue;
				}

			/* It's an issuerAndSerialNumber, remember it for later */
			queryInfo->iAndSStart = sMemBufPtr( stream );
			queryInfo->iAndSLength = valueLength;
			sSkip( stream, valueLength );
			continue;
			}

		/* It's something else, skip it and continue */
		sSkip( stream, subpacketLength - 1 );
		}

	return( sGetStatus( stream ) );
	}

/* Signature info:
		byte	ctb = PGP_PACKET_SIGNATURE_ONEPASS
		byte[]	length
		byte	version = 3
		byte	sigType
		byte	hashAlgo
		byte	sigAlgo

⌨️ 快捷键说明

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