]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
app-layer-ssl: add support for TLSv1.3 from draft 22
authorMats Klepsland <mats.klepsland@gmail.com>
Wed, 22 Aug 2018 12:21:24 +0000 (14:21 +0200)
committerMats Klepsland <mats.klepsland@gmail.com>
Sun, 16 Sep 2018 19:13:10 +0000 (21:13 +0200)
Add support for draft 22 to draft 28 and for the final
version (RFC8446) of TLSv1.3.

src/app-layer-ssl.c
src/app-layer-ssl.h

index 042c3ca327756bf30a8dda23679f7100f7ebb50d..6915952ed61f493ff99e24b28c2dfdf2c9942e73 100644 (file)
@@ -559,15 +559,17 @@ static inline int TLSDecodeHSHelloVersion(SSLState *ssl_state,
         return -1;
     }
 
+    ssl_state->curr_connp->version = *input << 8 | *(input + 1);
+
     if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) &&
             ssl_config.enable_ja3 && ssl_state->ja3_str == NULL) {
-        uint16_t version = *input << 8 | *(input + 1);
 
         ssl_state->ja3_str = Ja3BufferInit();
         if (ssl_state->ja3_str == NULL)
             return -1;
 
-        int rc = Ja3BufferAddValue(&ssl_state->ja3_str, version);
+        int rc = Ja3BufferAddValue(&ssl_state->ja3_str,
+                                   ssl_state->curr_connp->version);
         if (rc != 0)
             return -1;
     }
@@ -821,6 +823,56 @@ invalid_length:
     return -1;
 }
 
+static inline int TLSDecodeHSHelloExtensionSupportedVersions(SSLState *ssl_state,
+                                             const uint8_t * const initial_input,
+                                             const uint32_t input_len)
+{
+    uint8_t *input = (uint8_t *)initial_input;
+
+    if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) {
+        if (!(HAS_SPACE(1)))
+            goto invalid_length;
+
+        uint8_t supported_ver_len = *input;
+        input += 1;
+
+        if (!(HAS_SPACE(supported_ver_len)))
+            goto invalid_length;
+
+        /* Use the first (and prefered) version as client version */
+        ssl_state->curr_connp->version = *input << 8 | *(input + 1);
+
+        /* Set a flag to indicate that we have seen this extension */
+        ssl_state->flags |= SSL_AL_FLAG_CH_VERSION_EXTENSION;
+
+        input += supported_ver_len;
+    }
+
+    else if (ssl_state->current_flags & SSL_AL_FLAG_STATE_SERVER_HELLO) {
+        if (!(HAS_SPACE(2)))
+            goto invalid_length;
+
+        uint16_t ver = *input << 8 | *(input + 1);
+
+        if ((ssl_state->flags & SSL_AL_FLAG_CH_VERSION_EXTENSION) &&
+            ((ver == TLS_VERSION_13) || (((ver >> 8) & 0xff) == 0x7f))) {
+            ssl_state->flags |= SSL_AL_FLAG_LOG_WITHOUT_CERT;
+        }
+
+        ssl_state->curr_connp->version = ver;
+        input += 2;
+    }
+
+    return (input - initial_input);
+
+invalid_length:
+    SCLogDebug("TLS handshake invalid length");
+    SSLSetEvent(ssl_state,
+                TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH);
+
+    return -1;
+}
+
 static inline int TLSDecodeHSHelloExtensionEllipticCurves(SSLState *ssl_state,
                                           const uint8_t * const initial_input,
                                           const uint32_t input_len,
@@ -1018,6 +1070,18 @@ static inline int TLSDecodeHSHelloExtensions(SSLState *ssl_state,
                 break;
             }
 
+            case SSL_EXTENSION_SUPPORTED_VERSIONS:
+            {
+                ret = TLSDecodeHSHelloExtensionSupportedVersions(ssl_state, input,
+                                                                 input_len - parsed);
+                if (ret < 0)
+                    goto end;
+
+                input += ret;
+
+                break;
+            }
+
             case SSL_EXTENSION_SESSION_TICKET:
             {
                 if ((ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) &&
@@ -1536,12 +1600,30 @@ static int SSLv3ParseRecord(uint8_t direction, SSLState *ssl_state,
         return 0;
     }
 
+    uint8_t skip_version = 0;
+
+    /* Only set SSL/TLS version here if it has not already been set in
+       client/server hello. */
+    if (direction == 0) {
+        if ((ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) &&
+                (ssl_state->client_connp.version != TLS_VERSION_UNKNOWN)) {
+            skip_version = 1;
+        }
+    } else {
+        if ((ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) &&
+                (ssl_state->server_connp.version != TLS_VERSION_UNKNOWN)) {
+            skip_version = 1;
+        }
+    }
+
     switch (ssl_state->curr_connp->bytes_processed) {
         case 0:
             if (input_len >= 5) {
                 ssl_state->curr_connp->content_type = input[0];
-                ssl_state->curr_connp->version = input[1] << 8;
-                ssl_state->curr_connp->version |= input[2];
+                if (!skip_version) {
+                    ssl_state->curr_connp->version = input[1] << 8;
+                    ssl_state->curr_connp->version |= input[2];
+                }
                 ssl_state->curr_connp->record_length = input[3] << 8;
                 ssl_state->curr_connp->record_length |= input[4];
                 ssl_state->curr_connp->bytes_processed += SSLV3_RECORD_HDR_LEN;
@@ -1554,13 +1636,23 @@ static int SSLv3ParseRecord(uint8_t direction, SSLState *ssl_state,
 
             /* fall through */
         case 1:
-            ssl_state->curr_connp->version = *(input++) << 8;
+            if (!skip_version) {
+                ssl_state->curr_connp->version = *(input++) << 8;
+                printf("%d\n", ssl_state->curr_connp->version);
+            } else {
+                input++;
+            }
             if (--input_len == 0)
                 break;
 
             /* fall through */
         case 2:
-            ssl_state->curr_connp->version |= *(input++);
+            if (!skip_version) {
+                ssl_state->curr_connp->version |= *(input++);
+                printf("%d\n", ssl_state->curr_connp->version);
+            } else {
+                input++;
+            }
             if (--input_len == 0)
                 break;
 
@@ -1965,14 +2057,6 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state,
         return parsed;
     }
 
-    /* check record version */
-    if (ssl_state->curr_connp->version < SSL_VERSION_3 ||
-            ssl_state->curr_connp->version > TLS_VERSION_12) {
-
-        SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_VERSION);
-        return -1;
-    }
-
     /* record_length should never be zero */
     if (ssl_state->curr_connp->record_length == 0) {
         SCLogDebug("SSLv3 Record length is 0");
@@ -2200,9 +2284,6 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt
                     }
                 } else {
                     SCLogDebug("SSLv3.x detected");
-                    /* we will keep it this way till our record parser tells
-                       us what exact version this is */
-                    ssl_state->curr_connp->version = TLS_VERSION_UNKNOWN;
                     retval = SSLv3Decode(direction, ssl_state, pstate, input,
                                          input_len);
                     if (retval < 0) {
@@ -4459,8 +4540,6 @@ static int SSLParserTest23(void)
      * record */
     FAIL_IF(app_state->client_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL);
 
-    FAIL_IF(app_state->client_connp.version != SSL_VERSION_3);
-
     FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0);
     FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0);
     FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0);
@@ -4499,8 +4578,6 @@ static int SSLParserTest23(void)
 
     FAIL_IF(app_state->client_connp.content_type != SSLV3_APPLICATION_PROTOCOL);
 
-    FAIL_IF(app_state->client_connp.version != SSL_VERSION_3);
-
     FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0);
     FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0);
     FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0);
index 05087491abfa1d5d3037124f65924bfe09326ecf..069c86467944980ea53d815e94e64a962bdd7c83 100644 (file)
@@ -103,6 +103,13 @@ enum {
 /* Session resumed without a full handshake */
 #define SSL_AL_FLAG_SESSION_RESUMED             BIT_U32(20)
 
+/* Encountered a supported_versions extension in client hello */
+#define SSL_AL_FLAG_CH_VERSION_EXTENSION        BIT_U32(21)
+
+/* Log the session even without ever seeing a certificate. This is used
+   to log TLSv1.3 sessions. */
+#define SSL_AL_FLAG_LOG_WITHOUT_CERT            BIT_U32(22)
+
 /* config flags */
 #define SSL_TLS_LOG_PEM                         (1 << 0)
 
@@ -111,6 +118,7 @@ enum {
 #define SSL_EXTENSION_ELLIPTIC_CURVES           0x000a
 #define SSL_EXTENSION_EC_POINT_FORMATS          0x000b
 #define SSL_EXTENSION_SESSION_TICKET            0x0023
+#define SSL_EXTENSION_SUPPORTED_VERSIONS        0x002b
 
 /* SNI types */
 #define SSL_SNI_TYPE_HOST_NAME                  0
@@ -124,6 +132,21 @@ enum {
     TLS_VERSION_10 = 0x0301,
     TLS_VERSION_11 = 0x0302,
     TLS_VERSION_12 = 0x0303,
+    TLS_VERSION_13 = 0x0304,
+    TLS_VERSION_13_DRAFT28 = 0x7f1c,
+    TLS_VERSION_13_DRAFT27 = 0x7f1b,
+    TLS_VERSION_13_DRAFT26 = 0x7f1a,
+    TLS_VERSION_13_DRAFT25 = 0x7f19,
+    TLS_VERSION_13_DRAFT24 = 0x7f18,
+    TLS_VERSION_13_DRAFT23 = 0x7f17,
+    TLS_VERSION_13_DRAFT22 = 0x7f16,
+    TLS_VERSION_13_DRAFT21 = 0x7f15,
+    TLS_VERSION_13_DRAFT20 = 0x7f14,
+    TLS_VERSION_13_DRAFT19 = 0x7f13,
+    TLS_VERSION_13_DRAFT18 = 0x7f12,
+    TLS_VERSION_13_DRAFT17 = 0x7f11,
+    TLS_VERSION_13_DRAFT16 = 0x7f10,
+    TLS_VERSION_13_PRE_DRAFT16 = 0x7f01,
 };
 
 typedef struct SSLCertsChain_ {