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

📄 cmp.c

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

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "asn1.h"
  #include "asn1oid.h"
  #include "stream.h"
  #include "session.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../keymgmt/asn1.h"
  #include "../keymgmt/asn1oid.h"
  #include "../keymgmt/stream.h"
  #include "../session/session.h"
#else
  #include "crypt.h"
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1oid.h"
  #include "keymgmt/stream.h"
  #include "session/session.h"
#endif /* Compiler-specific includes */

/* Since the CMP spec is so vague and open-ended that almost anything can
   be argued to be valid, it's useful to be able to grab a sample message
   from a server and pick it apart offline.  Uncommenting the following
   define will read this stored input from disk rather than communicating
   with the server */

/*#define SKIP_IO						/* Don't communicate with server */

/* The following macro can be used to enable dumping of PDUs to disk (as a
   safeguard, this only works in the Win32 debug version to prevent it from
   being accidentally enabled in any release version) */

#if defined( __WIN32__ ) && !defined( NDEBUG )
  #define DEBUG_DUMP( type, level, sessionInfo ) \
		  debugDump( type, level, sessionInfo )
#else
  #define DEBUG_DUMP( type, level, sessionInfo )
#endif /* Win32 debug */

/* CMP version and default port */

#define CMP_VERSION			2		/* CMP version */
#define CMP_PORT			829		/* TCP default port */

/* Various CMP constants */

#define CMP_NONCE_SIZE		16		/* Size of nonces */
#define CMP_PASSWORD_ITERATIONS		100		/* No.of PW hashing iterations */
#define CMP_MAX_PASSWORD_ITERATIONS	10000	/* Max allowable iterations */

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

enum { CTAG_PH_MESSAGETIME, CTAG_PH_PROTECTIONALGO, CTAG_PH_SENDERKID,
	   CTAG_PH_RECIPKID, CTAG_PH_TRANSACTIONID, CTAG_PH_SENDERNONCE,
	   CTAG_PH_RECIPNONCE, CTAG_PH_FREETEXT, CTAG_PH_GENERALINFO };

/* Context-specific tags for the PKIBody wrapper */

enum { CTAG_PB_IR, CTAG_PB_IP, CTAG_PB_CR, CTAG_PB_CP, CTAG_PB_P10CR,
	   CTAG_PB_POPDECC, CTAG_PB_POPDECR, CTAG_PB_KUR, CTAG_PB_KUP,
	   CTAG_PB_KRR, CTAG_PB_KRP, CTAG_PB_RR, CTAG_PB_RP, CTAG_PB_CCR,
	   CTAG_PB_CCP, CTAG_PB_CKUANN, CTAG_PB_CANN, CTAG_PB_RANN,
	   CTAG_PB_CRLANN, CTAG_PB_PKICONF, CTAG_PB_NESTED, CTAG_PB_GENM,
	   CTAG_PB_GENP, CTAG_PB_ERROR, CTAG_PB_CERTCONF, CTAG_PB_LAST };

/* Context-specific tags for the PKIMessage */

enum { CTAG_PM_PROTECTION, CTAG_PM_EXTRACERTS };

/* Context-specific tags for the CertifiedKeyPair in the PKIMessage */

enum { CTAG_CK_CERT, CTAG_CK_ENCRYPTEDCERT };

/* Context-specific tags for the EncryptedValue in the CertifiedKeyPair */

enum { CTAG_EV_DUMMY1, CTAG_EV_CEKALGO, CTAG_EV_ENCCEK, CTAG_EV_DUMMY2,
	   CTAG_EV_DUMMY3 };

/* PKIStatus values */

enum { PKISTATUS_OK, PKISTATUS_OK_WITHINFO, PKISTATUS_REJECTED,
	   PKISTATUS_WAITING, PKISTATUS_REVOCATIONIMMINENT,
	   PKISTATUS_REVOCATION, PKISTATUS_KEYUPDATE };

/* PKIFailureInfo values */

#define CMPFAILINFO_OK					0x00000000L
#define CMPFAILINFO_BADALG				0x00000001L
#define CMPFAILINFO_BADMESSAGECHECK		0x00000002L
#define CMPFAILINFO_BADREQUEST			0x00000004L
#define CMPFAILINFO_BADTIME				0x00000008L
#define CMPFAILINFO_BADCERTID			0x00000010L
#define CMPFAILINFO_BADDATAFORMAT		0x00000020L
#define CMPFAILINFO_WRONGAUTHORITY		0x00000040L
#define CMPFAILINFO_INCORRECTDATA		0x00000080L
#define CMPFAILINFO_MISSINGTIMESTAMP	0x00000100L
#define CMPFAILINFO_BADPOP				0x00000200L
#define CMPFAILINFO_CERTREVOKED			0x00000400L
#define CMPFAILINFO_CERTCONFIRMED		0x00000800L
#define CMPFAILINFO_WRONGINTEGRITY		0x00001000L
#define CMPFAILINFO_BADRECIPIENTNONCE	0x00002000L
#define CMPFAILINFO_TIMENOTAVAILABLE	0x00004000L
#define CMPFAILINFO_UNACCEPTEDPOLICY	0x00008000L
#define CMPFAILINFO_UNACCEPTEDEXTENSION	0x00010000L
#define CMPFAILINFO_ADDINFONOTAVAILABLE	0x00020000L
#define CMPFAILINFO_BADSENDERNONCE		0x00040000L
#define CMPFAILINFO_BADCERTTEMPLATE		0x00080000L
#define CMPFAILINFO_SIGNERNOTTRUSTED	0x00100000L
#define CMPFAILINFO_TRANSACTIONIDINUSE	0x00200000L
#define CMPFAILINFO_UNSUPPORTEDVERSION	0x00400000L
#define CMPFAILINFO_NOTAUTHORIZED		0x00800000L
#define CMPFAILINFO_SYSTEMUNAVAIL		0x01000000L
#define CMPFAILINFO_SYSTEMFAILURE		0x02000000L
#define CMPFAILINFO_DUPLICATECERTREQ	0x04000000L

/* The OID for the Entrust MAC */

#define OID_ENTRUST_MAC	MKOID( "\x06\x09\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0D" )

/* When we're writing the payload of a CMP message, we use a shared function
   for most payload types because they're all pretty similar.  The following
   values distinguish between the message classes which can be handled by a
   single write function  */

typedef enum {
	CMPBODY_NORMAL, CMPBODY_CONFIRMATION, CMPBODY_ACK, CMPBODY_ERROR
	} CMPBODY_TYPE;

/* CMP uses so many unnecessary EXPLICIT tags that we define a macro to
   make it easier to evaluate the encoded sizes of objects tagged in this
   manner */

#define objSize( length )	( ( int ) sizeofObject( length ) )

/* CMP protocol state information.  This is passed around various
   subfunctions which handle individual parts of the protocol */

typedef struct {
	/* Session state information.  We record the operation being carried
	   out so we can make decisions about message validity and contents
	   when reading/writing fields, and whether the other side is a
	   cryptlib implementation which allows us to work around some of the
	   braindamage in CMP since we know the other side will do the right
	   thing or include extra information required to avoid CMP
	   shortcomings */
	int operation;							/* ir/cr/kur/rr */
	BOOLEAN isCryptlib;						/* Whether peer is cryptlib */

	/* Identification/state variable information.  The userID is either the
	   CA-supplied user ID value (for MACd messages) or the
	   subjectKeyIdentifier (for signed messages).  The sender and recipient
	   nonces change roles each at message turnaround, so as we go through
	   the various portions of the protocol the different nonces slowly
	   shift through the two values.  In order to accomodate nonstandard
	   implementations, we allow for nonces which are slightly large than
	   the required size */
	BYTE userID[ CRYPT_MAX_TEXTSIZE + 1 ];	/* User ID */
	BYTE transID[ CRYPT_MAX_HASHSIZE ];		/* Transaction nonce */
	BYTE senderNonce[ CRYPT_MAX_HASHSIZE ];	/* Sender nonce */
	BYTE recipNonce[ CRYPT_MAX_HASHSIZE ];	/* Recipient nonce */
	int userIDsize, transIDsize, senderNonceSize, recipNonceSize;

	/* When processing CMP data, we need to remember the last cryptlib error
	   status value we encountered and the last CMP extended failure value so
	   we can send it to the remote client/server in an error response */
	int status;								/* Last error status */
	long pkiFailInfo;						/* Last extended failure status */

	/* The information needed to verify message integrity.  Typically we
	   use a MAC, however in some cases the data isn't MAC'd but signed by
	   the user or CA, in which case we use the user private key to sign or
	   CA certificate to verify instead of MAC'ing it.  If we're signing,
	   we clear the userMACsend flag, if we're verifying we clear the
	   useMACreceive flag (in theory the two should match, but there are
	   implementations which use MACs one way and sigs the other).  If we're
	   using a MAC then rather than recalculating the MAC keying info each
	   time (which can get expensive with the iterated password setup) we
	   reuse it for each message by deleting the previous MAC value */
	CRYPT_ALGO hashAlgo;					/* Hash algo for signature */
	CRYPT_CONTEXT iMacContext;				/* MAC context */
	BYTE salt[ CRYPT_MAX_HASHSIZE ];		/* MAC password salt  */
	int saltSize;
	int iterations;							/* MAC password iterations */
	BOOLEAN useMACsend, useMACreceive;		/* Use MAC to verify integrity */

	/* Sometimes the other side will changes the MAC parameters in their
	   response, which is annoying because it doesn't serve any purpose but
	   does mean that we can't reuse the MAC context.  When we get a response
	   we compare the parameters with our ones, if they don't match we create
	   an alternative MAC context with the returned parameters and use that
	   instead.  This process is repeated for each message received */
	CRYPT_CONTEXT iAltMacContext;			/* Alternative MAC context */
	BYTE altSalt[ CRYPT_MAX_HASHSIZE ];		/* Alternative MAC password salt */
	int altSaltSize;
	int altIterations;						/* Alt.MAC password iterations */
	BOOLEAN useAltMAC;						/* Use alternative MAC context */

	/* Other protocol information.  CMP uses an extremely clunky confirmation
	   mechanism in which a cert conf uses as hash algorithm the algorithm
	   which was used in a previous message by the CA to sign the
	   certificate, which means implementations will break each time a new
	   certificate format is added since the CMP transport-level code is now
	   dependent on the format of the data it carries.  In order to support
	   this content-coupling of protocol and data, we record the hash
	   algorithm when we receive the CA's reply so it can be used later */
	CRYPT_ALGO confHashAlgo;				/* Cert.conf.hash algo */

	/* Pointers to parsed data in the current message.  This is used by
	   lower-level decoding routines to return information needed by higher-
	   level ones.  The MAC info position records the position of the MAC
	   info (we can't set up the MAC info until we've read the sender key ID,
	   but the MAC info is sent first, so we have to go back and re-process
	   it once we've got the sender key ID).  The authentication info records
	   the identification information of the key used to sign the message,
	   either an issuerAndSerialNumber if we're talking to a cryptlib-based
	   peer or a (generally ambiguous) DN for anything else */
	int macInfoPos;							/* Position of MAC info in stream */
	int authKeyIDpos, authKeyIDlength;		/* Position of auth.key ID in stream */
	} CMP_PROTOCOL_INFO;

/* Prototypes for functions in lib_sign.c */

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

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

#if defined( __WIN32__ ) && !defined( NDEBUG )

/* Dump a message to disk for diagnostic purposes */

static void debugDump( const int type, const int phase,
					   const SESSION_INFO *sessionInfoPtr )
	{
	static const char *irStrings[] = \
		{ "cmpi1_ir", "cmpi2_ip", "cmpi3_conf", "cmpi4_confack" };
	static const char *crStrings[] = \
		{ "cmpc1_cr", "cmpc2_cp", "cmpc3_conf", "cmpc4_confack" };
	static const char *kurStrings[] = \
		{ "cmpk1_kur", "cmpk2_kup", "cmpk3_conf", "cmpk4_confack" };
	static const char *rrStrings[] = \
		{ "cmpr1_rr", "cmpr2_rp" };
	static const char *errorStrings[] = \
		{ "cmpe1_error" };
	static const char *unkStrings[] = \
		{ "cmp_unknown1", "cmp_unknown2", "cmp_unknown3", "cmp_unknown4" };
	const char **fnStringPtr = ( type == CTAG_PB_IR ) ? irStrings : \
							   ( type == CTAG_PB_CR ) ? crStrings : \
							   ( type == CTAG_PB_KUR ) ? kurStrings : \
							   ( type == CTAG_PB_RR ) ? rrStrings : \
							   ( type == CTAG_PB_ERROR ) ? errorStrings : \
							  unkStrings;
	FILE *filePtr;
	char fileName[ 1024 ];

	strcpy( fileName, "r:/tmp/" );
	if( sessionInfoPtr->flags & SESSION_ISSERVER )
		{
		RESOURCE_DATA msgData;
		int i;

		setResourceData( &msgData, fileName + 7, 1024 - 7 );
		krnlSendMessage( sessionInfoPtr->privateKey,
						 RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
						 CRYPT_CERTINFO_DN );
		for( i = 0; i < msgData.length; i++ )
			{
			const int ch = fileName[ 7 + i ];

			if( ch == ' ' || ch == '\'' || ch == '"' || ch == '?' || \
				ch == '*' || ch == '[' || ch == ']' || ch == '`' || \
				ch == ',' || ch < ' ' || ch > 'z' )
				fileName[ 7 + i ] = '_';
			}
		strcat( fileName, "_" );
		}
	strcat( fileName, fnStringPtr[ phase - 1 ] );
	strcat( fileName, ".der" );

	filePtr = fopen( fileName, "wb" );
	if( filePtr != NULL )
		{
		fwrite( sessionInfoPtr->receiveBuffer, 1,
				sessionInfoPtr->receiveBufEnd, filePtr );
		fclose( filePtr );
		}
	}
#endif /* Windows debug mode only */

/* Map a request to a response type */

static int reqToRespType( const int reqType )
	{
	switch( reqType )
		{
		case CTAG_PB_IR:
			return( CTAG_PB_IP );
		case CTAG_PB_CR:
		case CTAG_PB_P10CR:
			return( CTAG_PB_CP );
		case CTAG_PB_POPDECC:
			return( CTAG_PB_POPDECR );
		case CTAG_PB_KUR:
			return( CTAG_PB_KUP );
		case CTAG_PB_KRR:
			return( CTAG_PB_KRP );
		case CTAG_PB_RR:
			return( CTAG_PB_RP );
		case CTAG_PB_CCR:
			return( CTAG_PB_CCP );
		case CTAG_PB_GENM:
			return( CTAG_PB_GENP );
		}

	return( CRYPT_ERROR );
	}

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

static char *getFailureString( const int value )
	{
	static const char *failureStrings[] = {
		"Unrecognized or unsupported Algorithm Identifier",
		"The integrity check failed (e.g. signature did not verify)",
		"This transaction is not permitted or supported",

⌨️ 快捷键说明

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