📄 cmp.c
字号:
/****************************************************************************
* *
* cryptlib CMP Session Management *
* 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 */
/* CMP requires a variety of authentication contexts, which are mapped to
session info contexts as follows:
| iAuthIn | iAuthOut
--------+---------------+-------------------
Client | CA cert | Client privKey
| | or MAC
Server | Client cert | CA privKey
| or MAC |
In addition general user information on the server side is stored in the
cmpUserInfo object */
#ifdef USE_CMP
/* If we're reading predefined requests/responses from disk instead of
communicating with the client/server, skip the network reads/writes */
#ifdef SKIP_IO
#define readPkiDatagram( dummy ) CRYPT_OK
#define writePkiDatagram( dummy ) CRYPT_OK
#endif /* SKIP_IO */
/* 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 DUMP_SERVER_MESSAGES */
#define DEBUG_DUMP_CMP( type, level, sessionInfo ) \
debugDump( type, level, sessionInfo )
#else
#define DEBUG_DUMP_CMP( type, level, sessionInfo )
#endif /* Win32 debug */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
#if defined( __WIN32__ ) && !defined( NDEBUG )
/* Dump a message to disk for diagnostic purposes. The CMP messages are
complex enough that we can't use the normal DEBUG_DUMP() macro but have
to use a special-purpose function that uses meaningful names for all
of the files that are created */
static void debugDump( const int type, const int phase,
const SESSION_INFO *sessionInfoPtr )
{
static const FAR_BSS char *irStrings[] = \
{ "cmpi1_ir", "cmpi2_ip", "cmpi3_conf", "cmpi4_confack" };
static const FAR_BSS char *crStrings[] = \
{ "cmpc1_cr", "cmpc2_cp", "cmpc3_conf", "cmpc4_confack" };
static const FAR_BSS char *kurStrings[] = \
{ "cmpk1_kur", "cmpk2_kup", "cmpk3_conf", "cmpk4_confack" };
static const FAR_BSS char *rrStrings[] = \
{ "cmpr1_rr", "cmpr2_rp" };
static const FAR_BSS char *gmStrings[] = \
{ "cmpg1_gr", "cmpg2_gp" };
static const FAR_BSS char *errorStrings[] = \
{ "cmpe1_error" };
static const FAR_BSS 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_GENM ) ? gmStrings : \
( type == CTAG_PB_ERROR ) ? errorStrings : \
unkStrings;
FILE *filePtr;
char fileName[ 1024 ];
#ifndef DUMP_SERVER_MESSAGES
/* Server messages have complex names based on the server DN, so we only
dump them if explicitly requested */
if( sessionInfoPtr->flags & SESSION_ISSERVER )
return;
#endif /* !DUMP_SERVER_MESSAGES */
/* GetTempPath( 512, fileName ); */
strcpy( fileName, "/tmp/" );
if( sessionInfoPtr->flags & SESSION_ISSERVER )
{
RESOURCE_DATA msgData;
const int pathLength = strlen( fileName );
int i;
setMessageData( &msgData, fileName + pathLength, 1024 - pathLength );
krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_DN );
for( i = 0; i < msgData.length; i++ )
{
const int ch = fileName[ pathLength + i ];
if( ch == ' ' || ch == '\'' || ch == '"' || ch == '?' || \
ch == '*' || ch == '[' || ch == ']' || ch == '`' || \
ch == ',' || ch < ' ' || ch > 'z' )
fileName[ pathLength + 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 request to response types */
static const struct {
const int request, response;
const int cryptlibRequest;
} reqRespMapTbl[] = {
{ CTAG_PB_IR, CTAG_PB_IP, CRYPT_REQUESTTYPE_INITIALISATION },
{ CTAG_PB_CR, CTAG_PB_CP, CRYPT_REQUESTTYPE_CERTIFICATE },
{ CTAG_PB_P10CR, CTAG_PB_CP, CRYPT_REQUESTTYPE_CERTIFICATE },
{ CTAG_PB_POPDECC, CTAG_PB_POPDECR, CRYPT_ERROR },
{ CTAG_PB_KUR, CTAG_PB_KUP, CRYPT_REQUESTTYPE_KEYUPDATE },
{ CTAG_PB_KRR, CTAG_PB_KRP, CRYPT_ERROR },
{ CTAG_PB_RR, CTAG_PB_RP, CRYPT_REQUESTTYPE_REVOCATION },
{ CTAG_PB_CCR, CTAG_PB_CCP, CRYPT_ERROR },
{ CTAG_PB_GENM, CTAG_PB_GENP, CRYPT_REQUESTTYPE_PKIBOOT },
{ CTAG_PB_LAST, CTAG_PB_LAST, CRYPT_ERROR }
};
int reqToResp( const int reqType )
{
int i;
for( i = 0; reqRespMapTbl[ i ].request != reqType && \
reqRespMapTbl[ i ].request != CTAG_PB_LAST; i++ );
return( reqRespMapTbl[ i ].response );
}
static int reqToClibReq( const int reqType )
{
int i;
for( i = 0; reqRespMapTbl[ i ].request != reqType && \
reqRespMapTbl[ i ].request != CTAG_PB_LAST; i++ );
return( reqRespMapTbl[ i ].cryptlibRequest );
}
static int clibReqToReq( const int reqType )
{
int i;
for( i = 0; reqRespMapTbl[ i ].cryptlibRequest != reqType && \
reqRespMapTbl[ i ].request != CTAG_PB_LAST; i++ );
return( reqRespMapTbl[ i ].request );
}
/* Initialise the MAC info used to protect the messages */
int initMacInfo( const CRYPT_CONTEXT iMacContext, const void *userPassword,
const int userPasswordLength, const void *salt,
const int saltLength, const int iterations )
{
MECHANISM_DERIVE_INFO mechanismInfo;
RESOURCE_DATA msgData;
BYTE macKey[ CRYPT_MAX_HASHSIZE ];
const void *passwordPtr = userPassword;
int passwordLength = userPasswordLength, status;
/* Turn the user password into an HMAC key using the CMP/Entrust password
derivation mechanism */
setMechanismDeriveInfo( &mechanismInfo, macKey, CMP_HMAC_KEYSIZE,
passwordPtr, passwordLength, CRYPT_ALGO_SHA,
( void * ) salt, saltLength, iterations );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
&mechanismInfo, MECHANISM_CMP );
if( cryptStatusError( status ) )
return( status );
/* Load the key into the MAC context */
setMessageData( &msgData, macKey, CMP_HMAC_KEYSIZE );
status = krnlSendMessage( iMacContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEY );
zeroise( macKey, CRYPT_MAX_HASHSIZE );
return( status );
}
/* Initialise and destroy the protocol state information */
#define PROTOCOLINFO_SET_USERID 0x01
#define PROTOCOLINFO_SET_TRANSID 0x02
#define PROTOCOLINFO_SET_MACINFO 0x04
#define PROTOCOLINFO_SET_MACCTX 0x08
#define PROTOCOLINFO_SET_ALL ( PROTOCOLINFO_SET_USERID | \
PROTOCOLINFO_SET_TRANSID | \
PROTOCOLINFO_SET_MACINFO | \
PROTOCOLINFO_SET_MACCTX )
static void initProtocolInfo( CMP_PROTOCOL_INFO *protocolInfo,
const BOOLEAN isCryptlib )
{
memset( protocolInfo, 0, sizeof( CMP_PROTOCOL_INFO ) );
protocolInfo->iMacContext = protocolInfo->iAltMacContext = CRYPT_ERROR;
protocolInfo->authContext = CRYPT_ERROR;
if( isCryptlib )
protocolInfo->isCryptlib = TRUE;
}
static int setProtocolInfo( CMP_PROTOCOL_INFO *protocolInfo,
const void *userID, const int userIDlength,
const int flags )
{
RESOURCE_DATA msgData;
int status;
/* Set state info */
setMessageData( &msgData, protocolInfo->senderNonce, CMP_NONCE_SIZE );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
protocolInfo->senderNonceSize = CMP_NONCE_SIZE;
/* Set fixed identification information */
if( flags & PROTOCOLINFO_SET_USERID )
{
assert( isReadPtr( userID, userIDlength ) );
memcpy( protocolInfo->userID, userID, userIDlength );
protocolInfo->userIDsize = userIDlength;
}
if( flags & PROTOCOLINFO_SET_TRANSID )
{
setMessageData( &msgData, protocolInfo->transID, CMP_NONCE_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
protocolInfo->transIDsize = CMP_NONCE_SIZE;
}
/* Set the MAC info and context */
if( flags & PROTOCOLINFO_SET_MACINFO )
{
setMessageData( &msgData, protocolInfo->salt, CMP_NONCE_SIZE );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
protocolInfo->saltSize = CMP_NONCE_SIZE;
protocolInfo->iterations = CMP_PASSWORD_ITERATIONS;
}
if( flags & PROTOCOLINFO_SET_MACCTX )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
assert( protocolInfo->iMacContext == CRYPT_ERROR && \
protocolInfo->iAltMacContext == CRYPT_ERROR );
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
protocolInfo->iMacContext = createInfo.cryptHandle;
protocolInfo->useMACsend = protocolInfo->useMACreceive = TRUE;
}
return( CRYPT_OK );
}
static void destroyProtocolInfo( CMP_PROTOCOL_INFO *protocolInfo )
{
/* Destroy any active MAC contexts. The authContext is just a reference
to the appropriate context in the session info so we don't destroy it
here */
if( protocolInfo->iMacContext != CRYPT_ERROR )
krnlSendNotifier( protocolInfo->iMacContext, IMESSAGE_DECREFCOUNT );
if( protocolInfo->iAltMacContext != CRYPT_ERROR )
krnlSendNotifier( protocolInfo->iMacContext, IMESSAGE_DECREFCOUNT );
zeroise( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) );
}
/* Set up user authentication information (either a MAC context or a public
key) based on a request submitted by the client. This is done whenever
the client starts a new transaction with a new user ID or cert ID */
int initServerAuthentMAC( SESSION_INFO *sessionInfoPtr,
CMP_PROTOCOL_INFO *protocolInfo )
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
int status;
assert( protocolInfo->userIDsize == 9 );
/* Set up general authentication information and if there's user info
still present from a previous transaction, clear it */
status = setProtocolInfo( protocolInfo, NULL, 0,
PROTOCOLINFO_SET_MACCTX );
if( cryptStatusError( status ) )
return( status );
if( sessionInfoPtr->cmpUserInfo != CRYPT_ERROR )
{
krnlSendNotifier( sessionInfoPtr->cmpUserInfo,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->cmpUserInfo = CRYPT_ERROR;
}
/* Get the user info for the user identified by the user ID from the
cert store. If we get a not-found error we report it as "signer not
trusted", which can also mean "signer unknown" */
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID,
protocolInfo->userID, protocolInfo->userIDsize,
NULL, 0, KEYMGMT_FLAG_NONE );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PKIUSER );
if( cryptStatusError( status ) )
{
protocolInfo->pkiFailInfo = CMPFAILINFO_SIGNERNOTTRUSTED;
retExt( sessionInfoPtr, status,
"Couldn't find PKI user information for requested user" );
}
sessionInfoPtr->cmpUserInfo = getkeyInfo.cryptHandle;
protocolInfo->userIDchanged = FALSE;
/* Get the password from the PKI user object if necessary */
if( sessionInfoPtr->passwordLength <= 0 )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, sessionInfoPtr->password,
CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( sessionInfoPtr->cmpUserInfo,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't read PKI user data from PKI user object" );
sessionInfoPtr->passwordLength = msgData.length;
sessionInfoPtr->flags |= SESSION_ISENCODEDPW;
}
return( CRYPT_OK );
}
int initServerAuthentSign( SESSION_INFO *sessionInfoPtr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -