From 1f98b97756b324159ff071cec31e92f6fc629133 Mon Sep 17 00:00:00 2001
From: Guus der Kinderen <guus.der.kinderen@gmail.com>
Date: Fri, 10 Nov 2017 19:47:07 +0100
Subject: [PATCH] Allow SSLv2 CLIENT-HELLO (without SSL 2.0)

The existing TLS probe is documented to ignore SSL 2.0, citing RFC 6176 as a reason.
RFC 6176 does prohibit the usage of SSL 2.0, but does allow for ClientHello messages
in the version 2 CLIENT-HELLO format (as long as those are used to negotiate the use
of a higher protocol).

This commit extends the TLS probe, by making it accept SSL v2 ClientHello messages
that negotiate a version of SSL/TLS 1.0 or higher (which is the same version range
as the original code).
---
 probe.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/probe.c b/probe.c
index 9b4a63e..8e12d53 100644
--- a/probe.c
+++ b/probe.c
@@ -236,14 +236,30 @@ static int is_sni_alpn_protocol(const char *p, int len, struct proto *proto)
 
 static int is_tls_protocol(const char *p, int len, struct proto *proto)
 {
-    if (len < 3)
+    if (len < 6)
         return PROBE_AGAIN;
 
-    /* TLS packet starts with a record "Hello" (0x16), followed by version
-     * (0x03 0x00-0x03) (RFC6101 A.1)
-     * This means we reject SSLv2 and lower, which is actually a good thing (RFC6176)
+    /* TLS packet starts with a record "Hello" (0x16), followed by the number of
+     * the highest version of SSL/TLS supported.
+     *
+     * A SSLv2 record header contains a two or three byte length code. If the
+     * most significant bit is set in the first byte of the record length code
+     * then the record has no padding and the total header length will be 2
+     * bytes,  otherwise the record has padding and the total header length will
+     * be 3 bytes. Next, a 1 char sized client-hello (0x01) is expected,
+     * followed by a 2 char sized version that indicates the highest version of
+     * TLS/SSL supported by the sender. [SSL2] Hickman, Kipp, "The SSL Protocol"
+     *
+     * We're checking the highest version of TLS/SSL supported against
+     * (0x03 0x00-0x03) (RFC6101 A.1). This means we reject the usage of SSLv2
+     * and lower, which is actually a good thing (RFC6176).
      */
-    return p[0] == 0x16 && p[1] == 0x03 && ( p[2] >= 0 && p[2] <= 0x03);
+    if (p[0] == 0x16) // TLS client-hello
+        return p[1] == 0x03 && ( p[2] >= 0 && p[2] <= 0x03);
+    if ((p[0] & 0x80) != 0) // SSLv2 client-hello, no padding
+        return p[2] == 0x01 && p[3] == 0x03 && ( p[4] >= 0 && p[4] <= 0x03);
+    else // SSLv2 client-hello, padded
+        return p[3] == 0x01 && p[4] == 0x03 && ( p[5] >= 0 && p[5] <= 0x03);
 }
 
 static int is_adb_protocol(const char *p, int len, struct proto *proto)