📄 ssl.c
字号:
for( premaster_index = 0; premaster_index < 48; )
{
int i;
premaster_secret[ premaster_index++ ] = shared_secret_length;
for( i = 0; i < shared_secret_length && premaster_index < 48; i++ )
premaster_secret[ premaster_index++ ] = shared_secret[ i ];
}
}
int createSharedMasterSecret( BYTE *masterSecret,
const SESSION_INFO *sessionInfoPtr )
{
MECHANISM_DERIVE_INFO mechanismInfo;
BYTE premasterSecret[ SSL_SECRET_SIZE ];
int status;
/* Expand the shared secret to create the premaster secret */
if( sessionInfoPtr->flags & SESSION_ISENCODEDPW )
{
BYTE decodedValue[ CRYPT_MAX_TEXTSIZE ];
int decodedValueLength;
/* It's a cryptlib-style encoded password, decode it into its binary
value */
decodedValueLength = decodePKIUserValue( decodedValue,
sessionInfoPtr->password,
sessionInfoPtr->passwordLength );
if( cryptStatusError( decodedValueLength ) )
{
assert( NOTREACHED );
return( decodedValueLength );
}
expandSharedSecret( premasterSecret, decodedValue,
min( decodedValueLength, SSL_SECRET_SIZE ) );
zeroise( decodedValue, CRYPT_MAX_TEXTSIZE );
}
else
expandSharedSecret( premasterSecret, sessionInfoPtr->password,
min( sessionInfoPtr->passwordLength,
SSL_SECRET_SIZE ) );
/* Create the master secret from the expanded user-supplied password.
Note that since the use of shared secrets is specified only for TLS,
we always use the TLS key derivation even if it's with the SSL
protocol */
setMechanismDeriveInfo( &mechanismInfo,
masterSecret, SSL_SECRET_SIZE,
premasterSecret, SSL_SECRET_SIZE,
CRYPT_USE_DEFAULT, "shared secret", 13, 1 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_DERIVE, &mechanismInfo,
MECHANISM_TLS );
zeroise( premasterSecret, SSL_SECRET_SIZE );
return( status );
}
/* Encrypt/decrypt a data block */
static int encryptData( const SESSION_INFO *sessionInfoPtr, BYTE *data,
const int dataLength )
{
int length = dataLength, status;
assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength > 0 && dataLength <= MAX_PACKET_SIZE + 20 );
assert( isWritePtr( data, dataLength ) );
/* If it's a block cipher, we need to add end-of-block padding */
if( sessionInfoPtr->cryptBlocksize > 1 )
{
BYTE *dataPadPtr = data + dataLength;
const int padSize = ( sessionInfoPtr->cryptBlocksize - 1 ) - \
( dataLength & ( sessionInfoPtr->cryptBlocksize - 1 ) );
int i;
/* Add the PKCS #5-style padding (PKCS #5 uses n, TLS uses n-1) */
for( i = 0; i < padSize + 1; i++ )
*dataPadPtr++ = padSize;
length += padSize + 1;
}
status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
IMESSAGE_CTX_ENCRYPT, data, length );
return( cryptStatusError( status ) ? status : length );
}
static int decryptData( SESSION_INFO *sessionInfoPtr, BYTE *data,
const int dataLength )
{
int length = dataLength, status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength > 0 && dataLength <= sessionInfoPtr->receiveBufEnd );
assert( isWritePtr( data, dataLength ) );
/* Decrypt the data */
status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
IMESSAGE_CTX_DECRYPT, data, length );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Decryption of SSL packet failed" );
/* If it's a block cipher, we need to remove end-of-block padding. Up
until TLS 1.1 the spec was silent about any requirement to check the
padding (and for SSLv3 it didn't specify the padding format at all)
so it's not really safe to reject an SSL a message if we don't find
the correct padding because many SSL implementations didn't process
the padded space in any way, leaving it containing whatever was there
before. Almost all TLS implementations get it right (even though in
TLS 1.0 there was only a requirement to generate, but not to check,
the PKCS #5-style padding). Because of this we only check the
padding bytes if we're talking TLS */
if( sessionInfoPtr->cryptBlocksize > 1 )
{
const int padSize = data[ dataLength - 1 ];
/* Make sure that the padding info looks OK. TLS allows up to 256
bytes of padding, but there are no known implementations that do
this. This is convenient because it allows us to quickly detect
most invalid decrypts */
if( padSize < 0 || padSize > sessionInfoPtr->cryptBlocksize - 1 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid padding value 0x%02X", padSize );
length -= padSize + 1;
if( length < 0 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Padding adjustment value 0x%02X is greater than packet "
"length %d", padSize, dataLength );
/* Check for PKCS #5-type padding (PKCS #5 uses n, TLS uses n-1) if
necessary */
if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
{
int i;
for( i = 0; i < padSize; i++ )
if( data[ length + i ] != padSize )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid padding byte 0x%02X at position %d",
data[ length + i ], length + i );
}
}
return( length );
}
/* Perform a MAC or dual MAC of a data block. We have to provide special-
case handling of zero-length blocks since some versions of OpenSSL send
these as a kludge to work around chosen-IV attacks */
static int macDataSSL( SESSION_INFO *sessionInfoPtr, const void *data,
const int dataLength, const int type,
const BOOLEAN isRead )
{
RESOURCE_DATA msgData;
BYTE buffer[ 128 ], *bufPtr;
BYTE *macPtr = isRead ? buffer : ( BYTE * ) data + dataLength;
const CRYPT_CONTEXT iHashContext = isRead ? \
sessionInfoPtr->iAuthInContext : sessionInfoPtr->iAuthOutContext;
const void *macSecret = isRead ? \
sessionInfoPtr->sslMacReadSecret : sessionInfoPtr->sslMacWriteSecret;
const long seqNo = isRead ? \
sessionInfoPtr->readSeqNo++ : sessionInfoPtr->writeSeqNo++;
const int padSize = \
( sessionInfoPtr->integrityAlgo == CRYPT_ALGO_MD5 ) ? 48 : 40;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
assert( isReadPtr( data, dataLength ) );
/* Set up the sequence number and length data */
memcpy( buffer, PROTOHMAC_PAD1, padSize );
memset( buffer + padSize, 0, SEQNO_SIZE );
bufPtr = buffer + padSize + 4;
mputLong( bufPtr, seqNo );
*bufPtr++ = type;
mputWord( bufPtr, dataLength );
/* Reset the hash context and generate the inner portion of the MAC:
hash( MAC_secret || pad1 || seq_num || type || length || data ) */
krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) macSecret,
sessionInfoPtr->authBlocksize );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
padSize + SEQNO_SIZE + ID_SIZE + UINT16_SIZE );
if( dataLength > 0 )
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
return( status );
/* Extract the inner hash value */
memcpy( buffer, PROTOHMAC_PAD2, padSize );
setMessageData( &msgData, buffer + padSize, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusError( status ) )
return( status );
/* Generate the outer portion of the handshake message's MAC and get the
MAC value, which is either written to the end of the data (for a
write) or to a separate buffer (for a read):
hash( MAC_secret || pad2 || inner_hash ) */
krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) macSecret,
sessionInfoPtr->authBlocksize );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
padSize + msgData.length );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, macPtr, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
if( cryptStatusError( status ) )
return( status );
/* If it's a read, compare the calculated MAC to the MAC present at the
end of the data */
if( isRead )
{
if( memcmp( macPtr, ( BYTE * ) data + dataLength, msgData.length ) )
retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
"Bad message MAC" );
return( CRYPT_OK );
}
return( dataLength + msgData.length );
}
static int macDataTLS( SESSION_INFO *sessionInfoPtr, const void *data,
const int dataLength, const int type,
const BOOLEAN isRead )
{
RESOURCE_DATA msgData;
BYTE buffer[ 128 ], *bufPtr;
BYTE *macPtr = isRead ? buffer : ( BYTE * ) data + dataLength;
const CRYPT_CONTEXT iHashContext = isRead ? \
sessionInfoPtr->iAuthInContext : sessionInfoPtr->iAuthOutContext;
const long seqNo = isRead ? \
sessionInfoPtr->readSeqNo++ : sessionInfoPtr->writeSeqNo++;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
assert( isReadPtr( data, dataLength ) );
/* Set up the sequence number, type, version, and length data */
memset( buffer, 0, SEQNO_SIZE );
bufPtr = buffer + 4;
mputLong( bufPtr, seqNo );
*bufPtr++ = type;
*bufPtr++ = SSL_MAJOR_VERSION;
*bufPtr++ = SSL_MINOR_VERSION_TLS;
mputWord( bufPtr, dataLength );
/* Reset the hash context and generate the MAC, which is either written
to the end of the data (for a write) or to a separate buffer (for a
read):
HMAC( seq_num || type || version || length || data ) */
krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
SEQNO_SIZE + ID_SIZE + VERSIONINFO_SIZE + UINT16_SIZE );
if( dataLength > 0 )
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, macPtr, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
if( cryptStatusError( status ) )
return( status );
/* If it's a read, compare the calculated MAC to the MAC present at the
end of the data */
if( isRead )
{
if( memcmp( macPtr, ( BYTE * ) data + dataLength, msgData.length ) )
retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
"Bad message MAC" );
return( CRYPT_OK );
}
return( dataLength + msgData.length );
}
int dualMacData( const SSL_HANDSHAKE_INFO *handshakeInfo, const void *data,
const int dataLength )
{
int status;
status = krnlSendMessage( handshakeInfo->clientMD5context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
if( cryptStatusOK( status ) )
status = krnlSendMessage( handshakeInfo->clientSHA1context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
if( cryptStatusOK( status ) )
status = krnlSendMessage( handshakeInfo->serverMD5context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
if( cryptStatusOK( status ) )
status = krnlSendMessage( handshakeInfo->serverSHA1context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
return( status );
}
/* Wrap/unwrap an SSL data packet. These functions process data as follows:
------ MAC'd
======================= Encrypted
[ hdr | IV | data | MAC | pad ] |
| +------+ | Wrap, adds hdr, IV, MAC, pad,
| | | returns total length
buffer length
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -