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

📄 cmp_rd.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*								Read CMP Messages							*
*						Copyright Peter Gutmann 1999-2003					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "asn1_rw.h"
  #include "asn1s_rw.h"
  #include "session.h"
  #include "cmp.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../misc/asn1_rw.h"
  #include "../misc/asn1s_rw.h"
  #include "../session/session.h"
  #include "../session/cmp.h"
#else
  #include "crypt.h"
  #include "misc/asn1_rw.h"
  #include "misc/asn1s_rw.h"
  #include "session/session.h"
  #include "session/cmp.h"
#endif /* Compiler-specific includes */

/* Prototypes for functions in lib_sign.c */

int checkRawSignature( const void *signature, const int signatureLength,
					   const CRYPT_CONTEXT iSigCheckContext,
					   const CRYPT_CONTEXT iHashContext );

#ifdef USE_CMP

/****************************************************************************
*																			*
*								Utility Routines							*
*																			*
****************************************************************************/

/* Read the CMP/Entrust MAC information:

	macInfo ::= SEQUENCE {
		algoID			OBJECT IDENTIFIER (entrustMAC),
		algoParams		SEQUENCE {
			salt		OCTET STRING,
			pwHashAlgo	AlgorithmIdentifier (SHA-1)
			iterations	INTEGER,
			macAlgo		AlgorithmIdentifier (HMAC-SHA1)
			} OPTIONAL
		} */

static int readMacInfo( STREAM *stream, CMP_PROTOCOL_INFO *protocolInfo,
						const void *password, const int passwordLength,
						void *errorInfo )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	BYTE salt[ CRYPT_MAX_HASHSIZE ];
	long value;
	int saltLength, iterations, status;

	/* Read the various parameter fields */
	readSequence( stream, NULL );
	status = readOID( stream, OID_ENTRUST_MAC );
	if( cryptStatusError( status ) )
		{
		/* If we don't find this OID we specifically report it as an unknown
		   algorithm problem rather than a generic bad data error */
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADALG;
		retExt( errorInfo, status, "Unrecognised MAC algorithm" );
		}
	if( peekTag( stream ) == BER_NULL )
		/* No parameters, use the same values as for the previous 
		   transaction */
		return( CRYPT_OK );
	readSequence( stream, NULL );
	readOctetString( stream, salt, &saltLength, CRYPT_MAX_HASHSIZE );
	readUniversal( stream );			/* pwHashAlgo */
	readShortInteger( stream, &value );
	status = readUniversal( stream );	/* macAlgo */
	if( cryptStatusError( status ) )
		retExt( errorInfo, status, "Invalid MAC algorithm information" );
	iterations = ( int ) value;
	if( iterations < 1 || iterations > CMP_MAX_PASSWORD_ITERATIONS )
		{
		/* Prevent DoS attacks due to excessive iteration counts (bad
		   algorithm is about the most appropriate error we can return
		   here).  The spec never defines any appropriate limits for this 
		   value, which leads to interesting effects when submitting a 
		   request for bignum iterations to some implementations */
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADALG;
		retExt( errorInfo, CRYPT_ERROR_BADDATA,
				"Invalid MAC iteration count %d", iterations );
		}

	/* If we're the responder and the MAC parameters aren't set yet, set
	   them based on the initiator's values.  If we're using MAC protection
	   and the parameters match our original MAC, reuse the MAC context.
	   As usual the spec is ambiguous over the use of the MAC info, leaving
	   it possible for implementations to re-key the MAC on a per-message
	   basis.  We try and cache MAC info as much as possible to reduce the
	   performance hit from re-keying for each message */
	if( protocolInfo->saltSize <= 0 )
		{
		status = initMacInfo( protocolInfo->iMacContext, password,
							  passwordLength, salt, saltLength, iterations );
		memcpy( protocolInfo->salt, salt, saltLength );
		protocolInfo->saltSize = saltLength;
		protocolInfo->iterations = iterations;
		if( cryptStatusError( status ) )
			retExt( errorInfo, status, 
					"Couldn't initialise MAC information" );
		return( CRYPT_OK );
		}
	if( protocolInfo->iterations && \
		saltLength == protocolInfo->saltSize && \
		!memcmp( salt, protocolInfo->salt, saltLength ) && \
		iterations == protocolInfo->iterations )
		{
		protocolInfo->useAltMAC = FALSE;
		return( CRYPT_OK );
		}
	protocolInfo->useAltMAC = TRUE;	/* Use the alternative MAC context */

	/* If we've got an alternative MAC context using the parameters from a 
	   previous message already set up, reuse this */
	if( protocolInfo->iAltMacContext != CRYPT_ERROR && \
		saltLength == protocolInfo->altSaltSize && \
		!memcmp( salt, protocolInfo->altSalt, saltLength ) && \
		iterations == protocolInfo->altIterations )
		return( CRYPT_OK );

	/* This is a new set of parameters, create a new altMAC context with
	   them */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	status = initMacInfo( createInfo.cryptHandle, password, passwordLength,
						  salt, saltLength, iterations );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		retExt( errorInfo, status, 
				"Couldn't initialise alternative MAC information" );
		}
	if( protocolInfo->iAltMacContext != CRYPT_ERROR )
		krnlSendNotifier( protocolInfo->iAltMacContext,
						  IMESSAGE_DECREFCOUNT );
	protocolInfo->iAltMacContext = createInfo.cryptHandle;
	memcpy( protocolInfo->altSalt, salt, saltLength );
	protocolInfo->altSaltSize = saltLength;
	protocolInfo->altIterations = iterations;

	return( CRYPT_OK );
	}

/* Read a cert encrypted with CMP's garbled reinvention of CMS content:

	EncryptedCert ::= SEQUENCE {
		dummy			[0]	... OPTIONAL,		-- Ignored
		cekAlg			[1]	AlgorithmIdentifier,-- CEK algorithm
		encCEK			[2]	BIT STRING,			-- Encrypted CEK
		dummy			[3]	... OPTIONAL,		-- Ignored
		dummy			[4] ... OPTIONAL,		-- Ignored
		encData			BIT STRING				-- Encrypted cert
		} */

static int readEncryptedCert( STREAM *stream,
							  const CRYPT_CONTEXT iImportContext,
							  void *errorInfo )
	{
	CRYPT_CONTEXT iSessionKey;
	MECHANISM_WRAP_INFO mechanismInfo;
	QUERY_INFO queryInfo;
	BYTE *encKeyPtr;
	int encKeyLength, encCertLength, status;

	/* Read the CEK algorithm identifier and encrypted CEK.  All of the
	   values are optional although there's no indication of why or what
	   you're supposed to do if they're not present (OTOH for others there's
	   no indication of what you're supposed to do when they're present
	   either) so we treat an absent required value as an error and ignore
	   the others */
	readSequence( stream, NULL );
	if( peekTag( stream ) == MAKE_CTAG( CTAG_EV_DUMMY1 ) )
		readUniversal( stream );				/* Junk */
	status = readContextAlgoID( stream, &iSessionKey, &queryInfo,
								CTAG_EV_CEKALGO );
	if( cryptStatusError( status ) )			/* CEK algo */
		retExt( errorInfo, status, 
				"Invalid encrypted certificate CEK algorithm" );
	status = readBitStringHole( stream, &encKeyLength, CTAG_EV_ENCCEK );
	if( cryptStatusOK( status ) &&				/* Encrypted CEK */
		( encKeyLength < 56 || encKeyLength > CRYPT_MAX_PKCSIZE ) )
		status = CRYPT_ERROR_OVERFLOW;
	if( cryptStatusOK( status ) )
		{
		encKeyPtr = sMemBufPtr( stream );
		sSkip( stream, encKeyLength );
		if( peekTag( stream ) == MAKE_CTAG( CTAG_EV_DUMMY2 ) )
			readUniversal( stream );			/* Junk */
		if( peekTag( stream ) == MAKE_CTAG( CTAG_EV_DUMMY3 ) )
			readUniversal( stream );			/* Junk */
		status = readBitStringHole( stream, &encCertLength, DEFAULT_TAG );
		}
	if( cryptStatusOK( status ) &&				/* Encrypted cert */
		( encCertLength < 128 || encCertLength > 8192 ) )
		status = CRYPT_ERROR_BADDATA;
	if( cryptStatusOK( status ) && \
		encCertLength > sMemDataLeft( stream ) )
		return( CRYPT_ERROR_UNDERFLOW );
	if( cryptStatusOK( status ) && \
		( queryInfo.cryptMode == CRYPT_MODE_ECB || \
		  queryInfo.cryptMode == CRYPT_MODE_CBC ) )
		{
		int blockSize;

		/* Make sure that the data length is valid.  Checking at this point 
		   saves a lot of unnecessary processing and allows us to return a 
		   more meaningful error code */
		krnlSendMessage( iSessionKey, IMESSAGE_GETATTRIBUTE, &blockSize,
						 CRYPT_CTXINFO_BLOCKSIZE );
		if( queryInfo.size % blockSize )
			status = CRYPT_ERROR_BADDATA;
		}
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iSessionKey, IMESSAGE_DECREFCOUNT );
		retExt( errorInfo, status, 
				"Invalid encrypted certificate CEK data" );
		}

	/* Copy the encrypted key to the buffer and import it into the session
	   key context */
	setMechanismWrapInfo( &mechanismInfo, encKeyPtr, encKeyLength,
						  NULL, 0, iSessionKey, iImportContext,
						  CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
							  &mechanismInfo, MECHANISM_PKCS1 );
	clearMechanismInfo( &mechanismInfo );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iSessionKey, IMESSAGE_DECREFCOUNT );
		retExt( errorInfo, status, 
				"Couldn't decrypt encrypted certificate CEK" );
		}

	/* Decrypt the returned cert */
	status = krnlSendMessage( iSessionKey, IMESSAGE_CTX_DECRYPT,
							  sMemBufPtr( stream ), encCertLength );
	krnlSendNotifier( iSessionKey, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		retExt( errorInfo, status,
				"Couldn't decrypt returned encrypted certificate using CEK" );
	return( CRYPT_OK );
	}

/* Read the kitchen-sink field in the PKI header */

static int readGeneralInfo( STREAM *stream, CMP_PROTOCOL_INFO *protocolInfo )
	{
	int generalInfoEndPos = stell( stream ), length, status;

	/* Go through the various attributes looking for anything that we can 
	   use */
	readConstructed( stream, NULL, CTAG_PH_GENERALINFO );
	status = readSequence( stream, &length );
	generalInfoEndPos += length;
	while( cryptStatusOK( status ) && stell( stream ) < generalInfoEndPos )
		{
		BYTE oid[ MAX_OID_SIZE ];

		/* Read the attribute.  Since there are only two attribute types 
		   that we use, we hardcode the read in here rather than performing 
		   a general-purpose attribute read */
		readSequence( stream, NULL );
		status = readRawObject( stream, oid, &length, MAX_OID_SIZE,
								BER_OBJECT_IDENTIFIER );
		if( cryptStatusError( status ) )
			break;

		/* Process the cryptlib presence-check value */
		if( length == sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) && \
			!memcmp( oid, OID_CRYPTLIB_PRESENCECHECK, length ) )
			{
			/* The other side is running cryptlib, we can make some common-
			   sense assumptions about its behaviour */
			protocolInfo->isCryptlib = TRUE;
			status = readSet( stream, NULL );/* Attribute */
			continue;
			}

		/* Check for the ESSCertID, which fixes CMP's broken cert 
		   identification mechanism */
		if( length == sizeofOID( OID_ESS_CERTID ) && \
			!memcmp( oid, OID_ESS_CERTID, length ) )
			{
			int endPos;

			/* Extract the cert hash from the ESSCertID */
			readSet( stream, NULL );		/* Attribute */
			readSequence( stream, NULL );	/* SigningCerts */
			readSequence( stream, NULL );	/* Certs */
			readSequence( stream, &length );/* ESSCertID */
			endPos = stell( stream ) + length;
			status = readOctetString( stream, protocolInfo->certID, 
									  &protocolInfo->certIDsize, 
									  CRYPT_MAX_HASHSIZE );
			if( cryptStatusOK( status ) && \
				protocolInfo->certIDsize != KEYID_SIZE )
				status = CRYPT_ERROR_BADDATA;
			if( cryptStatusError( status ) )
				continue;
			protocolInfo->certIDchanged = TRUE;
			if( stell( stream ) < endPos )
				/* Skip the issuerSerial if there's one present.  We can't 
				   really do much with it in this form without rewriting it 
				   into the standard issuerAndSerialNumber form, but in any 
				   case we don't need it because we've already got the cert 
				   ID */
				status = readUniversal( stream );
			continue;
			}

		/* It's something that we don't recognise, skip it */
		status = readUniversal( stream );
		}
	
	return( status );
	}
#endif /* USE_CMP */

/****************************************************************************
*																			*
*								Read Status Info							*
*																			*
****************************************************************************/

/* The following code is shared between CMP and TSP due to TSP's use of
   random elements cut & pasted from CMP without any real understanding of
   their function or semantics */

#if defined( USE_CMP ) || defined( USE_TSP )

/* Map a PKI failure info value to an error string */

static char *getFailureString( const int value )
	{
	static const FAR_BSS char *failureStrings[] = {
		"Unrecognized or unsupported Algorithm Identifier",
		"The integrity check failed (e.g. signature did not verify)",
		"This transaction is not permitted or supported",
		"The messageTime was not sufficiently close to the system time as "
			"defined by local policy",
		"No certificate could be found matching the provided criteria",
		"The data submitted has the wrong format",
		"The authority indicated in the request is different from the one "
			"creating the response token",
		"The requester's data is incorrect (used for notary services)",
		"Timestamp is missing but should be there (by policy)",
		"The proof-of-possession failed",
		"The certificate has already been revoked",
		"The certificate has already been confirmed",
		"Invalid integrity, password based instead of signature or vice "
			"versa",
		"Invalid recipient nonce, either missing or wrong value",
		"The TSA's time source is not available",
		"The requested TSA policy is not supported by the TSA",
		"The requested extension is not supported by the TSA",
		"The additional information requested could not be understood or is "
			"not available",
		"Invalid sender nonce, either missing or wrong size",
		"Invalid certificate template or missing mandatory information",
		"Signer of the message unknown or not trusted",
		"The transaction identifier is already in use",
		"The version of the message is not supported",
		"The sender was not authorized to make the preceding request or "
			"perform the preceding action",

⌨️ 快捷键说明

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