📄 ssl.c
字号:
}
else
/* If it's not an SSLv2 handshake it has to be an SSLv3/TLS
handshake */
if( type != SSL_MSG_HANDSHAKE )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Unknown SSL/TLS hello message type %d, should be %d",
type, SSL_MSG_HANDSHAKE );
}
else
if( type != packetType )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Unknown SSL/TLS message type %d, should be %d",
type, packetType );
if( *bufPtr++ != SSL_MAJOR_VERSION )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid SSL major version number %d", bufPtr[ -1 ] );
version = *bufPtr++;
if( version < SSL_MINOR_VERSION_SSL || \
version > ( ( ( packetType == SSL_MSG_SPECIAL_HANDSHAKE ) ? \
5 : SSL_MINOR_VERSION_TLS11 ) ) )
/* If it's the first handshake packet we allow versions up to a
hypothetical SSLv3.5 (which would be TLS 1.4), after that we
should have fallen back to a version that we understand */
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid SSL minor version number %d", version );
if( !isV2handshake )
{ totalLength = mgetWord( bufPtr ); }
if( totalLength < 1 || totalLength > sessionInfoPtr->receiveBufSize || \
( packetType != SSL_MSG_CHANGE_CIPHER_SPEC && \
totalLength < MIN_PACKET_SIZE ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid packet length %d", totalLength );
if( ( sessionInfoPtr->flags & SESSION_ISSECURE ) && \
( sessionInfoPtr->protocolFlags & SSL_PFLAG_EXPLICITIV ) )
{
/* If we're using an explicit IV, the IV data is counted as part of
the header so we have to adjust the payload read for the data that
we've already read */
memmove( sessionInfoPtr->receiveBuffer, bufPtr,
sessionInfoPtr->cryptBlocksize );
bufPtr = sessionInfoPtr->receiveBuffer + \
sessionInfoPtr->cryptBlocksize;
effectiveTotalLength = totalLength - sessionInfoPtr->cryptBlocksize;
assert( effectiveTotalLength > 0 );
}
else
{
bufPtr = sessionInfoPtr->receiveBuffer;
effectiveTotalLength = totalLength;
}
/* Read the payload packet(s) */
status = sread( &sessionInfoPtr->stream, bufPtr, effectiveTotalLength );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
if( status < effectiveTotalLength )
/* If we timed out during the handshake phase, treat it as a hard
timeout error */
retExt( sessionInfoPtr, CRYPT_ERROR_TIMEOUT,
"Timeout during packet data read, only got %d of %d bytes",
status, totalLength );
sessionInfoPtr->receiveBufPos = 0;
sessionInfoPtr->receiveBufEnd = totalLength;
if( handshakeInfo != NULL )
dualMacData( handshakeInfo, sessionInfoPtr->receiveBuffer,
totalLength );
if( isV2handshake )
{
/* SSLv2 puts the version info in the header, so we have to move the
data up in the buffer and drop in the minor version to return it
to the caller, with the high bit set to ensure that it doesn't
get confused with a normal SSL packet type */
memmove( sessionInfoPtr->receiveBuffer + 1,
sessionInfoPtr->receiveBuffer, totalLength );
sessionInfoPtr->receiveBuffer[ 0 ] = version | 0x80;
}
return( CRYPT_OK );
}
/* Check that the header of an SSL packet is in order:
byte ID = <type>
uint24 len
[ byte opaque = <nextByte>] */
int checkPacketHeader( SESSION_INFO *sessionInfoPtr, BYTE **bufPtrPtr,
const int type, const int minSize, const int nextByte )
{
BYTE *bufPtr = *bufPtrPtr;
int length;
if( *bufPtr++ != type || *bufPtr++ != 0 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid packet header 0x%02X 0x%02X", *bufPtrPtr[ 0 ],
*bufPtrPtr[ 1 ] );
length = mgetWord( bufPtr );
if( length < minSize || length > MAX_PACKET_SIZE || \
sessionInfoPtr->receiveBufPos + ID_SIZE + LENGTH_SIZE + length > \
sessionInfoPtr->receiveBufEnd )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid packet length", length );
if( nextByte != CRYPT_UNUSED && *bufPtr++ != nextByte )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid packet header data byte 0x%02X, expected 0x%02X",
bufPtr[ -1 ], nextByte );
*bufPtrPtr = bufPtr;
sessionInfoPtr->receiveBufPos = ID_SIZE + LENGTH_SIZE + length;
return( length );
}
/****************************************************************************
* *
* Shared Connect Functions *
* *
****************************************************************************/
/* Complete the dual MD5/SHA1 hash/MAC used in the finished message */
static int completeSSLDualMAC( const CRYPT_CONTEXT md5context,
const CRYPT_CONTEXT sha1context,
BYTE *hashValues, const char *label,
const BYTE *masterSecret )
{
RESOURCE_DATA msgData;
int status;
/* Generate the inner portion of the handshake message's MAC:
hash( handshake_messages || cl/svr_label || master_secret || pad1 ).
Note that the SHA-1 pad size is 40 bytes and not 44 (to get a total
length of 64 bytes), this is due to an error in the spec */
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, ( void * ) label,
SSL_SENDERLABEL_SIZE );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, ( void * ) label,
SSL_SENDERLABEL_SIZE );
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, ( void * ) masterSecret,
SSL_SECRET_SIZE );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, ( void * ) masterSecret,
SSL_SECRET_SIZE );
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, PROTOHMAC_PAD1, 48 );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, PROTOHMAC_PAD1, 40 );
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, "", 0 );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, "", 0 );
setMessageData( &msgData, hashValues, MD5MAC_SIZE );
status = krnlSendMessage( md5context, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, hashValues + MD5MAC_SIZE, SHA1MAC_SIZE );
status = krnlSendMessage( sha1context, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
if( cryptStatusError( status ) )
return( status );
/* Reset the hash contexts */
krnlSendMessage( md5context, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( sha1context, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
/* Generate the outer portion of the handshake message's MAC:
hash( master_secret || pad2 || inner_hash ) */
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, ( void * ) masterSecret,
SSL_SECRET_SIZE );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, ( void * ) masterSecret,
SSL_SECRET_SIZE );
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, PROTOHMAC_PAD2, 48 );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, PROTOHMAC_PAD2, 40 );
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, hashValues,
MD5MAC_SIZE );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, hashValues + MD5MAC_SIZE,
SHA1MAC_SIZE );
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, "", 0 );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, "", 0 );
setMessageData( &msgData, hashValues, MD5MAC_SIZE );
status = krnlSendMessage( md5context, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, hashValues + MD5MAC_SIZE, SHA1MAC_SIZE );
status = krnlSendMessage( sha1context, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
return( status );
}
static int completeTLSHashedMAC( const CRYPT_CONTEXT md5context,
const CRYPT_CONTEXT sha1context,
BYTE *hashValues, const char *label,
const BYTE *masterSecret )
{
MECHANISM_DERIVE_INFO mechanismInfo;
RESOURCE_DATA msgData;
BYTE hashBuffer[ 64 + CRYPT_MAX_HASHSIZE * 2 ];
const int labelLength = strlen( label );
int status;
memcpy( hashBuffer, label, labelLength );
/* Complete the hashing and get the MD5 and SHA-1 hashes */
krnlSendMessage( md5context, IMESSAGE_CTX_HASH, "", 0 );
krnlSendMessage( sha1context, IMESSAGE_CTX_HASH, "", 0 );
setMessageData( &msgData, hashBuffer + labelLength, MD5MAC_SIZE );
status = krnlSendMessage( md5context, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, hashBuffer + labelLength + MD5MAC_SIZE,
SHA1MAC_SIZE );
status = krnlSendMessage( sha1context, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
if( cryptStatusError( status ) )
return( status );
/* Generate the TLS check value. This isn't really a hash or a MAC, but
is generated by feeding the MD5 and SHA1 hashes of the handshake
messages into the TLS key derivation (PRF) function and truncating
the result to 12 bytes for no adequately explored reason, most
probably it's IPsec cargo cult protocol design:
TLS_PRF( label || MD5_hash || SHA1_hash ) */
setMechanismDeriveInfo( &mechanismInfo, hashValues, TLS_HASHEDMAC_SIZE,
( void * ) masterSecret, 48, CRYPT_USE_DEFAULT,
hashBuffer, labelLength + MD5MAC_SIZE + SHA1MAC_SIZE, 1 );
return( krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE,
&mechanismInfo, MECHANISM_TLS ) );
}
/* Complete the handshake with the client or server. The logic gets a bit
complex here because the roles of the client and server are reversed if
we're resuming a session:
Normal Resumed
Client Server Client Server
------ ------ ------ ------
KeyEx ---> <--- Hello
CCS ---> <--- CCS
Fin ---> <--- Fin
<--- CCS CCS --->
<--- Fin Fin --->
Because of this the handshake-completion step treats the two sides as
initiator and responder rather than client and server. The overall flow
is then:
dualMAC( initiator );
if( !initiator )
read initiator CCS;
dualMAC( responder );
send initiator/responder CCS;
if( initiator )
read responder CCS; */
static int readHandshakeCompletionData( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
const BYTE *hashValues )
{
BYTE *bufPtr;
const int macValueLength = \
( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL ) ? \
MD5MAC_SIZE + SHA1MAC_SIZE : TLS_HASHEDMAC_SIZE;
int status, length;
/* Process the other side's change cipher spec (we could do this more
simply via an sread() and memcmp() against a template but that
doesn't process alerts properly). Since change cipherspec is its
own protocol, the packet data consists of only a '1' byte:
byte 1
At this point we've sent our change cipher spec (so the send channel
is in the secure state) but haven't received the other side's one yet
so the receive channel isn't. To handle this we need to temporarily
turn off the secure-session flag to ensure that there's no security
processing applied to the received message */
sessionInfoPtr->flags &= ~SESSION_ISSECURE;
status = readPacketSSL( sessionInfoPtr, NULL,
SSL_MSG_CHANGE_CIPHER_SPEC );
sessionInfoPtr->flags |= SESSION_ISSECURE;
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
if( *bufPtr++ != 1 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid change cipher spec payload, expected 0x01, got "
"0x%02X", bufPtr[ -1 ] );
/* Change cipher spec was the last message not subject to security
encapsulation, if we're using explicit IVs the effective header size
changes at this point because of the extra IV data so we update the
receive buffer start offset to accomodate this */
if( sessionInfoPtr->protocolFlags & SSL_PFLAG_EXPLICITIV )
sessionInfoPtr->receiveBufStartOfs += sessionInfoPtr->cryptBlocksize;
/* Process the other side's finished. Since this is the first chance that
we have to test whether our crypto keys are set up correctly, we
report problems with decryption or MAC'ing or a failure to find any
recognisable header as a wrong key rather than bad data error:
SSLv3 TLS
byte ID = 0x14 byte ID = 0x14
uint24 len uint24 len
byte[16] MD5 MAC byte[12] hashedMAC
byte[20] SHA-1 MAC */
status = readPacketSSL( sessionInfoPtr, NULL, SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
bufPtr = sessionInfoPtr->receiveBuffer;
length = sessionInfoPtr->receiveBufEnd;
if( sessionInfoPtr->protocolFlags & SSL_PFLAG_EXPLICITIV )
{
#if 0
/* If we're using explicit IVs, the first block constitutes the IV.
Decrypt it and discard it (alternate code used when we can't
reload an IV during decryption) */
status = krnlSe
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -