aboutsummaryrefslogtreecommitdiffstats
path: root/src/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocols')
-rw-r--r--src/protocols/dpi_ssl.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/protocols/dpi_ssl.c b/src/protocols/dpi_ssl.c
new file mode 100644
index 0000000..f15a19c
--- /dev/null
+++ b/src/protocols/dpi_ssl.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2019 Intel and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <inttypes.h>
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+
+#include "../dpi.h"
+
+typedef enum
+{
+ State_Initial = 0,
+ State_Client_Hello = 1,
+ State_Server_Hello = 2,
+ State_Certificate = 3,
+} ssl_state;
+
+enum
+{
+ MAJOR_TLS = 0x3,
+};
+
+enum
+{
+ MINOR_SSL30 = 0,
+ MINOR_TLS10 = 0x1,
+ MINOR_TLS11 = 0x2,
+ MINOR_TLS12 = 0x3,
+};
+
+typedef enum
+{
+ change_cipher_spec = 20,
+ alert = 21,
+ handshake = 22,
+ application_data = 23,
+} ContentType;
+
+typedef struct
+{
+ u8 major;
+ u8 minor;
+} ProtocolVersion;
+
+typedef struct
+{
+ u8 type;
+ ProtocolVersion version;
+ u16 length;
+} __attribute__ ((packed)) ssl_header;
+
+typedef enum
+{
+ hello_request = 0,
+ client_hello = 1,
+ server_hello = 2,
+ certificate = 11,
+ server_key_exchange = 12,
+ certificate_request = 13,
+ server_hello_done = 14,
+ certificate_verify = 15,
+ client_key_exchange = 16,
+ finished = 20,
+} HandshakeType;
+
+typedef struct
+{
+ u8 msg_type; /* handshake type */
+ u8 length[3]; /* bytes in message */
+} Handshake_header;
+
+int dpi_ssl_detect_protocol_from_cert (u8 * payload, u32 payload_len,
+ dpi_flow_info_t * flow);
+
+#define dpi_isprint(ch) ((ch) >= 0x20 && (ch) <= 0x7e)
+#define dpi_isalpha(ch) (((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
+#define dpi_isdigit(ch) ((ch) >= '0' && (ch) <= '9')
+#define dpi_isspace(ch) (((ch) >= '\t' && (ch) <= '\r') || ((ch) == ' '))
+#define dpi_min(a,b) ((a < b) ? a : b)
+
+static void
+dpi_set_detected_protocol (dpi_flow_info_t * flow,
+ u32 upper_protocol, u32 lower_protocol)
+{
+
+ if ((upper_protocol == DPI_PROTOCOL_UNKNOWN)
+ && (lower_protocol != DPI_PROTOCOL_UNKNOWN))
+ upper_protocol = lower_protocol;
+
+ if (upper_protocol == lower_protocol)
+ lower_protocol = DPI_PROTOCOL_UNKNOWN;
+
+ if ((upper_protocol != DPI_PROTOCOL_UNKNOWN)
+ && (lower_protocol == DPI_PROTOCOL_UNKNOWN))
+ {
+ if ((flow->guessed_host_protocol_id != DPI_PROTOCOL_UNKNOWN)
+ && (upper_protocol != flow->guessed_host_protocol_id))
+ {
+ lower_protocol = upper_protocol;
+ upper_protocol = flow->guessed_host_protocol_id;
+ }
+ }
+
+ flow->detected_protocol[0] = upper_protocol;
+ flow->detected_protocol[1] = lower_protocol;
+}
+
+static u32
+dpi_ssl_refine_master_protocol (dpi_flow_info_t * flow, u32 protocol)
+{
+
+ if (flow->l4.tcp.ssl_got_server_cert == 1)
+ protocol = DPI_PROTOCOL_SSL;
+ else
+ protocol = DPI_PROTOCOL_SSL_NO_CERT;
+
+ return protocol;
+}
+
+int
+dpi_ssl_detect_protocol_from_cert (u8 * payload, u32 payload_len,
+ dpi_flow_info_t * flow)
+{
+ u32 host_protocol = DPI_PROTOCOL_UNKNOWN;
+ int rv = 0;
+
+ /* Only check SSL handshake packets.
+ * Check first segment and subsequent segments. */
+ if (((payload_len > (sizeof (ssl_header) + sizeof (Handshake_header)))
+ && (payload[0] == handshake)) || (flow->detect_begin))
+ {
+ if ((flow->detected_protocol[0] == DPI_PROTOCOL_UNKNOWN)
+ || (flow->detected_protocol[0] == DPI_PROTOCOL_SSL))
+ {
+ rv = dpi_search_host_protocol (flow, (char *) payload, payload_len,
+ DPI_PROTOCOL_SSL, &host_protocol);
+
+ if (host_protocol != DPI_PROTOCOL_UNKNOWN)
+ {
+ dpi_set_detected_protocol (flow, host_protocol,
+ dpi_ssl_refine_master_protocol (flow,
+ DPI_PROTOCOL_SSL));
+ return rv;
+ }
+ }
+ }
+ return 0;
+}
+
+
+void
+dpi_search_tcp_ssl (u8 * payload, u32 payload_len, dpi_flow_info_t * flow)
+{
+ u32 cur_len = payload_len;
+ u32 cur_len2;
+ u8 handshake_type;
+
+ /* Check first segment of SSL Certificate message */
+ if ((payload_len > (sizeof (ssl_header) + sizeof (Handshake_header)))
+ && (payload[0] == handshake))
+ {
+ handshake_type = payload[5];
+
+ if (handshake_type == client_hello)
+ {
+ flow->l4.tcp.ssl_stage = State_Client_Hello;
+ return;
+ }
+ else if (handshake_type == server_hello)
+ {
+ cur_len = ntohs (get_u16_t (payload, 3)) + sizeof (ssl_header);
+
+ /* This packet only contains Server Hello message */
+ if (cur_len == payload_len)
+ {
+ flow->l4.tcp.ssl_stage = State_Server_Hello;
+ return;
+ }
+
+ /* This packet contains Server Hello, Certificate and more messages */
+ if (payload_len >= cur_len + sizeof (ssl_header)
+ && payload[cur_len] == handshake
+ && payload[cur_len + 1] == MAJOR_TLS)
+ {
+ cur_len2 = ntohs (get_u16_t (payload, cur_len + 3))
+ + sizeof (ssl_header);
+ if (payload[cur_len + 5] == certificate)
+ {
+ flow->l4.tcp.ssl_stage = State_Certificate;
+ flow->detect_begin = 1;
+ /* Scan segments of certificate message */
+ if (dpi_ssl_detect_protocol_from_cert (&payload[cur_len],
+ cur_len2, flow) > 0)
+ return;
+ }
+ }
+ }
+ else if (handshake_type == certificate)
+ {
+ cur_len = ntohs (get_u16_t (payload, 3)) + sizeof (ssl_header);
+
+ /* This packet contains first segment of certificate message */
+ if (cur_len == payload_len)
+ {
+ flow->l4.tcp.ssl_stage = State_Certificate;
+ flow->detect_begin = 1;
+ /* Scan segments of certificate message */
+ if (dpi_ssl_detect_protocol_from_cert (payload, cur_len, flow) >
+ 0)
+ return;
+ }
+ }
+ else if (flow->detect_begin)
+ {
+ /* Check subsequent segments of SSL Certificate message */
+ if (dpi_ssl_detect_protocol_from_cert (payload, cur_len, flow) > 0)
+ return;
+ }
+ }
+
+ return;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */