private Framing DetectFraming(byte[] bytes, int length)
{
/* PCTv1.0 Hello starts with
* RECORD_LENGTH_MSB (ignore)
* RECORD_LENGTH_LSB (ignore)
* PCT1_CLIENT_HELLO (must be equal)
* PCT1_CLIENT_VERSION_MSB (if version greater than PCTv1)
* PCT1_CLIENT_VERSION_LSB (if version greater than PCTv1)
*
* ... PCT hello ...
*/
/* Microsoft Unihello starts with
* RECORD_LENGTH_MSB (ignore)
* RECORD_LENGTH_LSB (ignore)
* SSL2_CLIENT_HELLO (must be equal)
* SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3)
* SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3)
*
* ... SSLv2 Compatible Hello ...
*/
/* SSLv2 CLIENT_HELLO starts with
* RECORD_LENGTH_MSB (ignore)
* RECORD_LENGTH_LSB (ignore)
* SSL2_CLIENT_HELLO (must be equal)
* SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3)
* SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3)
*
* ... SSLv2 CLIENT_HELLO ...
*/
/* SSLv2 SERVER_HELLO starts with
* RECORD_LENGTH_MSB (ignore)
* RECORD_LENGTH_LSB (ignore)
* SSL2_SERVER_HELLO (must be equal)
* SSL2_SESSION_ID_HIT (ignore)
* SSL2_CERTIFICATE_TYPE (ignore)
* SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3)
* SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3)
*
* ... SSLv2 SERVER_HELLO ...
*/
/* SSLv3 Type 2 Hello starts with
* RECORD_LENGTH_MSB (ignore)
* RECORD_LENGTH_LSB (ignore)
* SSL2_CLIENT_HELLO (must be equal)
* SSL2_CLIENT_VERSION_MSB (if version greater than SSLv3)
* SSL2_CLIENT_VERSION_LSB (if version greater than SSLv3)
*
* ... SSLv2 Compatible Hello ...
*/
/* SSLv3 Type 3 Hello starts with
* 22 (HANDSHAKE MESSAGE)
* VERSION MSB
* VERSION LSB
* RECORD_LENGTH_MSB (ignore)
* RECORD_LENGTH_LSB (ignore)
* HS TYPE (CLIENT_HELLO)
* 3 bytes HS record length
* HS Version
* HS Version
*/
/* SSLv2 message codes
* SSL_MT_ERROR 0
* SSL_MT_CLIENT_HELLO 1
* SSL_MT_CLIENT_MASTER_KEY 2
* SSL_MT_CLIENT_FINISHED 3
* SSL_MT_SERVER_HELLO 4
* SSL_MT_SERVER_VERIFY 5
* SSL_MT_SERVER_FINISHED 6
* SSL_MT_REQUEST_CERTIFICATE 7
* SSL_MT_CLIENT_CERTIFICATE 8
*/
int version = -1;
if ((bytes == null || bytes.Length <= 0))
{
NetEventSource.Fail(this, "Header buffer is not allocated.");
}
// If the first byte is SSL3 HandShake, then check if we have a SSLv3 Type3 client hello.
if (bytes[0] == (byte)FrameType.Handshake || bytes[0] == (byte)FrameType.AppData
|| bytes[0] == (byte)FrameType.Alert)
{
if (length < 3)
{
return Framing.Invalid;
}
#if TRACE_VERBOSE
if (bytes[1] != 3 && NetEventSource.IsEnabled)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"WARNING: SslState::DetectFraming() SSL protocol is > 3, trying SSL3 framing in retail = {bytes[i]:x}");
}
#endif
version = (bytes[1] << 8) | bytes[2];
if (version < 0x300 || version >= 0x500)
{
return Framing.Invalid;
}
//
// This is an SSL3 Framing
//
return Framing.SinceSSL3;
}
#if TRACE_VERBOSE
if ((bytes[0] & 0x80) == 0 && NetEventSource.IsEnabled)
{
// We have a three-byte header format
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"WARNING: SslState::DetectFraming() SSL v <=2 HELLO has no high bit set for 3 bytes header, we are broken, received byte = {bytes[0]:x}");
}
#endif
if (length < 3)
{
return Framing.Invalid;
}
if (bytes[2] > 8)
{
return Framing.Invalid;
}
if (bytes[2] == 0x1) // SSL_MT_CLIENT_HELLO
{
if (length >= 5)
{
version = (bytes[3] << 8) | bytes[4];
}
}
else if (bytes[2] == 0x4) // SSL_MT_SERVER_HELLO
{
if (length >= 7)
{
version = (bytes[5] << 8) | bytes[6];
}
}
if (version != -1)
{
// If this is the first packet, the client may start with an SSL2 packet
// but stating that the version is 3.x, so check the full range.
// For the subsequent packets we assume that an SSL2 packet should have a 2.x version.
if (_Framing == Framing.Unknown)
{
if (version != 0x0002 && (version < 0x200 || version >= 0x500))
{
return Framing.Invalid;
}
}
else
{
if (version != 0x0002)
{
return Framing.Invalid;
}
}
}
// When server has replied the framing is already fixed depending on the prior client packet
if (!Context.IsServer || _Framing == Framing.Unified)
{
return Framing.BeforeSSL3;
}
return Framing.Unified; // Will use Ssl2 just for this frame.
}