📄 ssl_kmgmt.c
字号:
if( cryptStatusError( status ) )
{
assert( DEBUG_WARN );
return( status );
}
writeUint16( &stream, decodedValueLength );
swrite( &stream, zeroes, decodedValueLength );
writeUint16( &stream, decodedValueLength );
status = swrite( &stream, decodedValue, decodedValueLength );
zeroise( decodedValue, decodedValueLength );
}
else
{
writeUint16( &stream, attributeListPtr->valueLength );
swrite( &stream, zeroes, attributeListPtr->valueLength );
writeUint16( &stream, attributeListPtr->valueLength );
status = swrite( &stream, attributeListPtr->value,
attributeListPtr->valueLength );
}
if( cryptStatusError( status ) )
{
assert( DEBUG_WARN );
return( status );
}
*premasterSecretLength = stell( &stream );
sMemDisconnect( &stream );
return( CRYPT_OK );
}
/* Wrap/unwrap the pre-master secret */
int wrapPremasterSecret( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
void *data, const int dataMaxLength,
int *dataLength )
{
MECHANISM_WRAP_INFO mechanismInfo;
MESSAGE_DATA msgData;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
assert( isWritePtr( data, dataMaxLength ) );
assert( isWritePtr( dataLength, sizeof( int ) ) );
/* Clear return value */
memset( data, 0, dataMaxLength );
*dataLength = 0;
/* Create the premaster secret and wrap it using the server's public
key. Note that the version that we advertise at this point is the
version originally offered by the client in its hello message, not
the version eventually negotiated for the connection. This is
designed to prevent rollback attacks (but see also the comment in
unwrapPremasterSecret() below) */
handshakeInfo->premasterSecretSize = SSL_SECRET_SIZE;
handshakeInfo->premasterSecret[ 0 ] = SSL_MAJOR_VERSION;
handshakeInfo->premasterSecret[ 1 ] = handshakeInfo->clientOfferedVersion;
setMessageData( &msgData,
handshakeInfo->premasterSecret + VERSIONINFO_SIZE,
handshakeInfo->premasterSecretSize - VERSIONINFO_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM );
if( cryptStatusError( status ) )
return( status );
setMechanismWrapInfo( &mechanismInfo, data, dataMaxLength,
handshakeInfo->premasterSecret,
handshakeInfo->premasterSecretSize, CRYPT_UNUSED,
sessionInfoPtr->iKeyexCryptContext );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT,
&mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
if( cryptStatusOK( status ) )
*dataLength = mechanismInfo.wrappedDataLength;
clearMechanismInfo( &mechanismInfo );
return( status );
}
int unwrapPremasterSecret( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
const void *data, const int dataLength )
{
MECHANISM_WRAP_INFO mechanismInfo;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
assert( isReadPtr( data, dataLength ) );
/* Decrypt the encrypted premaster secret. In theory we could
explicitly defend against Bleichenbacher-type attacks at this point
by setting the premaster secret to a pseudorandom value if we get a
bad data or (later) an incorrect version error and continuing as
normal, however the attack depends on the server returning
information required to pinpoint the cause of the failure and
cryptlib just returns a generic "failed" response for any handshake
failure, so this explicit defence isn't really necessary.
There's a second, lower-grade level of oracle that an attacker can
use in the version check if they can distinguish between a decrypt
failure due to bad PKCS #1 padding and a failure due to a bad version
number (see "Attacking RSA-based Sessions in SSL/TLS", Vlastimil
Klima, Ondrej Pokorny, and Tomas Rosa, CHES'03). If we use the
Bleichenbacher defence and continue the handshake on bad padding but
bail out on a bad version then the two cases can be distinguished,
however since cryptlib bails out immediately in either case the two
shouldn't be distinguishable */
handshakeInfo->premasterSecretSize = SSL_SECRET_SIZE;
setMechanismWrapInfo( &mechanismInfo, ( void * ) data, dataLength,
handshakeInfo->premasterSecret,
handshakeInfo->premasterSecretSize, CRYPT_UNUSED,
sessionInfoPtr->privateKey );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
&mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
if( cryptStatusOK( status ) && \
mechanismInfo.keyDataLength != handshakeInfo->premasterSecretSize )
status = CRYPT_ERROR_BADDATA;
clearMechanismInfo( &mechanismInfo );
if( cryptStatusError( status ) )
return( status );
/* Make sure that it looks OK. Note that the version that we check for
at this point is the version originally offered by the client in its
hello message, not the version eventually negotiated for the
connection. This is designed to prevent rollback attacks */
if( handshakeInfo->premasterSecret[ 0 ] != SSL_MAJOR_VERSION || \
handshakeInfo->premasterSecret[ 1 ] != handshakeInfo->clientOfferedVersion )
{
/* Microsoft braindamage, even the latest versions of MSIE still send
the wrong version number for the premaster secret (making it look
like a rollback attack), so if we're expecting 3.1 and get 3.0, it's
MSIE screwing up */
if( handshakeInfo->premasterSecret[ 0 ] == SSL_MAJOR_VERSION && \
handshakeInfo->premasterSecret[ 1 ] == SSL_MINOR_VERSION_SSL && \
sessionInfoPtr->version == SSL_MINOR_VERSION_SSL && \
handshakeInfo->clientOfferedVersion == SSL_MINOR_VERSION_TLS )
{
ERROR_INFO *errorInfo = &sessionInfoPtr->errorInfo;
setErrorString( errorInfo,
"Warning: Accepting invalid premaster secret "
"version 3.0 (MSIE bug)", 66 );
}
else
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid premaster secret version data 0x%02X 0x%02X, "
"expected 0x03 0x%02X",
handshakeInfo->premasterSecret[ 0 ],
handshakeInfo->premasterSecret[ 1 ],
handshakeInfo->clientOfferedVersion ) );
}
}
return( CRYPT_OK );
}
/* Convert a pre-master secret to a master secret, and a master secret to
keying material */
int premasterToMaster( const SESSION_INFO *sessionInfoPtr,
const SSL_HANDSHAKE_INFO *handshakeInfo,
void *masterSecret, const int masterSecretLength )
{
MECHANISM_DERIVE_INFO mechanismInfo;
BYTE nonceBuffer[ 64 + SSL_NONCE_SIZE + SSL_NONCE_SIZE + 8 ];
assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isReadPtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
assert( isReadPtr( masterSecret, masterSecretLength ) );
if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
{
memcpy( nonceBuffer, handshakeInfo->clientNonce, SSL_NONCE_SIZE );
memcpy( nonceBuffer + SSL_NONCE_SIZE, handshakeInfo->serverNonce,
SSL_NONCE_SIZE );
setMechanismDeriveInfo( &mechanismInfo, masterSecret,
masterSecretLength,
handshakeInfo->premasterSecret,
handshakeInfo->premasterSecretSize,
CRYPT_USE_DEFAULT, nonceBuffer,
SSL_NONCE_SIZE + SSL_NONCE_SIZE, 1 );
return( krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
&mechanismInfo, MECHANISM_DERIVE_SSL ) );
}
memcpy( nonceBuffer, "master secret", 13 );
memcpy( nonceBuffer + 13, handshakeInfo->clientNonce, SSL_NONCE_SIZE );
memcpy( nonceBuffer + 13 + SSL_NONCE_SIZE, handshakeInfo->serverNonce,
SSL_NONCE_SIZE );
setMechanismDeriveInfo( &mechanismInfo, masterSecret, masterSecretLength,
handshakeInfo->premasterSecret,
handshakeInfo->premasterSecretSize,
CRYPT_USE_DEFAULT, nonceBuffer,
13 + SSL_NONCE_SIZE + SSL_NONCE_SIZE, 1 );
return( krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
&mechanismInfo, MECHANISM_DERIVE_TLS ) );
}
int masterToKeys( const SESSION_INFO *sessionInfoPtr,
const SSL_HANDSHAKE_INFO *handshakeInfo,
const void *masterSecret, const int masterSecretLength,
void *keyBlock, const int keyBlockLength )
{
MECHANISM_DERIVE_INFO mechanismInfo;
BYTE nonceBuffer[ 64 + SSL_NONCE_SIZE + SSL_NONCE_SIZE + 8 ];
assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isReadPtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
assert( isReadPtr( masterSecret, masterSecretLength ) );
assert( isWritePtr( keyBlock, keyBlockLength ) );
if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
{
memcpy( nonceBuffer, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
memcpy( nonceBuffer + SSL_NONCE_SIZE, handshakeInfo->clientNonce,
SSL_NONCE_SIZE );
setMechanismDeriveInfo( &mechanismInfo, keyBlock, keyBlockLength,
masterSecret, masterSecretLength, CRYPT_USE_DEFAULT,
nonceBuffer, SSL_NONCE_SIZE + SSL_NONCE_SIZE, 1 );
return( krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
&mechanismInfo, MECHANISM_DERIVE_SSL ) );
}
memcpy( nonceBuffer, "key expansion", 13 );
memcpy( nonceBuffer + 13, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
memcpy( nonceBuffer + 13 + SSL_NONCE_SIZE, handshakeInfo->clientNonce,
SSL_NONCE_SIZE );
setMechanismDeriveInfo( &mechanismInfo, keyBlock, keyBlockLength,
masterSecret, masterSecretLength, CRYPT_USE_DEFAULT,
nonceBuffer, 13 + SSL_NONCE_SIZE + SSL_NONCE_SIZE, 1 );
return( krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
&mechanismInfo, MECHANISM_DERIVE_TLS ) );
}
/* Load the SSL/TLS cryptovariables */
int loadKeys( SESSION_INFO *sessionInfoPtr,
const SSL_HANDSHAKE_INFO *handshakeInfo,
const void *keyBlock, const int keyBlockLength,
const BOOLEAN isClient )
{
SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
MESSAGE_DATA msgData;
BYTE *keyBlockPtr = ( BYTE * ) keyBlock;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isReadPtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
assert( isReadPtr( keyBlock, keyBlockLength ) );
/* Sanity-check the state */
if( keyBlockLength < ( sessionInfoPtr->authBlocksize * 2 ) + \
( handshakeInfo->cryptKeysize * 2 ) + \
( sessionInfoPtr->cryptBlocksize * 2 ) )
retIntError();
/* Load the keys and secrets:
( client_write_mac || server_write_mac || \
client_write_key || server_write_key || \
client_write_iv || server_write_iv )
First, we load the MAC keys. For TLS these are proper MAC keys, for
SSL we have to build the proto-HMAC ourselves from a straight hash
context so we store the raw cryptovariables rather than loading them
into a context */
if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
{
memcpy( isClient ? sslInfo->macWriteSecret : sslInfo->macReadSecret,
keyBlockPtr, sessionInfoPtr->authBlocksize );
memcpy( isClient ? sslInfo->macReadSecret : sslInfo->macWriteSecret,
keyBlockPtr + sessionInfoPtr->authBlocksize,
sessionInfoPtr->authBlocksize );
}
else
{
setMessageData( &msgData, keyBlockPtr, sessionInfoPtr->authBlocksize );
status = krnlSendMessage( isClient ? \
sessionInfoPtr->iAuthOutContext : \
sessionInfoPtr->iAuthInContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY );
if( cryptStatusError( status ) )
return( status );
setMessageData( &msgData, keyBlockPtr + sessionInfoPtr->authBlocksize,
sessionInfoPtr->authBlocksize );
status = krnlSendMessage( isClient ? \
sessionInfoPtr->iAuthInContext: \
sessionInfoPtr->iAuthOutContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY );
if( cryptStatusError( status ) )
return( status );
}
keyBlockPtr += sessionInfoPtr->authBlocksize * 2;
/* Then we load the encryption keys */
setMessageData( &msgData, keyBlockPtr, handshakeInfo->cryptKeysize );
status = krnlSendMessage( isClient ? \
sessionInfoPtr->iCryptOutContext : \
sessionInfoPtr->iCryptInContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY );
keyBlockPtr += handshakeInfo->cryptKeysize;
if( cryptStatusError( status ) )
return( status );
setMessageData( &msgData, keyBlockPtr, handshakeInfo->cryptKeysize );
status = krnlSendMessage( isClient ? \
sessionInfoPtr->iCryptInContext : \
sessionInfoPtr->iCryptOutContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY );
keyBlockPtr += handshakeInfo->cryptKeysize;
if( cryptStatusError( status ) )
return( status );
/* Finally we load the IVs if required. This load is actually redundant
for TLS 1.1, which uses explicit IVs, but it's easier to just do it
anyway */
if( isStreamCipher( sessionInfoPtr->cryptAlgo ) )
return( CRYPT_OK ); /* No IV, we're done */
setMessageData( &msgData, keyBlockPtr,
sessionInfoPtr->cryptBlocksize );
krnlSendMessage( isClient ? sessionInfoPtr->iCryptOutContext : \
sessionInfoPtr->iCryptInContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
keyBlockPtr += sessionInfoPtr->cryptBlocksize;
setMessageData( &msgData, keyBlockPtr,
sessionInfoPtr->cryptBlocksize );
return( krnlSendMessage( isClient ? sessionInfoPtr->iCryptInContext : \
sessionInfoPtr->iCryptOutContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV ) );
}
/* TLS versions greater than 1.0 prepend an explicit IV to the data, the
following function loads this from the packet data stream */
int loadExplicitIV( SESSION_INFO *sessionInfoPtr, STREAM *stream,
int *ivLength )
{
MESSAGE_DATA msgData;
BYTE iv[ CRYPT_MAX_IVSIZE + 8 ];
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( ivLength, sizeof( int ) ) );
/* Clear return value */
*ivLength = 0;
/* Read and load the IV */
status = sread( stream, iv, sessionInfoPtr->cryptBlocksize );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, iv, sessionInfoPtr->cryptBlocksize );
status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
}
if( cryptStatusError( status ) )
retExt( status,
( status, SESSION_ERRINFO, "Packet IV read/load failed" ) );
/* Tell the caller how much data we've consumed */
*ivLength = sessionInfoPtr->cryptBlocksize;
/* The following alternate code, which decrypts and discards the first
block, can be used when we're using hardware cryptologic that doesn't
allow a reaload of the IV during decryption */
#if 0
status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
IMESSAGE_CTX_DECRYPT, iv,
sessionInfoPtr->cryptBlocksize );
#endif /* 0 */
return( CRYPT_OK );
}
#endif /* USE_SSL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -