** `request`
** `response`
** `eot` (a session defined by the following commands: APPE, DELE, RETR, STOR, STOU, ACCT, PORT, PASV, EPRT, EPSV)
+* SSL
+ ** `tls_metadata_event`
* DNS
** `response`
* connection (conn)
* `data_channel.resp_h` - IP address of data channel receiving point
* `data_channel.resp_p` - TCP port of data channel receiving point
+Fields supported for SSL:
+
+* `version` - SSL/TLS version that the server chose
+* `server_name_identifier` - Server Name Identifier ( SNI ) extracted from Client Hello
+* `validation_status` - result of certificate validation
+* `subject` - RFC2253 formatted certificate subject information
+* `issuer` - RFC2253 formatted certificate issuer information
+* `module_identifier` - name of snort module that populated the event
+* `cipher` - SSL/TLS cipher suite that the server chose
+* `curve` - named elliptic curve the server chose
+
Fields supported for DNS:
* `proto` - transport protocol for DNS connection
ssl_cache_free(cached_data, cached_len);
}
-static ParseCHResult parse_client_initiation(const uint8_t* data, uint16_t size, ServiceSSLData* ss)
+static ParseHelloResult 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 ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
hdr3 = (const ServiceSSLV3Hdr*)data;
ver = ntohs(hdr3->version);
if (hdr3->type != SSL_HANDSHAKE || (ver != 0x0300 && ver != 0x0301 && ver != 0x0302 &&
ver != 0x0303))
{
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
}
data += sizeof(ServiceSSLV3Hdr);
size -= sizeof(ServiceSSLV3Hdr);
args.dir == APP_ID_FROM_INITIATOR)
{
auto parse_status = parse_client_initiation(data, size, ss);
- if (parse_status == ParseCHResult::FRAGMENTED_PACKET)
+ if (parse_status == ParseHelloResult::FRAGMENTED_PACKET)
{
save_ssl_cache(ss, size, data);
ss->cached_client_data = true;
ss->state = SSL_STATE_INITIATE;
goto inprocess;
}
- else if (parse_status == ParseCHResult::FAILED)
+ else if (parse_status == ParseHelloResult::FAILURE)
{
goto inprocess;
}
extractor_null_conn.h
extractor_service.cc
extractor_service.h
+ extractor_ssl.cc
+ extractor_ssl.h
extractors.cc
extractors.h
)
static const Parameter extractor_proto_params[] =
{
- { "service", Parameter::PT_ENUM, "http | ftp | conn | dns | weird | notice", nullptr,
+ { "service", Parameter::PT_ENUM, "http | ftp | ssl | conn | dns | weird | notice", nullptr,
"service to extract from" },
{ "tenant_id", Parameter::PT_INT, "0:max32", "0",
{
HTTP,
FTP,
+ SSL,
CONN,
DNS,
IPS_BUILTIN,
return "http";
case FTP:
return "ftp";
+ case SSL:
+ return "ssl";
case CONN:
return "conn";
case DNS:
#include "extractor_dns.h"
#include "extractor_ftp.h"
#include "extractor_http.h"
+#include "extractor_ssl.h"
using namespace snort;
srv = new FtpExtractorService(cfg.tenant_id, cfg.fields, cfg.on_events, cfg.service, ins);
break;
+ case ServiceType::SSL:
+ srv = new SslExtractorService(cfg.tenant_id, cfg.fields, cfg.on_events, cfg.service, ins);
+ break;
+
case ServiceType::CONN:
srv = new ConnExtractorService(cfg.tenant_id, cfg.fields, cfg.on_events, cfg.service, ins);
break;
validate_fields(FtpExtractorService::blueprint, cfg.fields);
break;
+ case ServiceType::SSL:
+ validate_events(SslExtractorService::blueprint, cfg.on_events);
+ validate_fields(SslExtractorService::blueprint, cfg.fields);
+ break;
+
case ServiceType::CONN:
validate_events(ConnExtractorService::blueprint, cfg.on_events);
validate_fields(ConnExtractorService::blueprint, cfg.fields);
const snort::Connector::ID& FtpExtractorService::get_log_id()
{ return log_id; }
+//-------------------------------------------------------------------------
+// SslExtractorService
+//-------------------------------------------------------------------------
+
+const ServiceBlueprint SslExtractorService::blueprint =
+{
+ // events
+ {
+ "tls_metadata_event",
+ },
+ // fields
+ {
+ "version",
+ "server_name_identifier",
+ "curve",
+ "cipher",
+ "subject",
+ "issuer",
+ "validation_status",
+ "module_identifier"
+ },
+};
+
+THREAD_LOCAL Connector::ID SslExtractorService::log_id;
+
+SslExtractorService::SslExtractorService(uint32_t tenant, const std::vector<std::string>& srv_fields,
+ const std::vector<std::string>& srv_events, ServiceType s_type, Extractor& ins)
+ : ExtractorService(tenant, srv_fields, srv_events, blueprint, s_type, ins)
+{
+ for (const auto& event : get_events())
+ {
+ if (!strcmp("tls_metadata_event", event.c_str()))
+ handlers.push_back(new SslExtractor(ins, tenant_id, get_fields()));
+ }
+}
+
+const snort::Connector::ID& SslExtractorService::internal_tinit()
+{ return log_id = logger->get_id(type.c_str()); }
+
+const snort::Connector::ID& SslExtractorService::get_log_id()
+{ return log_id; }
+
//-------------------------------------------------------------------------
// ConnExtractorService
//-------------------------------------------------------------------------
{
ServiceType http = ServiceType::HTTP;
ServiceType ftp = ServiceType::FTP;
+ ServiceType ssl = ServiceType::SSL;
ServiceType conn = ServiceType::CONN;
ServiceType dns = ServiceType::DNS;
ServiceType weird = ServiceType::IPS_BUILTIN;
CHECK_FALSE(strcmp("http", http.c_str()));
CHECK_FALSE(strcmp("ftp", ftp.c_str()));
+ CHECK_FALSE(strcmp("ssl", ssl.c_str()));
CHECK_FALSE(strcmp("conn", conn.c_str()));
CHECK_FALSE(strcmp("dns", dns.c_str()));
CHECK_FALSE(strcmp("weird", weird.c_str()));
static THREAD_LOCAL snort::Connector::ID log_id;
};
+class SslExtractorService : public ExtractorService
+{
+public:
+ static const ServiceBlueprint blueprint;
+
+ SslExtractorService(uint32_t tenant, const std::vector<std::string>& fields,
+ const std::vector<std::string>& events, ServiceType, Extractor&);
+
+private:
+ const snort::Connector::ID& internal_tinit() override;
+ const snort::Connector::ID& get_log_id() override;
+
+ static THREAD_LOCAL snort::Connector::ID log_id;
+};
+
class ConnExtractorService : public ExtractorService
{
public:
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2025-2025 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// extractor_ssl.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "extractor_ssl.h"
+
+#include <sys/time.h>
+
+#include "detection/detection_engine.h"
+#include "flow/flow_key.h"
+#include "profiler/profiler.h"
+#include "pub_sub/ssl_events.h"
+#include "protocols/ssl.h"
+#include "sfip/sf_ip.h"
+#include "utils/util.h"
+#include "utils/util_net.h"
+
+#include "extractor.h"
+#include "extractor_enums.h"
+
+using namespace snort;
+using namespace std;
+
+static const char* sslv_2_string = "SSL 2";
+static const char* sslv_3_string = "SSL 3";
+static const char* tls_1_0_string = "TLS 1.0";
+static const char* tls_1_1_string = "TLS 1.1";
+static const char* tls_1_2_string = "TLS 1.2";
+static const char* tls_1_3_string = "TLS 1.3";
+
+static const char* get_ssl_string_version(uint32_t version)
+{
+ switch (version)
+ {
+ case 0x0002:
+ return sslv_2_string;
+ case 0x0300:
+ return sslv_3_string;
+ case 0x0301:
+ return tls_1_0_string;
+ case 0x0302:
+ return tls_1_1_string;
+ case 0x0303:
+ return tls_1_2_string;
+ case 0x0304:
+ return tls_1_3_string;
+ default:
+ {
+ static THREAD_LOCAL char unknown_version[32];
+ memset(unknown_version, 0, sizeof(unknown_version));
+ snprintf(unknown_version, sizeof(unknown_version), "Unknown version (0x%04x)", version);
+ return unknown_version;
+ }
+ }
+}
+
+const std::unordered_map<uint16_t, const char*> get_ssl_string_curve_map =
+{
+ {0x0001, "sect163k1"},
+ {0x0002, "sect163r1"},
+ {0x0003, "sect163r2"},
+ {0x0004, "sect193r1"},
+ {0x0005, "sect193r2"},
+ {0x0006, "sect233k1"},
+ {0x0007, "sect233r1"},
+ {0x0008, "sect239k1"},
+ {0x0009, "sect283k1"},
+ {0x000A, "sect283r1"},
+ {0x000B, "sect409k1"},
+ {0x000C, "sect409r1"},
+ {0x000D, "sect571k1"},
+ {0x000E, "sect571r1"},
+ {0x000F, "secp160k1"},
+ {0x0010, "secp160r1"},
+ {0x0011, "secp160r2"},
+ {0x0012, "secp192k1"},
+ {0x0013, "secp192r1"},
+ {0x0014, "secp224k1"},
+ {0x0015, "secp224r1"},
+ {0x0016, "secp256k1"},
+ {0x0017, "secp256r1"},
+ {0x0018, "secp384r1"},
+ {0x0019, "secp521r1"},
+ {0x001A, "brainpoolP256r1"},
+ {0x001B, "brainpoolP384r1"},
+ {0x001C, "brainpoolP512r1"},
+ {0x001D, "x25519"},
+ {0x001E, "x448"},
+ {0x001F, "brainpoolP256r1tls13"},
+ {0x0020, "brainpoolP384r1tls13"},
+ {0x0021, "brainpoolP512r1tls13"},
+ {0x0022, "GC256A"},
+ {0x0023, "GC256B"},
+ {0x0024, "GC256C"},
+ {0x0025, "GC256D"},
+ {0x0026, "GC512A"},
+ {0x0027, "GC512B"},
+ {0x0028, "GC512C"},
+ {0x0029, "curveSM2"},
+ {0x0100, "ffdhe2048"},
+ {0x0101, "ffdhe3072"},
+ {0x0102, "ffdhe4096"},
+ {0x0103, "ffdhe6144"},
+ {0x0104, "ffdhe8192"},
+ {0x0200, "MLKEM512"},
+ {0x0201, "MLKEM768"},
+ {0x0202, "MLKEM1024"},
+ {0x11EB, "SecP256r1MLKEM768"},
+ {0x11EC, "X25519MLKEM768"},
+ {0x11ED, "SecP384r1MLKEM1024"},
+ {0x6399, "X25519Kyber768Draft00"},
+ {0x639A, "SecP256r1Kyber768Draft00"}
+};
+
+const std::unordered_map<uint16_t, const char*> tls_cipher_map =
+{
+ {0x0001, "TLS_RSA_WITH_NULL_MD5"},
+ {0x0002, "TLS_RSA_WITH_NULL_SHA"},
+ {0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
+ {0x0004, "TLS_RSA_WITH_RC4_128_MD5"},
+ {0x0005, "TLS_RSA_WITH_RC4_128_SHA"},
+ {0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
+ {0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA"},
+ {0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {0x0009, "TLS_RSA_WITH_DES_CBC_SHA"},
+ {0x000A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {0x000B, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+ {0x000C, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
+ {0x000D, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
+ {0x000E, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {0x000F, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
+ {0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+ {0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
+ {0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
+ {0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
+ {0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
+ {0x0018, "TLS_DH_anon_WITH_RC4_128_MD5"},
+ {0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
+ {0x001A, "TLS_DH_anon_WITH_DES_CBC_SHA"},
+ {0x001B, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
+ {0x001E, "TLS_KRB5_WITH_DES_CBC_SHA"},
+ {0x001F, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"},
+ {0x0020, "TLS_KRB5_WITH_RC4_128_SHA"},
+ {0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA"},
+ {0x0022, "TLS_KRB5_WITH_DES_CBC_MD5"},
+ {0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"},
+ {0x0024, "TLS_KRB5_WITH_RC4_128_MD5"},
+ {0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5"},
+ {0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"},
+ {0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"},
+ {0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"},
+ {0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"},
+ {0x002A, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"},
+ {0x002B, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"},
+ {0x002C, "TLS_PSK_WITH_NULL_SHA"},
+ {0x002D, "TLS_DHE_PSK_WITH_NULL_SHA"},
+ {0x002E, "TLS_RSA_PSK_WITH_NULL_SHA"},
+ {0x002F, "TLS_RSA_WITH_AES_128_CBC_SHA"},
+ {0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
+ {0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
+ {0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
+ {0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
+ {0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
+ {0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA"},
+ {0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
+ {0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
+ {0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
+ {0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
+ {0x003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
+ {0x003B, "TLS_RSA_WITH_NULL_SHA256"},
+ {0x003C, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
+ {0x003D, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
+ {0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
+ {0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
+ {0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
+ {0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA"},
+ {0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA"},
+ {0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA"},
+ {0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA"},
+ {0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA"},
+ {0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"},
+ {0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
+ {0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
+ {0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
+ {0x006A, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
+ {0x006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
+ {0x006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
+ {0x006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
+ {0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA"},
+ {0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA"},
+ {0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA"},
+ {0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA"},
+ {0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA"},
+ {0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"},
+ {0x008A, "TLS_PSK_WITH_RC4_128_SHA"},
+ {0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"},
+ {0x008C, "TLS_PSK_WITH_AES_128_CBC_SHA"},
+ {0x008D, "TLS_PSK_WITH_AES_256_CBC_SHA"},
+ {0x008E, "TLS_DHE_PSK_WITH_RC4_128_SHA"},
+ {0x008F, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"},
+ {0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"},
+ {0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"},
+ {0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"},
+ {0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"},
+ {0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"},
+ {0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"},
+ {0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"},
+ {0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"},
+ {0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"},
+ {0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"},
+ {0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"},
+ {0x009B, "TLS_DH_anon_WITH_SEED_CBC_SHA"},
+ {0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256"},
+ {0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384"},
+ {0x009E, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"},
+ {0x009F, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"},
+ {0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"},
+ {0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"},
+ {0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"},
+ {0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"},
+ {0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"},
+ {0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"},
+ {0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"},
+ {0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"},
+ {0x00A8, "TLS_PSK_WITH_AES_128_GCM_SHA256"},
+ {0x00A9, "TLS_PSK_WITH_AES_256_GCM_SHA384"},
+ {0x00AA, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"},
+ {0x00AB, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"},
+ {0x00AC, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"},
+ {0x00AD, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"},
+ {0x00AE, "TLS_PSK_WITH_AES_128_CBC_SHA256"},
+ {0x00AF, "TLS_PSK_WITH_AES_256_CBC_SHA384"},
+ {0x00B0, "TLS_PSK_WITH_NULL_SHA256"},
+ {0x00B1, "TLS_PSK_WITH_NULL_SHA384"},
+ {0x00B2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"},
+ {0x00B3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"},
+ {0x00B4, "TLS_DHE_PSK_WITH_NULL_SHA256"},
+ {0x00B5, "TLS_DHE_PSK_WITH_NULL_SHA384"},
+ {0x00B6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"},
+ {0x00B7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"},
+ {0x00B8, "TLS_RSA_PSK_WITH_NULL_SHA256"},
+ {0x00B9, "TLS_RSA_PSK_WITH_NULL_SHA384"},
+ {0x00BA, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0x00BB, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0x00BC, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0x00BD, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0x00BE, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0x00BF, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0x00C0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"},
+ {0x00C1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"},
+ {0x00C2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"},
+ {0x00C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"},
+ {0x00C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"},
+ {0x00C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"},
+ {0x00C6, "TLS_SM4_GCM_SM3"},
+ {0x00C7, "TLS_SM4_CCM_SM3"},
+ {0x00FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"},
+ {0x1301, "TLS_AES_128_GCM_SHA256"},
+ {0x1302, "TLS_AES_256_GCM_SHA384"},
+ {0x1303, "TLS_CHACHA20_POLY1305_SHA256"},
+ {0x1304, "TLS_AES_128_CCM_SHA256"},
+ {0x1305, "TLS_AES_128_CCM_8_SHA256"},
+ {0x1306, "TLS_AEGIS_256_SHA512"},
+ {0x1307, "TLS_AEGIS_128L_SHA256"},
+ {0x5600, "TLS_FALLBACK_SCSV"},
+ {0xC001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"},
+ {0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"},
+ {0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"},
+ {0xC004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"},
+ {0xC005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"},
+ {0xC006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"},
+ {0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"},
+ {0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"},
+ {0xC009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"},
+ {0xC00A, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"},
+ {0xC00B, "TLS_ECDH_RSA_WITH_NULL_SHA"},
+ {0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA"},
+ {0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {0xC00E, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"},
+ {0xC00F, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"},
+ {0xC010, "TLS_ECDHE_RSA_WITH_NULL_SHA"},
+ {0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"},
+ {0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {0xC013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"},
+ {0xC014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},
+ {0xC015, "TLS_ECDH_anon_WITH_NULL_SHA"},
+ {0xC016, "TLS_ECDH_anon_WITH_RC4_128_SHA"},
+ {0xC017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"},
+ {0xC018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"},
+ {0xC019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"},
+ {0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"},
+ {0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {0xC01C, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"},
+ {0xC01D, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"},
+ {0xC01E, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"},
+ {0xC01F, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"},
+ {0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"},
+ {0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"},
+ {0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"},
+ {0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"},
+ {0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"},
+ {0xC025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"},
+ {0xC026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"},
+ {0xC027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"},
+ {0xC028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"},
+ {0xC029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"},
+ {0xC02A, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"},
+ {0xC02B, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"},
+ {0xC02C, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"},
+ {0xC02D, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"},
+ {0xC02E, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"},
+ {0xC02F, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"},
+ {0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"},
+ {0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"},
+ {0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"},
+ {0xC033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA"},
+ {0xC034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA"},
+ {0xC035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"},
+ {0xC036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA"},
+ {0xC037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256"},
+ {0xC038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384"},
+ {0xC039, "TLS_ECDHE_PSK_WITH_NULL_SHA"},
+ {0xC03A, "TLS_ECDHE_PSK_WITH_NULL_SHA256"},
+ {0xC03B, "TLS_ECDHE_PSK_WITH_NULL_SHA384"},
+ {0xC03C, "TLS_RSA_WITH_ARIA_128_CBC_SHA256"},
+ {0xC03D, "TLS_RSA_WITH_ARIA_256_CBC_SHA384"},
+ {0xC03E, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256"},
+ {0xC03F, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384"},
+ {0xC040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256"},
+ {0xC041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384"},
+ {0xC042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256"},
+ {0xC043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384"},
+ {0xC044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256"},
+ {0xC045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384"},
+ {0xC046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256"},
+ {0xC047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384"},
+ {0xC048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256"},
+ {0xC049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384"},
+ {0xC04A, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256"},
+ {0xC04B, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384"},
+ {0xC04C, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256"},
+ {0xC04D, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384"},
+ {0xC04E, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256"},
+ {0xC04F, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384"},
+ {0xC050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256"},
+ {0xC051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384"},
+ {0xC052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256"},
+ {0xC053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384"},
+ {0xC054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256"},
+ {0xC055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384"},
+ {0xC056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256"},
+ {0xC057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384"},
+ {0xC058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256"},
+ {0xC059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384"},
+ {0xC05A, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256"},
+ {0xC05B, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384"},
+ {0xC05C, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256"},
+ {0xC05D, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"},
+ {0xC05E, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256"},
+ {0xC05F, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384"},
+ {0xC060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256"},
+ {0xC061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384"},
+ {0xC062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256"},
+ {0xC063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384"},
+ {0xC064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256"},
+ {0xC065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384"},
+ {0xC066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256"},
+ {0xC067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384"},
+ {0xC068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256"},
+ {0xC069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384"},
+ {0xC06A, "TLS_PSK_WITH_ARIA_128_GCM_SHA256"},
+ {0xC06B, "TLS_PSK_WITH_ARIA_256_GCM_SHA384"},
+ {0xC06C, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256"},
+ {0xC06D, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384"},
+ {0xC06E, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256"},
+ {0xC06F, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384"},
+ {0xC070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256"},
+ {0xC071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384"},
+ {0xC072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC07A, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC07B, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC07C, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC07D, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC07E, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC07F, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC08A, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC08B, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC08C, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC08D, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC08E, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC08F, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256"},
+ {0xC093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384"},
+ {0xC094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC09A, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256"},
+ {0xC09B, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384"},
+ {0xC09C, "TLS_RSA_WITH_AES_128_CCM"},
+ {0xC09D, "TLS_RSA_WITH_AES_256_CCM"},
+ {0xC09E, "TLS_DHE_RSA_WITH_AES_128_CCM"},
+ {0xC09F, "TLS_DHE_RSA_WITH_AES_256_CCM"},
+ {0xC0A0, "TLS_RSA_WITH_AES_128_CCM_8"},
+ {0xC0A1, "TLS_RSA_WITH_AES_256_CCM_8"},
+ {0xC0A2, "TLS_DHE_RSA_WITH_AES_128_CCM_8"},
+ {0xC0A3, "TLS_DHE_RSA_WITH_AES_256_CCM_8"},
+ {0xC0A4, "TLS_PSK_WITH_AES_128_CCM"},
+ {0xC0A5, "TLS_PSK_WITH_AES_256_CCM"},
+ {0xC0A6, "TLS_DHE_PSK_WITH_AES_128_CCM"},
+ {0xC0A7, "TLS_DHE_PSK_WITH_AES_256_CCM"},
+ {0xC0A8, "TLS_PSK_WITH_AES_128_CCM_8"},
+ {0xC0A9, "TLS_PSK_WITH_AES_256_CCM_8"},
+ {0xC0AA, "TLS_PSK_DHE_WITH_AES_128_CCM_8"},
+ {0xC0AB, "TLS_PSK_DHE_WITH_AES_256_CCM_8"},
+ {0xC0AC, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"},
+ {0xC0AD, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM"},
+ {0xC0AE, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"},
+ {0xC0AF, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8"},
+ {0xC0B0, "TLS_ECCPWD_WITH_AES_128_GCM_SHA256"},
+ {0xC0B1, "TLS_ECCPWD_WITH_AES_256_GCM_SHA384"},
+ {0xC0B2, "TLS_ECCPWD_WITH_AES_128_CCM_SHA256"},
+ {0xC0B3, "TLS_ECCPWD_WITH_AES_256_CCM_SHA384"},
+ {0xC0B4, "TLS_SHA256_SHA256"},
+ {0xC0B5, "TLS_SHA384_SHA384"},
+ {0xC100, "TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC"},
+ {0xC101, "TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC"},
+ {0xC102, "TLS_GOSTR341112_256_WITH_28147_CNT_IMIT"},
+ {0xC103, "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L"},
+ {0xC104, "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L"},
+ {0xC105, "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S"},
+ {0xC106, "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S"},
+ {0xCCA8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"},
+ {0xCCA9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"},
+ {0xCCAA, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"},
+ {0xCCAB, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+ {0xCCAC, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+ {0xCCAD, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+ {0xCCAE, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256"},
+ {0xD001, "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256"},
+ {0xD002, "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384"},
+ {0xD003, "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256"},
+ {0xD005, "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256"},
+ {0xfee0, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"},
+ {0xfee1, "SSL_RSA_FIPS_WITH_DES_CBC_SHA"},
+ {0xfefe, "SSL_RSA_FIPS_WITH_DES_CBC_SHA"},
+ {0xfeff, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"}
+};
+
+const std::unordered_map<uint16_t, const char*> ssl_cipher_map =
+{
+ {0x0700, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"},
+ {0x0701, "SSL_CK_DES_192_EDE3_CBC_WITH_SHA"},
+ {0x0600, "SSL_CK_DES_64_CBC_WITH_MD5"},
+ {0x0601, "SSL_CK_DES_64_CBC_WITH_SHA"},
+ {0xff08, "SSL_CK_DES_64_CFB64_WITH_MD5_1"},
+ {0x0400, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
+ {0x0200, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
+ {0x0500, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
+ {0x0300, "SSL_CK_RC2_128_CBC_WITH_MD5"},
+ {0x0800, "SSL_CK_RC4_64_WITH_MD5"},
+ {0x0100, "SSL_CK_RC4_128_WITH_MD5"}
+};
+
+static const char* get_cipher(const DataEvent* event, const Flow*)
+{
+ auto tls_event = (const SslTlsMetadataBaseEvent*)event;
+ auto map = tls_event->get_version() < 0x0300 ? ssl_cipher_map : tls_cipher_map;
+ auto it = map.find(tls_event->get_cipher());
+ if (it != map.end())
+ {
+ return it->second;
+ }
+ else
+ {
+ static THREAD_LOCAL char unknown_cipher[32];
+ memset(unknown_cipher, 0, sizeof(unknown_cipher));
+ snprintf(unknown_cipher, sizeof(unknown_cipher), "Unknown cipher (0x%02x)", tls_event->get_cipher());
+ return unknown_cipher;
+ }
+}
+
+static const char* get_curve(const DataEvent* event, const Flow*)
+{
+ auto it = get_ssl_string_curve_map.find(((const SslTlsMetadataBaseEvent*)event)->get_curve());
+ if (it != get_ssl_string_curve_map.end())
+ {
+ return it->second;
+ }
+ else
+ {
+ static THREAD_LOCAL char unknown_curve[32];
+ memset(unknown_curve, 0, sizeof(unknown_curve));
+ snprintf(unknown_curve, sizeof(unknown_curve), "Unknown curve (0x%02x)", ((const SslTlsMetadataBaseEvent*)event)->get_curve());
+ return unknown_curve;
+ }
+}
+
+static const char* get_version(const DataEvent* event, const Flow*)
+{
+ return get_ssl_string_version(((const SslTlsMetadataBaseEvent*)event)->get_version());
+}
+
+static const char* get_validation_status(const DataEvent* event, const Flow*)
+{
+ return ((const SslTlsMetadataBaseEvent*)event)->get_validation_status().c_str();
+}
+
+static const char* get_subject(const DataEvent* event, const Flow*)
+{
+ return ((const SslTlsMetadataBaseEvent*)event)->get_subject().c_str();
+}
+
+static const char* get_issuer(const DataEvent* event, const Flow*)
+{
+ return ((const SslTlsMetadataBaseEvent*)event)->get_issuer().c_str();
+}
+
+static const char* get_module_identifier(const DataEvent* event, const Flow*)
+{
+ return ((const SslTlsMetadataBaseEvent*)event)->get_module_identifier().c_str();
+}
+
+static const char* get_server_name_identifier(const DataEvent* event, const Flow*)
+{
+ return ((const SslTlsMetadataBaseEvent*)event)->get_server_name_identifier().c_str();
+}
+
+static const map<string, ExtractorEvent::BufGetFn> buf_getters =
+{
+ {"version", get_version},
+ {"server_name_identifier", get_server_name_identifier},
+ {"validation_status", get_validation_status},
+ {"subject", get_subject},
+ {"issuer", get_issuer},
+ {"curve", get_curve},
+ {"cipher", get_cipher},
+ {"module_identifier", get_module_identifier}
+};
+
+THREAD_LOCAL const snort::Connector::ID* SslExtractor::log_id = nullptr;
+
+SslExtractor::SslExtractor(Extractor& i, uint32_t t, const vector<string>& fields) :
+ ExtractorEvent(ServiceType::SSL, i, t)
+{
+ for (const auto& f : fields)
+ {
+ if (append(nts_fields, nts_getters, f))
+ continue;
+ if (append(sip_fields, sip_getters, f))
+ continue;
+ if (append(num_fields, num_getters, f))
+ continue;
+ if (append(buf_fields, buf_getters, f))
+ continue;
+ }
+
+ DataBus::subscribe_global(ssl_pub_key, SslEventIds::SSL_TLS_METADATA_EVENT,
+ new Server(*this, S_NAME), i.get_snort_config());
+}
+
+void SslExtractor::internal_tinit(const snort::Connector::ID* service_id)
+{ log_id = service_id; }
+
+void SslExtractor::handle(DataEvent& event, Flow* flow)
+{
+ // cppcheck-suppress unreadVariable
+ Profile profile(extractor_perf_stats);
+
+ if (!filter(flow))
+ return;
+
+ extractor_stats.total_events++;
+
+ logger->open_record();
+ log(nts_fields, &event, flow);
+ log(sip_fields, &event, flow);
+ log(num_fields, &event, flow);
+ log(buf_fields, &event, flow);
+ logger->close_record(*log_id);
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2025-2025 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// extractor_ssl.h author Oleksandr Stepanov <ostepano@cisco.com>
+
+#ifndef EXTRACTOR_SSL_H
+#define EXTRACTOR_SSL_H
+
+#include <cassert>
+
+#include "extractors.h"
+
+class SslExtractorFlowData;
+
+class SslExtractor : public ExtractorEvent
+{
+public:
+ SslExtractor(Extractor&, uint32_t tenant, const std::vector<std::string>& fields);
+
+ void handle(DataEvent&, Flow*);
+
+private:
+ using Server = Handler<SslExtractor>;
+
+ void internal_tinit(const snort::Connector::ID*) override;
+
+ static THREAD_LOCAL const snort::Connector::ID* log_id;
+};
+
+#endif
#include "ssl.h"
+#include <openssl/ssl.h>
#include <openssl/x509.h>
#include "packet.h"
#define SSL2_CHELLO_BYTE 0x01
#define SSL2_SHELLO_BYTE 0x04
+SSL_CTX* global_ssl_ctxt = nullptr;
+SSL* global_ssl = nullptr;
+
SSLV3ClientHelloData::~SSLV3ClientHelloData()
{
snort_free(host_name);
snort_free(certs_data);
snort_free(common_name);
snort_free(org_unit);
+ snort_free(issuer_info);
+ snort_free(subject_info);
}
void SSLV3ServerCertData::clear()
org_unit = nullptr;
}
+void TLSConnectionData::process(const SSLV3ServerCertData &cert_data)
+{
+ subject_info = cert_data.subject_info ? std::string(cert_data.subject_info) : "";
+ issuer_info = cert_data.issuer_info ? std::string(cert_data.issuer_info) : "";
+}
+
+void TLSConnectionData::process(const SSLV3ClientHelloData &client_hello_data)
+{
+ server_name_identifier = client_hello_data.host_name ? std::string(client_hello_data.host_name) : "";
+}
+
static uint32_t SSL_decode_version_v3(uint8_t major, uint8_t minor)
{
/* Should only be called internally and by functions which have previously
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,
- SSLV3ServerCertData* server_cert_data)
+ SSLV3ServerCertData* server_cert_data, TLSConnectionParams* tls_connection_params)
{
const SSL_handshake_hello_t* hello;
const ServiceSSLV3CertsRecord* certs_rec;
hello = (const SSL_handshake_hello_t*)handshake;
retval |= SSL_decode_version_v3(hello->major, hello->minor);
+ if (tls_connection_params)
+ tls_connection_params->selected_tls_version = ntohs(*((const uint16_t*)((const uint8_t*)hello + offsetof(SSL_handshake_hello_t, major))));
/* Compare version of record with version of handshake */
if ((cur_flags & SSL_VERFLAGS) != (retval & SSL_VERFLAGS))
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:
case SSL_HS_SKEYX:
if (pkt_flags & PKT_FROM_SERVER)
+ {
retval |= SSL_SERVER_KEYX_FLAG | SSL_CUR_SERVER_KEYX_FLAG;
+
+ snort::parse_server_key_exchange((const uint8_t*)handshake+SSL_HS_PAYLOAD_OFFSET, size, tls_connection_params);
+ }
else
+ {
retval |= SSL_BOGUS_HS_DIR_FLAG;
+ }
break;
-
case SSL_HS_CKEYX:
if (pkt_flags & PKT_FROM_SERVER)
retval |= SSL_BOGUS_HS_DIR_FLAG;
static uint32_t SSL_decode_v3(const uint8_t* pkt, int size, uint32_t pkt_flags,
uint8_t* alert_flags, uint16_t* partial_rec_len, int max_hb_len, uint32_t* info_flags,
- SSLV3ClientHelloData* client_hello_data, SSLV3ServerCertData* server_cert_data, uint32_t prev_flags)
+ SSLV3ClientHelloData* client_hello_data, SSLV3ServerCertData* server_cert_data, uint32_t prev_flags, TLSConnectionParams* tls_connection_params)
{
uint32_t retval = 0;
uint16_t hblen;
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);
+ retval |= SSL_decode_handshake_v3(pkt, hsize, retval, pkt_flags, client_hello_data, server_cert_data, tls_connection_params);
}
else if (ccs)
{
return false;
}
-static uint32_t SSL_decode_v2(const uint8_t* pkt, int size, uint32_t pkt_flags)
+static uint32_t SSL_decode_v2(const uint8_t* pkt, int size, uint32_t pkt_flags, TLSConnectionParams* tls_connection_params)
{
const SSLv2_chello_t* chello;
const SSLv2_shello_t* shello;
break;
}
+ if (tls_connection_params)
+ tls_connection_params->selected_tls_version = ntohs(*((const uint16_t*)(pkt + offsetof(SSLv2_shello_t, major))));
+
break;
case SSL_V2_CKEY:
- retval |= SSL_CLIENT_KEYX_FLAG | SSL_CUR_CLIENT_KEYX_FLAG;
+ if (size < (int)sizeof(SSLv2_client_master_key_t))
+ {
+ retval |= SSL_TRUNCATED_FLAG;
+ break;
+ }
+ if (tls_connection_params)
+ tls_connection_params->cipher = ntohs(*((const uint16_t*)(pkt + offsetof(SSLv2_client_master_key_t, cipher_spec))));
+ retval |= SSL_CLIENT_KEYX_FLAG | SSL_CUR_CLIENT_KEYX_FLAG;
break;
default:
uint32_t SSL_decode(
const uint8_t* pkt, int size, uint32_t pkt_flags, uint32_t prev_flags,
uint8_t* alert_flags, uint16_t* partial_rec_len, int max_hb_len, uint32_t* info_flags,
- SSLV3ClientHelloData* client_hello_data, SSLV3ServerCertData* server_cert_data)
+ SSLV3ClientHelloData* client_hello_data, SSLV3ServerCertData* server_cert_data, TLSConnectionParams* tls_connection_params)
{
if (!pkt || !size)
return SSL_ARG_ERROR_FLAG;
/* Only SSL v2 will have these bits set */
if (((pkt[0] & 0x80) || (pkt[0] & 0x40)) && !(partial_rec_len && *partial_rec_len))
- return SSL_decode_v2(pkt, size, pkt_flags);
+ return SSL_decode_v2(pkt, size, pkt_flags, tls_connection_params);
/* If this packet is only 5 bytes, it inconclusive whether its SSLv2 or TLS.
* If it is v2, it's definitely truncated anyway. By decoding a 5 byte
* indicate that it is truncated. */
if (size == 5)
return SSL_decode_v3(pkt, size, pkt_flags, alert_flags, partial_rec_len, max_hb_len, info_flags,
- client_hello_data, server_cert_data, prev_flags);
+ client_hello_data, server_cert_data, prev_flags, tls_connection_params);
/* At this point, 'size' has to be > 5 */
/* If these lengths match, it's v3
Otherwise, it's v2 */
if (reclen - SSL_HS_PAYLOAD_OFFSET != datalen)
- return SSL_decode_v2(pkt, size, pkt_flags);
+ return SSL_decode_v2(pkt, size, pkt_flags, tls_connection_params);
}
}
}
/* If these lengths match, it's v3
Otherwise, it's v2 */
if (reclen - SSL_HS_PAYLOAD_OFFSET != datalen)
- return SSL_decode_v2(pkt, size, pkt_flags);
+ return SSL_decode_v2(pkt, size, pkt_flags, tls_connection_params);
}
}
return SSL_decode_v3(pkt, size, pkt_flags, alert_flags, partial_rec_len, max_hb_len, info_flags,
- client_hello_data, server_cert_data, prev_flags);
+ client_hello_data, server_cert_data, prev_flags, tls_connection_params);
}
/* very simplistic - just enough to say this is binary data - the rules will make a final
return false;
}
-ParseCHResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV3ClientHelloData* client_hello_data)
+ParseHelloResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV3ClientHelloData* client_hello_data)
{
if (client_hello_data == nullptr)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
if (size < sizeof(ServiceSSLV3Record))
- return ParseCHResult::FAILED;
+ return ParseHelloResult::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 ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
}
unsigned length = ntohs(rec->length) + offsetof(ServiceSSLV3Record, version);
if (size < length)
- return ParseCHResult::FRAGMENTED_PACKET;
+ return ParseHelloResult::FRAGMENTED_PACKET;
pkt += sizeof(ServiceSSLV3Record);
size -= sizeof(ServiceSSLV3Record);
/* Session ID (1-byte length). */
if (size < 1)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
length = *((const uint8_t*)pkt);
pkt += length + 1;
if (size < (length + 1))
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
size -= length + 1;
/* Cipher Suites (2-byte length). */
if (size < 2)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
length = ntohs(*((const uint16_t*)pkt));
pkt += length + 2;
if (size < (length + 2))
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
size -= length + 2;
/* Compression Methods (1-byte length). */
if (size < 1)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
length = *((const uint8_t*)pkt);
pkt += length + 1;
if (size < (length + 1))
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
size -= length + 1;
/* Extensions (2-byte length) */
if (size < 2)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
length = ntohs(*((const uint16_t*)pkt));
pkt += 2;
size -= 2;
if (size < length)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
/* We need at least type (2 bytes) and length (2 bytes) in the extension. */
while (length >= 4)
{
/* Found server host name. */
if (length < sizeof(ServiceSSLV3ExtensionServerName))
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
unsigned len = ntohs(ext->string_length);
if ((length - sizeof(ServiceSSLV3ExtensionServerName)) < len)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
const uint8_t* str = pkt + offsetof(ServiceSSLV3ExtensionServerName, string_length) +
sizeof(ext->string_length);
client_hello_data->host_name = snort_strndup((const char*)str, len);
- return ParseCHResult::SUCCESS;
+ return ParseHelloResult::SUCCESS;
}
unsigned len = ntohs(ext->length) + offsetof(ServiceSSLV3ExtensionServerName, list_length);
if (len > length)
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
pkt += len;
length -= len;
}
- return ParseCHResult::FAILED;
+ return ParseHelloResult::FAILURE;
+}
+
+ParseHelloResult parse_server_hello_data(const uint8_t* pkt, uint16_t size, TLSConnectionParams* tls_connection_params)
+{
+ if (tls_connection_params == nullptr)
+ return ParseHelloResult::FAILURE;
+
+ if (size < sizeof(ServiceSSLV3Record))
+ return ParseHelloResult::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;
+ }
+ unsigned length = ntohs(rec->length) + offsetof(ServiceSSLV3Record, version);
+ if (size < length)
+ return ParseHelloResult::FRAGMENTED_PACKET;
+ pkt += sizeof(ServiceSSLV3Record);
+ size -= sizeof(ServiceSSLV3Record);
+
+ /* Session ID (1-byte length). */
+ if (size < 1)
+ return ParseHelloResult::FAILURE;
+ length = *((const uint8_t*)pkt);
+ pkt += length + 1;
+ if (size < (length + 1))
+ return ParseHelloResult::FAILURE;
+ size -= length + 1;
+
+ /* Cipher Suite (2-byte length). */
+ if (size < 2)
+ return ParseHelloResult::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;
+ length = *((const uint8_t*)pkt);
+ pkt += length + 1;
+ if (size < (length + 1))
+ return ParseHelloResult::FAILURE;
+ size -= length + 1;
+
+ /* Extensions (2-byte length) */
+ if (size < 2)
+ return ParseHelloResult::FAILURE;
+ length = ntohs(*((const uint16_t*)pkt));
+ pkt += 2;
+ size -= 2;
+ if (size < length)
+ return ParseHelloResult::FAILURE;
+
+ /* We need at least type (2 bytes) and length (2 bytes) in the extension. */
+ while (length >= 4)
+ {
+ const ServiceSSLV3ExtensionSupportedVersion* ext = (const ServiceSSLV3ExtensionSupportedVersion*)pkt;
+ if (ntohs(ext->type) == SSL_EXT_SUPPORTED_VERSION)
+ {
+ /* Found supported version extension. */
+ if (length < sizeof(ServiceSSLV3ExtensionSupportedVersion))
+ return ParseHelloResult::FAILURE;
+
+ unsigned len = ntohs(ext->length);
+ if (len != sizeof(ext->supported_version))
+ return ParseHelloResult::FAILURE;
+
+ tls_connection_params->selected_tls_version = ntohs(ext->supported_version);
+ return ParseHelloResult::SUCCESS;
+ }
+
+ unsigned len = ntohs(ext->length) + offsetof(ServiceSSLV3ExtensionSupportedVersion, supported_version);
+ if (len > length)
+ return ParseHelloResult::FAILURE;
+
+ pkt += len;
+ length -= len;
+ }
+
+ return ParseHelloResult::FAILURE;
}
bool parse_server_certificates(SSLV3ServerCertData* server_cert_data)
if (!server_cert_data->certs_data or !server_cert_data->certs_len)
return false;
- char* common_name = nullptr;
- char* org_unit = nullptr;
const uint8_t* data = server_cert_data->certs_data;
int len = server_cert_data->certs_len;
+
+ char* common_name = nullptr;
int common_name_len = 0;
- int org_unit_len = 0;
+
+ char* org_unit = nullptr;
+ int org_unit_len = 0;
while (len > 2 and !(common_name and org_unit))
{
X509* cert = nullptr;
- X509_NAME* cert_name = nullptr;
+ X509_NAME* cert_subject = nullptr;
+ X509_NAME* cert_issuer = nullptr;
int cert_len = ntoh3(data);
data += 3;
if (!cert)
break;
- if (nullptr == (cert_name = X509_get_subject_name(cert)))
+ cert_subject = X509_get_subject_name(cert);
+ cert_issuer = X509_get_issuer_name(cert);
+
+ if (!cert_subject and !cert_issuer)
{
X509_free(cert);
continue;
}
- if (!common_name)
+ if (!server_cert_data->issuer_info)
+ {
+ BIO* issuer_bio = BIO_new(BIO_s_mem());
+ int read_issuer_status = X509_NAME_print_ex(issuer_bio, cert_issuer, 0, XN_FLAG_RFC2253);
+ if (read_issuer_status)
+ {
+ BUF_MEM* bptr = nullptr;
+ BIO_get_mem_ptr(issuer_bio, &bptr);
+ server_cert_data->issuer_info = snort_strndup(bptr->data, bptr->length);
+ server_cert_data->issuer_info_strlen = bptr->length;
+ }
+ BIO_free(issuer_bio);
+ }
+
+ if (!server_cert_data->subject_info)
+ {
+ BIO* subject_bio = BIO_new(BIO_s_mem());
+ int read_subject_status = X509_NAME_print_ex(subject_bio, cert_subject, 0, XN_FLAG_RFC2253);
+ if (read_subject_status)
+ {
+ BUF_MEM* bptr = nullptr;
+ BIO_get_mem_ptr(subject_bio, &bptr);
+ server_cert_data->subject_info = snort_strndup(bptr->data, bptr->length);
+ server_cert_data->subject_info_strlen = bptr->length;
+ }
+ BIO_free(subject_bio);
+ }
+
+ if (cert_subject and !common_name)
{
int lastpos = -1;
- lastpos = X509_NAME_get_index_by_NID(cert_name, NID_commonName, lastpos);
+ lastpos = X509_NAME_get_index_by_NID(cert_subject, NID_commonName, lastpos);
if (lastpos != -1)
{
- X509_NAME_ENTRY* e = X509_NAME_get_entry(cert_name, lastpos);
+ X509_NAME_ENTRY* e = X509_NAME_get_entry(cert_subject, lastpos);
const unsigned char* str_data = ASN1_STRING_get0_data(X509_NAME_ENTRY_get_data(e));
int length = strlen((const char*)str_data);
}
}
- if (!org_unit)
+ if (cert_subject and !org_unit)
{
int lastpos = -1;
- lastpos = X509_NAME_get_index_by_NID(cert_name, NID_organizationalUnitName, lastpos);
+ lastpos = X509_NAME_get_index_by_NID(cert_subject, NID_organizationalUnitName, lastpos);
if (lastpos != -1)
{
- X509_NAME_ENTRY* e = X509_NAME_get_entry(cert_name, lastpos);
+ X509_NAME_ENTRY* e = X509_NAME_get_entry(cert_subject, lastpos);
const unsigned char* str_data = ASN1_STRING_get0_data(X509_NAME_ENTRY_get_data(e));
org_unit_len = strlen((const char*)str_data);
org_unit = snort_strndup((const char*)(str_data), org_unit_len);
}
}
- cert_name = nullptr;
X509_free(cert);
}
return true;
}
+bool parse_server_key_exchange(const uint8_t* pkt, uint16_t size, TLSConnectionParams* tls_connection_params)
+{
+ if (tls_connection_params == nullptr)
+ return false;
+
+ if (size < 3)
+ return false;
+
+ uint8_t curve_type = *(pkt);
+
+ /* Non named curve, skipping */
+ if (curve_type != 3)
+ {
+ return false;
+ }
+
+ tls_connection_params->curve = ntohs(*(const uint16_t*)(pkt+1));
+
+ return true;
+}
+
} // namespace snort
#ifndef SSL_H
#define SSL_H
+#include <string>
+
#include "main/snort_types.h"
#define SSL_NO_FLAG 0x00000000
SSL_CUR_SERVER_KEYX_FLAG | SSL_CUR_CLIENT_KEYX_FLAG | \
SSL_UNKNOWN_FLAG)
+#define SSL_TLS_METADATA_FINISH_PACKET (SSL_SERVER_KEYX_FLAG | SSL_CLIENT_KEYX_FLAG | SSL_CHANGE_CIPHER_FLAG)
+
// Flag set when a client uses SSLv3/TLS backward compatibility and sends a
// SSLv2 Hello specifying an SSLv3/TLS version.
#define SSL_V3_BACK_COMPAT_V2 0x04000000
/* Flags for additional info */
#define SSL_ALERT_LVL_FATAL_FLAG 0x00000001
+#define SSL_TLS_METADATA_PUBLISHED 0x00000002
/* The constants used below are from RFC 2246 */
uint8_t length[3];
};
+struct SSL_random_t
+{
+ uint32_t gmt_unix_time;
+ uint8_t random_bytes[28];
+};
+
struct SSL_handshake_hello_t
{
uint8_t type;
uint8_t length[3];
uint8_t major;
uint8_t minor;
+ SSL_random_t random;
+ uint8_t session_id_length;
};
// http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
uint8_t minor;
};
+struct SSLv2_client_master_key_t
+{
+ uint16_t length;
+ uint8_t type;
+ uint8_t cipher_spec[3];
+};
+
struct SO_PUBLIC SSLV3ClientHelloData
{
~SSLV3ClientHelloData();
~SSLV3ServerCertData();
void clear();
/* While collecting certificates: */
- unsigned certs_len; // (Total) length of certificate(s).
+ unsigned certs_len = 0; // (Total) length of certificate(s).
uint8_t* certs_data = nullptr; // Certificate(s) data (each proceeded by length (3 bytes)).
/* Data collected from certificates afterwards: */
char* common_name = nullptr;
- int common_name_strlen;
+ int common_name_strlen = 0;
char* org_unit = nullptr;
- int org_unit_strlen;
+ int org_unit_strlen = 0;
+ char* issuer_info = nullptr;
+ int issuer_info_strlen = 0;
+ char* subject_info = nullptr;
+ int subject_info_strlen = 0;
+};
+
+struct SO_PUBLIC TLSConnectionParams
+{
+ uint16_t curve = 0;
+ uint16_t cipher = 0;
+ uint16_t selected_tls_version = 0;
+};
+
+struct SO_PUBLIC TLSConnectionData
+{
+ void process(const SSLV3ServerCertData& cert_data);
+ void process(const SSLV3ClientHelloData& client_hello_data);
+
+ std::string server_name_identifier;
+ std::string subject_info;
+ std::string issuer_info;
+ TLSConnectionParams tls_params;
};
enum class SSLV3RecordType : uint8_t
/* String follows. */
};
+struct ServiceSSLV3ExtensionSupportedVersion
+{
+ uint16_t type;
+ uint16_t length;
+ uint16_t supported_version;
+};
+
/* Extension types. */
#define SSL_EXT_SERVER_NAME 0
+#define SSL_EXT_SUPPORTED_VERSION 43
#define SSL_V2_MIN_LEN 5
namespace snort
{
-enum class ParseCHResult
+enum ParseHelloResult : uint8_t
{
SUCCESS = 0,
FRAGMENTED_PACKET = 1,
- FAILED = 2
+ FAILURE = 2
};
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);
+ SSLV3ClientHelloData* data = nullptr, SSLV3ServerCertData* server_cert_data = nullptr, TLSConnectionParams* tls_connection_params = nullptr);
- ParseCHResult parse_client_hello_data(const uint8_t* pkt, uint16_t size, SSLV3ClientHelloData*);
+ 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);
+ 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);
SO_PUBLIC bool IsTlsServerHello(const uint8_t* ptr, const uint8_t* end);
typedef struct X509_name_entry_st X509_NAME_ENTRY;
X509_NAME *X509_get_subject_name(const X509 *a) { return nullptr; }
+X509_NAME *X509_get_issuer_name(const X509 *a) { return nullptr; }
void X509_free(X509* a) { }
#if OPENSSL_VERSION_NUMBER < 0x30000000L
int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos)
X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc) { return nullptr; }
ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne) { return nullptr; }
const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x) { return nullptr; }
-X509* d2i_X509(X509 **a, const unsigned char **in, long len)
-{
- return nullptr;
-}
+X509* d2i_X509(X509 **a, const unsigned char **in, long len) { return nullptr; }
+int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent, unsigned long flags) { return 0; }
+BIO *BIO_new(const BIO_METHOD *type) { return nullptr; }
+int BIO_free(BIO *a) { return 0; }
+long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg) { return 0; }
+const BIO_METHOD *BIO_s_mem(void) { return nullptr; }
namespace snort
{
CHECK_EQUAL(0, test_data.certs_len);
}
+TEST(ssl_protocol_tests, parse_server_key_exchange_normal)
+{
+ TLSConnectionParams tls_params;
+ uint8_t test_data[3] = { 0x03, 0xFF, 0xFF }; // Valid curve type and 0xFFFF curve id
+ auto result = parse_server_key_exchange(test_data, sizeof(test_data), &tls_params);
+ CHECK_EQUAL(true, result);
+ CHECK_EQUAL(0xFFFF, tls_params.curve);
+}
+
+TEST(ssl_protocol_tests, parse_server_key_exchange_invalid_curve_type)
+{
+ TLSConnectionParams tls_params;
+ uint8_t test_data[3] = { 0x02, 0xFF, 0xFF }; // Invalid curve type
+ auto result = parse_server_key_exchange(test_data, sizeof(test_data), &tls_params);
+ CHECK_EQUAL(false, result);
+ CHECK_EQUAL(0, tls_params.curve);
+}
+
+TEST(ssl_protocol_tests, parse_server_key_exchange_invalid_len)
+{
+ TLSConnectionParams tls_params;
+ uint8_t test_data[2] = { 0x03, 0xFF }; // Invalid length, should be at least 3 bytes
+ auto result = parse_server_key_exchange(test_data, sizeof(test_data), &tls_params);
+ CHECK_EQUAL(false, result);
+ CHECK_EQUAL(0, tls_params.curve);
+}
+
+TEST(ssl_protocol_tests, parse_server_hello_tls_1_3)
+{
+ // This is a minimal valid Server Hello packet with TLS 1.3 version in extensions
+ uint8_t test_data[] = {
+ 0x02, // Handshake Type: Server Hello
+ 0x00, 0x00, 0x4e, // Length
+ 0x03, 0x03, // Version TLS 1.2
+ // Random (32 bytes)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Session ID length
+ 0x20,
+ // Session ID (32 bytes)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Cipher Suite (2 bytes)
+ 0xc0, 0x2b,
+ // Compression Method (1 byte)
+ 0x00,
+ // Extensions length (2 bytes)
+ 0x00, 0x06,
+ // Extension: Supported Versions (type=43 length=2)
+ 0x00, 0x2b,
+ 0x00, 0x02,
+ // Supported Version: TLS 1.3 (0x0304)
+ 0x03, 0x04
+ };
+
+ TLSConnectionParams tls_params;
+ auto result = parse_server_hello_data(test_data, sizeof(test_data), &tls_params);
+ CHECK_EQUAL(ParseHelloResult::SUCCESS, result);
+ CHECK_EQUAL(0x0304, tls_params.selected_tls_version);
+ CHECK_EQUAL(0xc02b, tls_params.cipher);
+}
+
+TEST(ssl_protocol_tests, parse_server_hello_invalid_packet_len)
+{
+ // This is an incomplete Server Hello packet
+ uint8_t test_data[] = {
+ 0x02, // Handshake Type: Server Hello
+ 0x00, 0x00, 0xF6, // Length invalid (too large for provided data)
+ 0x03, 0x03, // Version TLS 1.2
+ // Random (32 bytes)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Session ID length
+ 0x20,
+ // Session ID truncated
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ TLSConnectionParams tls_params;
+ auto result = parse_server_hello_data(test_data, sizeof(test_data), &tls_params);
+ CHECK_EQUAL(ParseHelloResult::FRAGMENTED_PACKET, result);
+}
+
int main(int argc, char** argv)
{
return CommandLineTestRunner::RunAllTests(argc, argv);
-}
\ No newline at end of file
+}
{
CHELLO_SERVER_NAME,
SERVER_COMMON_NAME,
+ SSL_TLS_METADATA_EVENT,
num_ids
};
const snort::Packet* packet;
};
+class SslTlsMetadataBaseEvent : public snort::DataEvent
+{
+public:
+ SslTlsMetadataBaseEvent() = default;
+ virtual ~SslTlsMetadataBaseEvent() override = default;
+
+ /* Values expected to be in host machine byte order */
+ virtual uint16_t get_version() const = 0;
+ virtual uint16_t get_curve() const = 0;
+ virtual uint16_t get_cipher() const = 0;
+ virtual const std::string& get_server_name_identifier() const = 0;
+ virtual const std::string& get_subject() const = 0;
+ virtual const std::string& get_issuer() const = 0;
+ virtual const std::string& get_validation_status() const = 0;
+ virtual const std::string& get_module_identifier() const = 0;
+};
+
#endif
#define SSL_FLOW_DATA_H
#include "flow/flow_data.h"
+#include "protocols/ssl.h"
+
+#include <string>
#define GID_SSL 137
struct SSLData
{
uint32_t ssn_flags;
+ uint32_t info_flags;
uint16_t partial_rec_len[4];
};
#include "protocols/ssl.h"
#include "pub_sub/finalize_packet_event.h"
#include "pub_sub/opportunistic_tls_event.h"
-#include "pub_sub/ssl_events.h"
#include "stream/stream.h"
#include "stream/stream_splitter.h"
#include "trace/trace_api.h"
{ CountType::END, nullptr, nullptr }
};
-SslFlowData::SslFlowData() : SslBaseFlowData()
+//-------------------------------------------------------------------------
+// class stuff
+//-------------------------------------------------------------------------
+class Ssl : public Inspector
+{
+public:
+ Ssl(SSL_PROTO_CONF*);
+ ~Ssl() override;
+
+ void show(const SnortConfig*) const override;
+ void eval(Packet*) override;
+ bool configure(SnortConfig*) override;
+
+ StreamSplitter* get_splitter(bool c2s) override
+ { return new SslSplitter(c2s); }
+
+ const static std::string s_name;
+
+private:
+ SSL_PROTO_CONF* config;
+};
+
+const std::string Ssl::s_name = "ssl";
+
+uint16_t SslMetadataEvent::get_version() const
+{
+ return tls_connection_data.tls_params.selected_tls_version;
+}
+
+const std::string& SslMetadataEvent::get_server_name_identifier() const
+{
+ return tls_connection_data.server_name_identifier;
+}
+
+uint16_t SslMetadataEvent::get_curve() const
+{
+ return tls_connection_data.tls_params.curve;
+}
+
+uint16_t SslMetadataEvent::get_cipher() const
+{
+ return tls_connection_data.tls_params.cipher;
+}
+
+const std::string& SslMetadataEvent::get_subject() const
+{
+ return tls_connection_data.subject_info;
+}
+
+const std::string& SslMetadataEvent::get_issuer() const
+{
+ return tls_connection_data.issuer_info;
+}
+
+const std::string& SslMetadataEvent::get_validation_status() const
+{
+ return validation_status;
+}
+
+const std::string& SslMetadataEvent::get_module_identifier() const
+{
+ return Ssl::s_name;
+}
+
+SslFlowData::SslFlowData(const snort::Flow* flow) : SslBaseFlowData(),
+ finalize_info(), tls_connection_data(), flow_handle(flow)
{
- memset(&session, 0, sizeof(session));
- finalize_info = {};
+ memset(&session, 0, sizeof(SSLData));
sslstats.concurrent_sessions++;
if(sslstats.max_concurrent_sessions < sslstats.concurrent_sessions)
sslstats.max_concurrent_sessions = sslstats.concurrent_sessions;
{
assert(sslstats.concurrent_sessions > 0);
sslstats.concurrent_sessions--;
+
+ if (!(session.info_flags & SSL_TLS_METADATA_PUBLISHED))
+ {
+ SslMetadataEvent event(tls_connection_data);
+ DataBus::publish(pub_id, SslEventIds::SSL_TLS_METADATA_EVENT, event, const_cast<snort::Flow*>(flow_handle));
+ }
}
-static SSLData* SetNewSSLData(Packet* p)
+static SslFlowData* SetNewSSLData(Packet* p)
{
- SslFlowData* fd = new SslFlowData;
+ SslFlowData* fd = new SslFlowData(p->flow);
p->flow->set_flow_data(fd);
- return &fd->get_session();
+ return fd;
}
static void SSL_UpdateCounts(const uint32_t new_flags)
Profile profile(sslPerfStats); // cppcheck-suppress unreadVariable
/* Attempt to get a previously allocated SSL block. */
- SSLData* sd = SslBaseFlowData::get_ssl_session_data(p->flow);
+ SslFlowData* fd = static_cast<SslFlowData*>(p->flow->get_flow_data(SslFlowData::get_ssl_inspector_id()));
- if (sd == nullptr)
+ if (fd == nullptr)
{
/* Check the stream session. If it does not currently
* have our SSL data-block attached, create one.
*/
- sd = SetNewSSLData(p);
+ fd = SetNewSSLData(p);
- if ( !sd )
+ if ( !fd )
// Could not get/create the session data for this packet.
return;
}
- SSL_CLEAR_TEMPORARY_FLAGS(sd->ssn_flags);
+ SSLData& sd = fd->get_session();
+
+ SSL_CLEAR_TEMPORARY_FLAGS(sd.ssn_flags);
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;
uint32_t info_flags = 0;
SSLV3ClientHelloData client_hello_data;
- SSLV3ServerCertData server_cert_data;
- 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,
- &server_cert_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,
+ &server_cert, &fd->get_tls_connection_data().tls_params);
+ sd.info_flags |= info_flags;
+
+ if (new_flags & SSL_CERTIFICATE_FLAG)
+ fd->get_tls_connection_data().process(server_cert);
+
+ if (new_flags & SSL_CLIENT_HELLO_FLAG)
+ fd->get_tls_connection_data().process(client_hello_data);
+
+ if (((new_flags & SSL_TLS_METADATA_FINISH_PACKET) or (fd->get_tls_connection_data().tls_params.selected_tls_version == 0x0304))
+ and !(sd.info_flags & SSL_TLS_METADATA_PUBLISHED))
+ {
+ SslMetadataEvent event(fd->get_tls_connection_data());
+ DataBus::publish(pub_id, SslEventIds::SSL_TLS_METADATA_EVENT, event, p->flow);
+ sd.info_flags |= SSL_TLS_METADATA_PUBLISHED;
+ }
if (client_hello_data.host_name != nullptr)
{
DataBus::publish(pub_id, SslEventIds::CHELLO_SERVER_NAME, event);
}
- if (server_cert_data.common_name != nullptr)
+ if (server_cert.common_name != nullptr)
{
- SslServerCommonNameEvent event(server_cert_data.common_name, p);
+ SslServerCommonNameEvent event(server_cert.common_name, p);
DataBus::publish(pub_id, SslEventIds::SERVER_COMMON_NAME, event);
}
DetectionEngine::queue_event(GID_SSL, SSL_ALERT_HB_RESPONSE);
}
}
- if (sd->ssn_flags & SSL_ENCRYPTED_FLAG )
+ if (sd.ssn_flags & SSL_ENCRYPTED_FLAG )
{
sslstats.decoded++;
sslstats.disabled++;
}
- sd->ssn_flags |= new_flags;
+ sd.ssn_flags |= new_flags;
return;
}
// compatibility flag and the SSLv2 flag since this session will continue
// as SSLv3/TLS.
- if ((sd->ssn_flags & SSL_V3_BACK_COMPAT_V2) && SSL_V3_SERVER_HELLO(new_flags))
- sd->ssn_flags &= ~(SSL_VER_SSLV2_FLAG|SSL_V3_BACK_COMPAT_V2);
+ if ((sd.ssn_flags & SSL_V3_BACK_COMPAT_V2) && SSL_V3_SERVER_HELLO(new_flags))
+ sd.ssn_flags &= ~(SSL_VER_SSLV2_FLAG|SSL_V3_BACK_COMPAT_V2);
- if ( (SSL_IS_CHELLO(new_flags) && SSL_IS_CHELLO(sd->ssn_flags) && SSL_IS_SHELLO(sd->ssn_flags) )
- || (SSL_IS_CHELLO(new_flags) && SSL_IS_SHELLO(sd->ssn_flags) ))
+ if ( (SSL_IS_CHELLO(new_flags) && SSL_IS_CHELLO(sd.ssn_flags) && SSL_IS_SHELLO(sd.ssn_flags) )
+ || (SSL_IS_CHELLO(new_flags) && SSL_IS_SHELLO(sd.ssn_flags) ))
{
DetectionEngine::queue_event(GID_SSL, SSL_INVALID_CLIENT_HELLO);
}
else if (!(config->trustservers))
{
- if ( (SSL_IS_SHELLO(new_flags) && !SSL_IS_CHELLO(sd->ssn_flags) ))
+ if ( (SSL_IS_SHELLO(new_flags) && !SSL_IS_CHELLO(sd.ssn_flags) ))
{
if (!(Stream::missed_packets(p->flow, SSN_DIR_FROM_CLIENT)))
DetectionEngine::queue_event(GID_SSL, SSL_INVALID_SERVER_HELLO);
if (SSL_IS_ALERT(new_flags))
{
- sd->ssn_flags = SSLPP_process_alert(config, sd->ssn_flags, new_flags, p, info_flags);
+ sd.ssn_flags = SSLPP_process_alert(config, sd.ssn_flags, new_flags, p, info_flags);
}
else if (SSL_IS_HANDSHAKE(new_flags))
{
- sd->ssn_flags = SSLPP_process_hs(sd->ssn_flags, new_flags);
+ sd.ssn_flags = SSLPP_process_hs(sd.ssn_flags, new_flags);
}
else if (SSL_IS_APP(new_flags))
{
- sd->ssn_flags = SSLPP_process_app(config, sd->ssn_flags, new_flags, p);
+ sd.ssn_flags = SSLPP_process_app(config, sd.ssn_flags, new_flags, p);
}
else if (SSL_IS_CHANGE_CIPHER(new_flags))
{
* the encrypted handshake message is inspected, and attempts to process some random type and it fails.
* To avoid this situation, update the 'change cipher spec' flag in the session to skip processing
* the encrypted handshake message.*/
- sd->ssn_flags |= SSL_CHANGE_CIPHER_FLAG;
+ sd.ssn_flags |= SSL_CHANGE_CIPHER_FLAG;
}
else
{
/* Different record type that we don't care about.
* * Either it's a 'change cipher spec' or we failed to recognize the
* * record type. Do not update session data */
- SSLPP_process_other(config, sd, new_flags, p);
+ SSLPP_process_other(config, &sd, new_flags, p);
/* Application data is updated inside of SSLPP_process_other */
return;
}
- sd->ssn_flags |= new_flags;
+ sd.ssn_flags |= new_flags;
}
-//-------------------------------------------------------------------------
-// class stuff
-//-------------------------------------------------------------------------
-static const char* s_name = "ssl";
-
-class Ssl : public Inspector
-{
-public:
- Ssl(SSL_PROTO_CONF*);
- ~Ssl() override;
-
- void show(const SnortConfig*) const override;
- void eval(Packet*) override;
- bool configure(SnortConfig*) override;
-
- StreamSplitter* get_splitter(bool c2s) override
- { return new SslSplitter(c2s); }
-
-private:
- SSL_PROTO_CONF* config;
-};
-
class SslStartTlsEventtHandler : public DataHandler
{
public:
- SslStartTlsEventtHandler() : DataHandler(s_name) { }
+ SslStartTlsEventtHandler() : DataHandler(Ssl::s_name.c_str()) { }
void handle(DataEvent&, Flow* flow) override
{
- SslFlowData* fd = new SslFlowData;
+ SslFlowData* fd = new SslFlowData(flow);
fd->finalize_info.orig_flag = flow->flags.trigger_finalize_event;
fd->finalize_info.switch_in = true;
flow->set_flow_data(fd);
class SslFinalizePacketHandler : public DataHandler
{
public:
- SslFinalizePacketHandler() : DataHandler(s_name) {}
+ SslFinalizePacketHandler() : DataHandler(Ssl::s_name.c_str()) {}
void handle(DataEvent& e, Flow*) override
{
pkt->flow->flags.trigger_finalize_event = fd->finalize_info.orig_flag;
fd->finalize_info.switch_in = false;
pkt->flow->set_proxied();
- pkt->flow->set_service(const_cast<Packet*>(pkt), s_name);
+ pkt->flow->set_service(const_cast<Packet*>(pkt), Ssl::s_name.c_str());
}
}
};
IT_SERVICE,
PROTO_BIT__PDU,
nullptr, // buffers
- s_name,
+ Ssl::s_name.c_str(),
ssl_init,
nullptr, // pterm
nullptr, // tinit
// Implementation header with definitions, datatypes and flowdata class for SSL service inspector.
#include "flow/flow.h"
+#include "pub_sub/ssl_events.h"
#include "ssl_flow_data.h"
+class SslMetadataEvent : public SslTlsMetadataBaseEvent
+{
+public:
+ SslMetadataEvent(const TLSConnectionData& conn_data)
+ : tls_connection_data(conn_data)
+ { }
+
+ virtual ~SslMetadataEvent() override
+ { }
+
+ uint16_t get_version() const override;
+ uint16_t get_curve() const override;
+ uint16_t get_cipher() const override;
+ const std::string& get_server_name_identifier() const override;
+ const std::string& get_subject() const override;
+ const std::string& get_issuer() const override;
+ const std::string& get_validation_status() const override;
+ const std::string& get_module_identifier() const override;
+
+private:
+ TLSConnectionData tls_connection_data;
+ std::string validation_status;
+};
+
class SslFlowData : public SslBaseFlowData
{
public:
- SslFlowData();
+ SslFlowData(const snort::Flow* flow);
~SslFlowData() override;
static void init()
SSLData& get_session() override
{ return session; }
+ TLSConnectionData& get_tls_connection_data()
+ { return tls_connection_data; }
+
public:
struct {
bool orig_flag : 1;
private:
SSLData session;
+ TLSConnectionData tls_connection_data;
+ const snort::Flow* flow_handle;
};
#endif