]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #5014: ssl: alert on multi client hello and server certificates data
authorDaniil Kolomiiets -X (dkolomii - SOFTSERVE INC at Cisco) <dkolomii@cisco.com>
Mon, 16 Feb 2026 17:17:25 +0000 (17:17 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Mon, 16 Feb 2026 17:17:25 +0000 (17:17 +0000)
Merge in SNORT/snort3 from ~DKOLOMII/snort3:ssl_client_certificate_parse_fix to master

Squashed commit of the following:

commit 768d92978901b7e8e101600601b14952c91e0172
Author: Daniil Kolomiiets <dkolomii@cisco.com>
Date:   Thu Feb 12 13:29:13 2026 -0500

    ssl: alert on multiple chello certificate records

src/network_inspectors/appid/service_plugins/service_ssl.cc
src/protocols/ssl.cc
src/protocols/ssl.h
src/protocols/test/ssl_protocol_test.cc
src/service_inspectors/ssl/ssl_flow_data.h
src/service_inspectors/ssl/ssl_inspector.cc
src/service_inspectors/ssl/ssl_module.cc

index f0c6a1c4e7bdcb504f34aec6f7836b6041f4b8f3..1758e247dfd45a8aaece84d700f545946c751ae0 100644 (file)
@@ -195,20 +195,20 @@ ServiceSSLData::~ServiceSSLData()
     ssl_cache_free(cached_data, cached_len);
 }
 
-static ParseHelloResult parse_client_initiation(const uint8_t* data, uint16_t size, ServiceSSLData* ss)
+static ParseResult parse_client_initiation(const uint8_t* data, uint16_t size, ServiceSSLData* ss)
 {
     const ServiceSSLV3Hdr* hdr3;
     uint16_t ver;
 
     /* Sanity check header stuff. */
     if (size < sizeof(ServiceSSLV3Hdr))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     hdr3 = (const ServiceSSLV3Hdr*)data;
     ver = ntohs(hdr3->version);
     if (hdr3->type != SSL_HANDSHAKE || (ver != 0x0300 && ver != 0x0301 && ver != 0x0302 &&
         ver != 0x0303))
     {
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     }
     data += sizeof(ServiceSSLV3Hdr);
     size -= sizeof(ServiceSSLV3Hdr);
@@ -311,14 +311,14 @@ int SslServiceDetector::validate(AppIdDiscoveryArgs& args)
             args.dir == APP_ID_FROM_INITIATOR)
         {
             auto parse_status = parse_client_initiation(data, size, ss);
-            if (parse_status == ParseHelloResult::FRAGMENTED_PACKET)
+            if (parse_status == ParseResult::FRAGMENTED_PACKET)
             {
                 save_ssl_cache(ss, size, data);
                 ss->cached_client_data = true;
                 ss->state = SSL_STATE_INITIATE;
                 goto inprocess;
             }
-            else if (parse_status == ParseHelloResult::FAILURE)
+            else if (parse_status == ParseResult::FAILURE)
             {
                 goto inprocess;
             }
@@ -572,7 +572,7 @@ success:
     if (ss->server_cert.certs_data && ss->server_cert.certs_len)
     {
         if (!(args.asd.scan_flags & SCAN_CERTVIZ_ENABLED_FLAG) and
-            (!parse_server_certificates(&ss->server_cert)))
+            (parse_server_certificates(&ss->server_cert)) == snort::ParseResult::FAILURE)
         {
             goto fail;
         }
index ef049cf75082ea5abb55cf988663a238b7d378af..16641052892c5a566a598582ad2c541f3547ed1c 100644 (file)
@@ -123,7 +123,7 @@ static uint32_t SSL_decode_version_v3(uint8_t major, uint8_t minor)
 }
 
 static uint32_t SSL_decode_handshake_v3(const uint8_t* pkt, int size,
-    uint32_t cur_flags, uint32_t pkt_flags, SSLV3ClientHelloData* client_hello_data,
+    uint32_t cur_flags, uint32_t pkt_flags, uint8_t* alert_flags, SSLV3ClientHelloData* client_hello_data,
     SSLV3ServerCertData* server_cert_data, TLSConnectionParams* tls_connection_params)
 {
     const SSL_handshake_hello_t* hello;
@@ -170,7 +170,9 @@ static uint32_t SSL_decode_handshake_v3(const uint8_t* pkt, int size,
             hello = (const SSL_handshake_hello_t*)handshake;
             retval |= SSL_decode_version_v3(hello->major, hello->minor);
 
-            snort::parse_client_hello_data((const uint8_t*)handshake, size + SSL_HS_PAYLOAD_OFFSET, client_hello_data);
+            if (snort::parse_client_hello_data((const uint8_t*)handshake, size + SSL_HS_PAYLOAD_OFFSET, 
+                    client_hello_data) == snort::ParseResult::MULTIPLE_RECORDS && alert_flags)
+                *alert_flags |= SSL_ALERT_CHELLO_MULTIPLE_RECORDS;
 
             break;
 
@@ -197,7 +199,6 @@ static uint32_t SSL_decode_handshake_v3(const uint8_t* pkt, int size,
                 retval |= SSL_BAD_VER_FLAG;
 
             snort::parse_server_hello_data((const uint8_t*)handshake, size + SSL_HS_PAYLOAD_OFFSET, tls_connection_params);
-
             break;
 
         case SSL_HS_SHELLO_DONE:
@@ -241,7 +242,8 @@ static uint32_t SSL_decode_handshake_v3(const uint8_t* pkt, int size,
                 server_cert_data->certs_data = (uint8_t*)snort_alloc(server_cert_data->certs_len);
                 memcpy(server_cert_data->certs_data, pkt + SSL_CERTS_LEN_SIZE, server_cert_data->certs_len);
 
-                snort::parse_server_certificates(server_cert_data);
+                if(snort::parse_server_certificates(server_cert_data) == snort::ParseResult::MULTIPLE_RECORDS && alert_flags)
+                    *alert_flags |= SSL_ALERT_CERT_MULTIPLE_RECORDS;
             }
 
             retval |= SSL_CERTIFICATE_FLAG;
@@ -349,17 +351,17 @@ static uint32_t SSL_decode_v3(const uint8_t* pkt, int size, uint32_t pkt_flags,
             {
                 hblen = ntohs(heartbeat->length);
                 if (hblen > max_hb_len)
-                    *alert_flags = SSL_HEARTBLEED_REQUEST;
+                    *alert_flags = SSL_ALERT_HEARTBLEED_REQUEST;
             }
             else if ((heartbeat->type) == SSL_HEARTBEAT_RESPONSE)
             {
                 if (reclen > max_hb_len )
-                    *alert_flags = SSL_HEARTBLEED_RESPONSE;
+                    *alert_flags = SSL_ALERT_HEARTBLEED_RESPONSE;
             }
             else if (!(retval & SSL_BAD_VER_FLAG))
             {
                 if (reclen > max_hb_len )
-                    *alert_flags = SSL_HEARTBLEED_UNKNOWN;
+                    *alert_flags = SSL_ALERT_HEARTBLEED_UNKNOWN;
             }
             break;
 
@@ -369,7 +371,7 @@ static uint32_t SSL_decode_v3(const uint8_t* pkt, int size, uint32_t pkt_flags,
             if (!(retval & SSL_CHANGE_CIPHER_FLAG) && !(prev_flags & SSL_CHANGE_CIPHER_FLAG))
             {
                 int hsize = size < (int)reclen ? size : (int)reclen;
-                retval |= SSL_decode_handshake_v3(pkt, hsize, retval, pkt_flags, client_hello_data, server_cert_data, tls_connection_params);
+                retval |= SSL_decode_handshake_v3(pkt, hsize, retval, pkt_flags, alert_flags, client_hello_data, server_cert_data, tls_connection_params);
             }
             else if (ccs)
             {
@@ -655,61 +657,61 @@ bool IsSSL(const uint8_t* ptr, int len, int pkt_flags)
     return false;
 }
 
-ParseHelloResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV3ClientHelloData* client_hello_data)
+ParseResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV3ClientHelloData* client_hello_data)
 {
     if (client_hello_data == nullptr)
-        return ParseHelloResult::FAILURE;
-
+        return ParseResult::FAILURE;
+    
     if (size < sizeof(ServiceSSLV3Record))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     const ServiceSSLV3Record* rec = (const ServiceSSLV3Record*)pkt;
     uint16_t ver = ntohs(rec->version);
     if (rec->type != SSLV3RecordType::CLIENT_HELLO || (ver != 0x0300 && ver != 0x0301 && ver != 0x0302 &&
         ver != 0x0303) || rec->length_msb)
     {
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     }
     unsigned length = ntohs(rec->length) + offsetof(ServiceSSLV3Record, version);
     if (size < length)
-        return ParseHelloResult::FRAGMENTED_PACKET;
+        return ParseResult::FRAGMENTED_PACKET;
     pkt += sizeof(ServiceSSLV3Record);
     size -= sizeof(ServiceSSLV3Record);
 
     /* Session ID (1-byte length). */
     if (size < 1)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     length = *((const uint8_t*)pkt);
     pkt += length + 1;
     if (size < (length + 1))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     size -= length + 1;
 
     /* Cipher Suites (2-byte length). */
     if (size < 2)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     length = ntohs(*((const uint16_t*)pkt));
     pkt += length + 2;
     if (size < (length + 2))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     size -= length + 2;
 
     /* Compression Methods (1-byte length). */
     if (size < 1)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     length = *((const uint8_t*)pkt);
     pkt += length + 1;
     if (size < (length + 1))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     size -= length + 1;
 
     /* Extensions (2-byte length) */
     if (size < 2)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     length = ntohs(*((const uint16_t*)pkt));
     pkt += 2;
     size -= 2;
     if (size < length)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
 
     /* We need at least type (2 bytes) and length (2 bytes) in the extension. */
     while (length >= 4)
@@ -719,82 +721,86 @@ ParseHelloResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV
         {
             /* Found server host name. */
             if (length < sizeof(ServiceSSLV3ExtensionServerName))
-                return ParseHelloResult::FAILURE;
+                return ParseResult::FAILURE;
 
             unsigned len = ntohs(ext->string_length);
             if ((length - sizeof(ServiceSSLV3ExtensionServerName)) < len)
-                return ParseHelloResult::FAILURE;
+                return ParseResult::FAILURE;
 
             const uint8_t* str = pkt + offsetof(ServiceSSLV3ExtensionServerName, string_length) +
                 sizeof(ext->string_length);
+            
+            if(client_hello_data->host_name)
+                return ParseResult::MULTIPLE_RECORDS;
+
             client_hello_data->host_name = snort_strndup((const char*)str, len);
-            return ParseHelloResult::SUCCESS;
+            return ParseResult::SUCCESS;
         }
 
         unsigned len = ntohs(ext->length) + offsetof(ServiceSSLV3ExtensionServerName, list_length);
         if (len > length)
-            return ParseHelloResult::FAILURE;
+            return ParseResult::FAILURE;
 
         pkt += len;
         length -= len;
     }
 
-    return ParseHelloResult::FAILURE;
+    return ParseResult::FAILURE;
 }
 
-ParseHelloResult parse_server_hello_data(const uint8_t* pkt, uint16_t size, TLSConnectionParams* tls_connection_params)
+ParseResult parse_server_hello_data(const uint8_t* pkt, uint16_t size, TLSConnectionParams* tls_connection_params)
 {
     if (tls_connection_params == nullptr)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
 
     if (size < sizeof(ServiceSSLV3Record))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     const ServiceSSLV3Record* rec = (const ServiceSSLV3Record*)pkt;
     uint16_t ver = ntohs(rec->version);
     if (rec->type != SSLV3RecordType::SERVER_HELLO || (ver != 0x0300 && ver != 0x0301 && ver != 0x0302 &&
         ver != 0x0303) || rec->length_msb)
     {
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     }
     unsigned length = ntohs(rec->length) + offsetof(ServiceSSLV3Record, version);
     if (size < length)
-        return ParseHelloResult::FRAGMENTED_PACKET;
+        return ParseResult::FRAGMENTED_PACKET;
     pkt += sizeof(ServiceSSLV3Record);
     size -= sizeof(ServiceSSLV3Record);
 
     /* Session ID (1-byte length). */
     if (size < 1)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     length = *((const uint8_t*)pkt);
     pkt += length + 1;
     if (size < (length + 1))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     size -= length + 1;
 
     /* Cipher Suite (2-byte length). */
     if (size < 2)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     tls_connection_params->cipher = ntohs(*((const uint16_t*)pkt));
     pkt += 2;
     size -= 2;
 
     /* Compression Methods (1-byte length). */
     if (size < 1)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     length = *((const uint8_t*)pkt);
     pkt += length + 1;
     if (size < (length + 1))
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     size -= length + 1;
 
     /* Extensions (2-byte length) */
     if (size < 2)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
     length = ntohs(*((const uint16_t*)pkt));
     pkt += 2;
     size -= 2;
     if (size < length)
-        return ParseHelloResult::FAILURE;
+        return ParseResult::FAILURE;
 
     /* We need at least type (2 bytes) and length (2 bytes) in the extension. */
     while (length >= 4)
@@ -804,33 +810,33 @@ ParseHelloResult parse_server_hello_data(const uint8_t* pkt, uint16_t size, TLSC
         {
             /* Found supported version extension. */
             if (length < sizeof(ServiceSSLV3ExtensionSupportedVersion))
-                return ParseHelloResult::FAILURE;
+                return ParseResult::FAILURE;
 
             unsigned len = ntohs(ext->length);
             if (len != sizeof(ext->supported_version))
-                return ParseHelloResult::FAILURE;
+                return ParseResult::FAILURE;
 
             tls_connection_params->selected_tls_version = ntohs(ext->supported_version);
-            return ParseHelloResult::SUCCESS;
+            return ParseResult::SUCCESS;
         }
 
         unsigned len = ntohs(ext->length) + offsetof(ServiceSSLV3ExtensionSupportedVersion, supported_version);
         if (len > length)
-            return ParseHelloResult::FAILURE;
+            return ParseResult::FAILURE;
 
         pkt += len;
         length -= len;
     }
 
-    return ParseHelloResult::FAILURE;
+    return ParseResult::FAILURE;
 }
 
-bool parse_server_certificates(SSLV3ServerCertData* server_cert_data)
+ParseResult parse_server_certificates(SSLV3ServerCertData* server_cert_data)
 {
     if (!server_cert_data->certs_data)
     {
         server_cert_data->certs_len = 0;
-        return false;
+        return ParseResult::FAILURE;
     }
     else if (!server_cert_data->certs_len)
     {
@@ -839,7 +845,7 @@ bool parse_server_certificates(SSLV3ServerCertData* server_cert_data)
 #ifdef REG_TEST
         LogMessage("Free server certificate data due to length being 0!\n");
 #endif
-        return false;
+        return ParseResult::FAILURE;
     }
 
     const uint8_t* data = server_cert_data->certs_data;
@@ -943,16 +949,35 @@ bool parse_server_certificates(SSLV3ServerCertData* server_cert_data)
         X509_free(cert);
     }
 
+    ParseResult result = ParseResult::SUCCESS;
+
     if (common_name)
     {
-        server_cert_data->common_name = common_name;
-        server_cert_data->common_name_strlen = common_name_len;
+        if(server_cert_data->common_name)
+        {
+           result = ParseResult::MULTIPLE_RECORDS;
+           snort_free(common_name);
+        }
+        else
+        {
+            server_cert_data->common_name = common_name;
+            server_cert_data->common_name_strlen = common_name_len;
+        }
     }
 
     if (org_unit)
     {
-        server_cert_data->org_unit = org_unit;
-        server_cert_data->org_unit_strlen = org_unit_len;
+        if(server_cert_data->org_unit)
+        {
+            result = ParseResult::MULTIPLE_RECORDS;
+            snort_free(org_unit);
+        }
+        else
+        {
+            server_cert_data->org_unit = org_unit;
+            server_cert_data->org_unit_strlen = org_unit_len;
+        }
+       
     }
 
     /* No longer need entire certificates. We have what we came for. */
@@ -960,7 +985,7 @@ bool parse_server_certificates(SSLV3ServerCertData* server_cert_data)
     server_cert_data->certs_data = nullptr;
     server_cert_data->certs_len = 0;
 
-    return true;
+    return result;
 }
 
 bool parse_server_key_exchange(const uint8_t* pkt, uint16_t size, TLSConnectionParams* tls_connection_params)
index f0c590611b5e045afd64828a4b8b30e69e0a6059..010a3663317d07ca3967effc959abff482136472 100644 (file)
@@ -352,28 +352,33 @@ struct ServiceSSLV3ExtensionSupportedVersion
     SSL_BAD_VER_FLAG | SSL_BAD_TYPE_FLAG | \
     SSL_TRAILING_GARB_FLAG | SSL_UNKNOWN_FLAG))
 
-#define SSL_HEARTBLEED_REQUEST  0x01
-#define SSL_HEARTBLEED_RESPONSE 0x02
-#define SSL_HEARTBLEED_UNKNOWN  0x04
+// SSL alert flags
+#define SSL_ALERT_HEARTBLEED_REQUEST          0x01
+#define SSL_ALERT_HEARTBLEED_RESPONSE         0x02
+#define SSL_ALERT_HEARTBLEED_UNKNOWN          0x04
+#define SSL_ALERT_CHELLO_MULTIPLE_RECORDS     0x08
+#define SSL_ALERT_CERT_MULTIPLE_RECORDS       0x10
 
 namespace snort
 {
 
-enum ParseHelloResult : uint8_t
+enum ParseResult : uint8_t
 {
     SUCCESS = 0,
     FRAGMENTED_PACKET = 1,
-    FAILURE = 2
+    MULTIPLE_RECORDS = 2,
+    FAILURE = 3
 };
 
+
 SO_PUBLIC uint32_t SSL_decode(
     const uint8_t* pkt, int size, uint32_t pktflags, uint32_t prevflags,
     uint8_t* alert_flags, uint16_t* partial_rec_len, int hblen, uint32_t* info_flags = nullptr,
     SSLV3ClientHelloData* data = nullptr, SSLV3ServerCertData* server_cert_data = nullptr, TLSConnectionParams* tls_connection_params = nullptr);
 
-    ParseHelloResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV3ClientHelloData*);
-    ParseHelloResult parse_server_hello_data(const uint8_t* pkt, uint16_t size, TLSConnectionParams*);
-    bool parse_server_certificates(SSLV3ServerCertData* server_cert_data);
+    ParseResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV3ClientHelloData*);
+    ParseResult parse_server_hello_data(const uint8_t* pkt, uint16_t size, TLSConnectionParams*);
+    ParseResult parse_server_certificates(SSLV3ServerCertData* server_cert_data);
     bool parse_server_key_exchange(const uint8_t* pkt, uint16_t size, TLSConnectionParams*);
 
 SO_PUBLIC bool IsTlsClientHello(const uint8_t* ptr, const uint8_t* end);
@@ -381,4 +386,3 @@ SO_PUBLIC bool IsTlsServerHello(const uint8_t* ptr, const uint8_t* end);
 SO_PUBLIC bool IsSSL(const uint8_t* ptr, int len, int pkt_flags);
 }
 #endif
-
index 64f8600662382e6edd9a55490b7bfb4a412db76f..51a37a63307a82cf7349e5f53f897a3c1b624690 100644 (file)
@@ -106,7 +106,7 @@ TEST(ssl_protocol_tests, cert_data_incomplete_len_2)
     test_data.certs_data = new uint8_t[2] { 0x01, 0x02 }; // Incomplete length, should be at least 3 bytes
     test_data.certs_len = 2;
     auto result = parse_server_certificates(&test_data);
-    CHECK_EQUAL(true, result);
+    CHECK_EQUAL(static_cast<uint8_t>(snort::ParseResult::SUCCESS), static_cast<uint8_t>(result));
     POINTERS_EQUAL(nullptr, test_data.certs_data);
     CHECK_EQUAL(0, test_data.certs_len);
 }
@@ -172,7 +172,7 @@ TEST(ssl_protocol_tests, parse_server_hello_tls_1_3)
 
     TLSConnectionParams tls_params;
     auto result = parse_server_hello_data(test_data, sizeof(test_data), &tls_params);
-    CHECK_EQUAL(ParseHelloResult::SUCCESS, result);
+    CHECK_EQUAL(static_cast<uint8_t>(ParseResult::SUCCESS), static_cast<uint8_t>(result));
     CHECK_EQUAL(0x0304, tls_params.selected_tls_version);
     CHECK_EQUAL(0xc02b, tls_params.cipher);
 }
@@ -198,7 +198,7 @@ TEST(ssl_protocol_tests, parse_server_hello_invalid_packet_len)
 
     TLSConnectionParams tls_params;
     auto result = parse_server_hello_data(test_data, sizeof(test_data), &tls_params);
-    CHECK_EQUAL(ParseHelloResult::FRAGMENTED_PACKET, result);
+    CHECK_EQUAL(static_cast<uint8_t>(ParseResult::FRAGMENTED_PACKET), static_cast<uint8_t>(result));
 }
 
 
index 39ff75a3351c74437dc292e65bc2a823f33eebfe..053a4b21582c8c4953bf8865edd3e4d3ca69d234 100644 (file)
 
 #define GID_SSL 137
 
-#define     SSL_INVALID_CLIENT_HELLO               1
-#define     SSL_INVALID_SERVER_HELLO               2
-#define     SSL_ALERT_HB_REQUEST                   3
-#define     SSL_ALERT_HB_RESPONSE                  4
+#define     SSL_INVALID_CLIENT_HELLO          1
+#define     SSL_INVALID_SERVER_HELLO          2
+#define     SSL_ALERT_HB_REQUEST              3
+#define     SSL_ALERT_HB_RESPONSE             4
+#define     SSL_ALERT_CHELLO_MULTI_RECORDS    5
+#define     SSL_ALERT_CERT_MULTI_RECORDS      6
 
 struct SSLData
 {
index c3a02d01075e38f5a6cac7b7cee20852228008ee..be3ee7265388a95af22ec8fa79a56d2fbb6707cc 100644 (file)
@@ -375,12 +375,12 @@ static void snort_ssl(SSL_PROTO_CONF* config, Packet* p)
     uint8_t dir = (p->is_from_server()) ? 1 : 0;
     uint8_t index = (p->packet_flags & PKT_REBUILT_STREAM) ? 2 : 0;
 
-    uint8_t heartbleed_type = 0;
+    uint8_t alert_flags = 0;
     uint32_t info_flags = 0;
     SSLV3ClientHelloData client_hello_data;
     SSLV3ServerCertData server_cert;
     uint32_t new_flags = SSL_decode(p->data, (int)p->dsize, p->packet_flags, sd.ssn_flags,
-        &heartbleed_type, &(sd.partial_rec_len[dir+index]), config->max_heartbeat_len, &info_flags, &client_hello_data,
+        &alert_flags, &(sd.partial_rec_len[dir+index]), config->max_heartbeat_len, &info_flags, &client_hello_data,
         &server_cert, &fd->get_tls_connection_data().tls_params);
     sd.info_flags |= info_flags;
 
@@ -409,21 +409,31 @@ static void snort_ssl(SSL_PROTO_CONF* config, Packet* p)
         DataBus::publish(pub_id, SslEventIds::CHELLO_SERVER_NAME, event);
     }
 
+    if(alert_flags & SSL_ALERT_CHELLO_MULTIPLE_RECORDS)
+    {
+        DetectionEngine::queue_event(GID_SSL, SSL_ALERT_CHELLO_MULTI_RECORDS);
+    }
+
     if (server_cert.common_name != nullptr)
     {
         SslServerCommonNameEvent event(server_cert.common_name, p);
         DataBus::publish(pub_id, SslEventIds::SERVER_COMMON_NAME, event);
     }
 
-    if (heartbleed_type & SSL_HEARTBLEED_REQUEST)
+    if(alert_flags & SSL_ALERT_CERT_MULTIPLE_RECORDS)
+    {
+        DetectionEngine::queue_event(GID_SSL, SSL_ALERT_CERT_MULTI_RECORDS);
+    }
+
+    if (alert_flags & SSL_ALERT_HEARTBLEED_REQUEST)
     {
         DetectionEngine::queue_event(GID_SSL, SSL_ALERT_HB_REQUEST);
     }
-    else if (heartbleed_type & SSL_HEARTBLEED_RESPONSE)
+    else if (alert_flags & SSL_ALERT_HEARTBLEED_RESPONSE)
     {
         DetectionEngine::queue_event(GID_SSL, SSL_ALERT_HB_RESPONSE);
     }
-    else if (heartbleed_type & SSL_HEARTBLEED_UNKNOWN)
+    else if (alert_flags & SSL_ALERT_HEARTBLEED_UNKNOWN)
     {
         if (!dir)
         {
index b42c5d60fd1fd324f3f1dc5a1327256fbbc24efd..d4a5ec428b19c1252f832c54d3406843e9720eeb 100644 (file)
@@ -33,6 +33,8 @@ using namespace std;
 #define SSL_INVALID_SERVER_HELLO_STR "invalid server HELLO without client HELLO detected"
 #define SSL_HEARTBLEED_REQUEST_STR "heartbeat read overrun attempt detected"
 #define SSL_HEARTBLEED_RESPONSE_STR "large heartbeat response detected"
+#define SSL_CHELLO_MULTI_RECORDS_STR "multiple client HELLO host names detected in single packet"
+#define SSL_CERT_MULTI_RECORDS_STR "multiple server CERTIFICATE common names or organizational units detected in single packet"
 
 static const Parameter s_params[] =
 {
@@ -51,6 +53,8 @@ static const RuleMap ssl_rules[] =
     { SSL_INVALID_SERVER_HELLO, SSL_INVALID_SERVER_HELLO_STR },
     { SSL_ALERT_HB_REQUEST, SSL_HEARTBLEED_REQUEST_STR },
     { SSL_ALERT_HB_RESPONSE, SSL_HEARTBLEED_RESPONSE_STR },
+    { SSL_ALERT_CHELLO_MULTI_RECORDS, SSL_CHELLO_MULTI_RECORDS_STR },
+    { SSL_ALERT_CERT_MULTI_RECORDS, SSL_CERT_MULTI_RECORDS_STR },
 
     { 0, nullptr }
 };