]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
app-layer-ssl: get server name from SNI extension
authorMats Klepsland <mats.klepsland@gmail.com>
Tue, 13 Oct 2015 12:06:37 +0000 (14:06 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 23 Nov 2015 09:37:17 +0000 (10:37 +0100)
Decode client hello handshake to get server name from SNI extension.

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

index 5fb41ba15a21b3d45dc3befe7e59a42e2b955cbf..2c20a0544808e27a7dad45c5dd45799c26e66592 100644 (file)
@@ -119,10 +119,15 @@ SslConfig ssl_config;
 #define SSLV3_RECORD_HDR_LEN 5
 #define SSLV3_MESSAGE_HDR_LEN 4
 
+#define SSLV3_CLIENT_HELLO_VERSION_LEN 2
+#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32
+
 /* TLS heartbeat protocol types */
 #define TLS_HB_REQUEST              1
 #define TLS_HB_RESPONSE             2
 
+#define HAS_SPACE(n) (((input) + (n) - (initial_input)) > (input_len)) ?  0 : 1
+
 static void SSLParserReset(SSLState *ssl_state)
 {
     ssl_state->curr_connp->bytes_processed = 0;
@@ -143,11 +148,101 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input,
     switch (ssl_state->curr_connp->handshake_type) {
         case SSLV3_HS_CLIENT_HELLO:
             ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO;
+
+            /* skip version */
+            input += SSLV3_CLIENT_HELLO_VERSION_LEN;
+
+            /* skip random */
+            input += SSLV3_CLIENT_HELLO_RANDOM_LEN;
+
+            if (!(HAS_SPACE(1)))
+                goto end;
+
+            /* skip session id */
+            uint8_t session_id_length = *(input++);
+
+            input += session_id_length;
+
+            if (!(HAS_SPACE(2)))
+                goto end;
+
+            /* skip cipher suites */
+            uint16_t cipher_suites_length = ntohs(*(uint16_t *)input);
+            input += 2;
+
+            input += cipher_suites_length;
+
+            if (!(HAS_SPACE(1)))
+                goto end;
+
+            /* skip compression methods */
+            uint8_t compression_methods_length = *(input++);
+
+            input += compression_methods_length;
+
+            if (!(HAS_SPACE(2)))
+                goto end;
+
+            uint16_t extensions_len = ntohs(*(uint16_t *)input);
+            input += 2;
+
+            uint16_t processed_len = 0;
+            while (processed_len < extensions_len)
+            {
+                if (!(HAS_SPACE(2)))
+                    goto end;
+
+                uint16_t ext_type = ntohs(*(uint16_t *)input);
+                input += 2;
+
+                if (!(HAS_SPACE(2)))
+                    goto end;
+
+                uint16_t ext_len = ntohs(*(uint16_t *)input);
+                input += 2;
+
+
+                switch (ext_type) {
+                    case SSL_EXTENSION_SNI:
+                    {
+                        /* skip sni_list_length and sni_type */
+                        input += 3;
+
+                        if (!(HAS_SPACE(2)))
+                            goto end;
+
+                        uint16_t sni_len = ntohs(*(uint16_t *)input);
+                        input += 2;
+
+                        size_t sni_strlen = sni_len + 1;
+                        ssl_state->curr_connp->sni = SCMalloc(sni_strlen);
+
+                        if (unlikely(ssl_state->curr_connp->sni == NULL))
+                            goto end;
+
+                        if (!(HAS_SPACE(sni_len)))
+                            goto end;
+
+                        memcpy(ssl_state->curr_connp->sni, input,
+                               sni_strlen - 1);
+                        ssl_state->curr_connp->sni[sni_strlen-1] = 0;
+
+                        input += sni_len;
+                        break;
+                    }
+                    default:
+                    {
+                        input += ext_len;
+                        break;
+                    }
+                }
+                processed_len += ext_len + 4;
+            }
+end:
             break;
 
         case SSLV3_HS_SERVER_HELLO:
             ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO;
-
             break;
 
         case SSLV3_HS_SERVER_KEY_EXCHANGE:
@@ -1141,6 +1236,8 @@ void SSLStateFree(void *p)
         SCFree(ssl_state->client_connp.cert0_issuerdn);
     if (ssl_state->client_connp.cert0_fingerprint)
         SCFree(ssl_state->client_connp.cert0_fingerprint);
+    if (ssl_state->client_connp.sni)
+        SCFree(ssl_state->client_connp.sni);
 
     if (ssl_state->server_connp.trec)
         SCFree(ssl_state->server_connp.trec);
@@ -1150,6 +1247,8 @@ void SSLStateFree(void *p)
         SCFree(ssl_state->server_connp.cert0_issuerdn);
     if (ssl_state->server_connp.cert0_fingerprint)
         SCFree(ssl_state->server_connp.cert0_fingerprint);
+    if (ssl_state->server_connp.sni)
+        SCFree(ssl_state->server_connp.sni);
 
     /* Free certificate chain */
     while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) {
index 2fc1a9699bde52331a7262fafba647ba99e873e6..e6274249b9e436ef823b91fa0ce4e94937db080e 100644 (file)
@@ -86,7 +86,8 @@ enum {
 /* config flags */
 #define SSL_TLS_LOG_PEM                         (1 << 0)
 
-
+/* extensions */
+#define SSL_EXTENSION_SNI                       0x0000
 
 /* SSL versions.  We'll use a unified format for all, with the top byte
  * holding the major version and the lower byte the minor version */
@@ -134,6 +135,9 @@ typedef struct SSLStateConnp_ {
     char *cert0_issuerdn;
     char *cert0_fingerprint;
 
+    /* ssl server name indication extension */
+    char *sni;
+
     uint8_t *cert_input;
     uint32_t cert_input_len;