📄 cmp.c
字号:
RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
/* Decrypt the returned cert */
status = krnlSendMessage( iSessionKey, RESOURCE_IMESSAGE_CTX_DECRYPT,
sMemBufPtr( stream ), encCertLength );
krnlSendNotifier( iSessionKey, RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
/* Get information on a user from a cert store */
static int getUserInformation( SESSION_INFO *sessionInfoPtr,
const void *userID, const int userIDsize,
const BOOLEAN isPublicKey )
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
int status;
assert( sessionInfoPtr->iAuthInContext == CRYPT_ERROR );
/* Get the user info or public key from the cert store */
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID,
userID, userIDsize, NULL, 0, isPublicKey ? \
KEYMGMT_FLAG_USAGE_SIGN : KEYMGMT_FLAG_NONE );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
RESOURCE_IMESSAGE_KEY_GETKEY,
&getkeyInfo, isPublicKey ? \
KEYMGMT_ITEM_PUBLICKEY : KEYMGMT_ITEM_PKIUSER );
if( cryptStatusOK( status ) )
sessionInfoPtr->iAuthInContext = getkeyInfo.cryptHandle;
return( status );
}
/****************************************************************************
* *
* MAC Routines *
* *
****************************************************************************/
/* The CMP spec never defines any keysize for the CMP/Entrust MAC, but
everyone seems to use 160 bits for this */
#define HMAC_KEYSIZE 20
/* Initialise and destroy the protocol state information */
static int initProtocolInfo( CMP_PROTOCOL_INFO *protocolInfo,
const void *userID, const int userIDlength,
const BOOLEAN useMAC )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
/* Initialise the handshake state info values. If this is state held
by the responder, some of the data will already have been set up
from the contents of the initiator's message so we only start from
scratch if this is completely new data */
if( userID != NULL )
{
memset( protocolInfo, 0, sizeof( CMP_PROTOCOL_INFO ) );
memcpy( protocolInfo->userID, userID, userIDlength );
protocolInfo->userIDsize = userIDlength;
getNonce( protocolInfo->transID, CMP_NONCE_SIZE );
protocolInfo->transIDsize = CMP_NONCE_SIZE;
}
getNonce( protocolInfo->senderNonce, CMP_NONCE_SIZE );
protocolInfo->senderNonceSize = CMP_NONCE_SIZE;
protocolInfo->iMacContext = \
protocolInfo->iAltMacContext = CRYPT_ERROR;
protocolInfo->useMACsend = protocolInfo->useMACreceive = useMAC;
/* If we're not using a MAC for message protection, we're done */
if( !useMAC )
return( CRYPT_OK );
/* Set up the MAC values. We only set up the salt if we're the initiator
since the responder will get their salt from the incoming message */
if( userID != NULL )
{
getNonce( protocolInfo->salt, CMP_NONCE_SIZE );
protocolInfo->saltSize = CMP_NONCE_SIZE;
}
#ifdef SKIP_IO
puts( "CMP: Using fixed salt to allow MAC to verify." );
memcpy( protocolInfo->salt,
"\xDD\xEF\xCF\xC9\x93\x1F\x28\xA7\x55\x5A\x14\x9F\x13\x90\xE2\x60",
16 );
#endif /* SKIP_IO */
protocolInfo->iterations = CMP_PASSWORD_ITERATIONS;
/* Create the MAC context used to protect the messages */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
protocolInfo->iMacContext = createInfo.cryptHandle;
return( status );
}
static void destroyProtocolInfo( CMP_PROTOCOL_INFO *protocolInfo )
{
/* Destroy any active contexts */
if( protocolInfo->iMacContext != CRYPT_ERROR )
krnlSendNotifier( protocolInfo->iMacContext,
RESOURCE_IMESSAGE_DECREFCOUNT );
if( protocolInfo->iAltMacContext != CRYPT_ERROR )
krnlSendNotifier( protocolInfo->iMacContext,
RESOURCE_IMESSAGE_DECREFCOUNT );
zeroise( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) );
}
/* Initialise the MAC info used to protect the messages */
static 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 decodedPassword[ CRYPT_MAX_TEXTSIZE ];
BYTE macKey[ CRYPT_MAX_HASHSIZE ];
const void *passwordPtr = userPassword;
int passwordLength = userPasswordLength, status;
/* If it's a cryptlib-style password, decode it into its binary value.
We don't need to check the return value since the validity has already
been checked when the password was set*/
if( isUserValue( userPassword, userPasswordLength ) )
{
passwordLength = decodeUserValue( decodedPassword, userPassword,
userPasswordLength );
passwordPtr = decodedPassword;
}
/* Turn the user password into an HMAC key using the CMP/Entrust password
derivation mechanism */
setMechanismDeriveInfo( &mechanismInfo, macKey, HMAC_KEYSIZE,
passwordPtr, passwordLength, CRYPT_ALGO_SHA,
( void * ) salt, saltLength, iterations );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_DERIVE, &mechanismInfo,
MECHANISM_CMP );
if( cryptStatusError( status ) )
return( status );
/* Load the key into the MAC context */
setResourceData( &msgData, macKey, HMAC_KEYSIZE );
status = krnlSendMessage( iMacContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEY );
zeroise( macKey, CRYPT_MAX_HASHSIZE );
return( status );
}
/* Read/write 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)
}
} */
static void writeMacInfo( STREAM *stream,
const CMP_PROTOCOL_INFO *protocolInfo )
{
int paramSize;
/* Determine how big the payload will be */
paramSize = ( int ) sizeofObject( protocolInfo->saltSize ) + \
sizeofAlgoID( CRYPT_ALGO_SHA ) + \
sizeofShortInteger( CMP_PASSWORD_ITERATIONS ) + \
sizeofAlgoID( CRYPT_ALGO_HMAC_SHA );
/* Write the wrapper */
writeSequence( stream, sizeofOID( OID_ENTRUST_MAC ) + \
( int ) sizeofObject( paramSize ) );
writeOID( stream, OID_ENTRUST_MAC );
/* Write the payload */
writeSequence( stream, paramSize );
writeOctetString( stream, protocolInfo->salt, protocolInfo->saltSize,
DEFAULT_TAG );
writeAlgoID( stream, CRYPT_ALGO_SHA );
writeShortInteger( stream, CMP_PASSWORD_ITERATIONS, DEFAULT_TAG );
writeAlgoID( stream, CRYPT_ALGO_HMAC_SHA );
}
static int readMacInfo( STREAM *stream, CMP_PROTOCOL_INFO *protocolInfo,
const void *password, const int passwordLength )
{
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 have to specifically report it as an
unknown algorithm problem rather than a generic bad data error */
protocolInfo->pkiFailInfo = CMPFAILINFO_BADALG;
return( status );
}
readSequence( stream, NULL );
readOctetString( stream, salt, &saltLength, CRYPT_MAX_HASHSIZE );
readUniversal( stream );
readShortInteger( stream, &value );
status = readUniversal( stream );
if( cryptStatusError( status ) )
return( status );
iterations = ( int ) value;
if( 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) */
protocolInfo->pkiFailInfo = CMPFAILINFO_BADALG;
return( CRYPT_ERROR_BADDATA );
}
/* 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*/
if( !protocolInfo->saltSize )
{
status = initMacInfo( protocolInfo->iMacContext, password,
passwordLength, salt, saltLength, iterations );
memcpy( protocolInfo->salt, salt, saltLength );
protocolInfo->saltSize = saltLength;
protocolInfo->iterations = iterations;
return( status );
}
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 returned parameters
already set up from a previous message, 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 MAC context with them */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
status = initMacInfo( createInfo.cryptHandle, password, passwordLength,
salt, saltLength, iterations );
if( cryptStatusOK( status ) )
{
if( protocolInfo->iAltMacContext != CRYPT_ERROR )
krnlSendNotifier( protocolInfo->iAltMacContext,
RESOURCE_IMESSAGE_DECREFCOUNT );
protocolInfo->iAltMacContext = createInfo.cryptHandle;
memcpy( protocolInfo->altSalt, salt, saltLength );
protocolInfo->altSaltSize = saltLength;
protocolInfo->altIterations = iterations;
}
else
krnlSendNotifier( createInfo.cryptHandle,
RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
/* Hash/MAC the message header and body */
static int hashMessageContents( const CRYPT_CONTEXT iHashContext,
const void *data, const int length )
{
STREAM stream;
BYTE buffer[ 8 ];
/* Delete the hash/MAC value, which resets the context */
krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_DELETEATTRIBUTE,
NULL, CRYPT_CTXINFO_HASHVALUE );
/* Write the pseudoheader used for hashing/MACing the header and body and
hash/MAC it */
sMemOpen( &stream, buffer, 8 );
writeSequence( &stream, length );
krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_CTX_HASH, buffer,
stell( &stream ) );
sMemClose( &stream );
krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_CTX_HASH,
( void * ) data, length );
return( krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_CTX_HASH,
buffer, 0 ) );
}
/****************************************************************************
* *
* PKI Body Functions *
* *
****************************************************************************/
/* Write assorted PKI body messages */
static int writeRequestBody( STREAM *stream,
const SESSION_INFO *sessionInfoPtr,
const CMP_PROTOCOL_INFO *protocolInfo )
{
const CRYPT_ATTRIBUTE_TYPE attrType = \
( protocolInfo->operation == CTAG_PB_RR ) ? \
CRYPT_IATTRIBUTE_ENC_OBJDATA : CRYPT_IATTRIBUTE_ENC_CERT;
RESOURCE_DATA msgData;
int status;
UNUSED( protocolInfo );
/* Find out how big the payload will be. Since revocation requests are
unsigned entities we have to vary the attribute type we're reading
based on whether we're submitting a signed or unsigned object in the
request */
setResourceData( &msgData, NULL, 0 );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
attrType );
if( cryptStatusError( status ) )
return( status );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -