From 534ee93df4a80dec9418c87d7d31dcfeb3d308d5 Mon Sep 17 00:00:00 2001 From: vignvisw Date: Mon, 22 Jul 2024 20:02:51 +0530 Subject: [PATCH 1/9] Code improvements for CPU cycle counter --- src/libmerc/libmerc.cc | 3 + src/libmerc/pkt_proc.cc | 11 ++++ src/libmerc/tsc_clock.hpp | 100 +++++++++++++++++++++++++++++ unit_tests/functional_unit_test.cc | 2 + 4 files changed, 116 insertions(+) create mode 100644 src/libmerc/tsc_clock.hpp diff --git a/src/libmerc/libmerc.cc b/src/libmerc/libmerc.cc index f7eb8b6c..c2bb8104 100644 --- a/src/libmerc/libmerc.cc +++ b/src/libmerc/libmerc.cc @@ -14,6 +14,7 @@ #include "pkt_proc.h" #include "config_generator.h" #include "global_config.h" +#include "tsc_clock.hpp" #ifndef MERCURY_SEMANTIC_VERSION #warning MERCURY_SEMANTIC_VERSION is not defined @@ -41,6 +42,7 @@ static const uint32_t git_count = GIT_COUNT; static char init_time[128] = { '\0' }; +uint64_t tsc_clock::clock_ticks_per_sec = 0; void mercury_print_version_string(FILE *f) { struct semantic_version mercury_version(MERCURY_SEMANTIC_VERSION); @@ -89,6 +91,7 @@ mercury_context mercury_init(const struct libmerc_config *vars, int verbosity) { // taking place // assert(printf_err(log_info, "libmerc is running assert() tests\n") != 0); + tsc_clock::initialize(); try { m = new mercury{vars, verbosity}; diff --git a/src/libmerc/pkt_proc.cc b/src/libmerc/pkt_proc.cc index 6719d1a0..950d09c7 100644 --- a/src/libmerc/pkt_proc.cc +++ b/src/libmerc/pkt_proc.cc @@ -53,6 +53,7 @@ #include "openvpn.h" #include "mysql.hpp" #include "geneve.hpp" +#include "tsc_clock.hpp" // double malware_prob_threshold = -1.0; // TODO: document hidden option @@ -508,6 +509,11 @@ size_t stateful_pkt_proc::ip_write_json(void *buffer, } } + if (ts->tv_sec == 0) { + tsc_clock time_now; + ts->tv_sec = time_now.time_in_seconds(); + } + // process transport/application protocols // protocol x; @@ -785,6 +791,11 @@ bool stateful_pkt_proc::analyze_ip_packet(const uint8_t *packet, if (reassembler) { reassembler->dump_pkt = false; } + if (ts->tv_sec == 0) { + tsc_clock time_now; + ts->tv_sec = time_now.time_in_seconds(); + } + if (transport_proto == ip::protocol::tcp) { tcp_packet tcp_pkt{pkt, &ip_pkt}; if (!tcp_pkt.is_valid()) { diff --git a/src/libmerc/tsc_clock.hpp b/src/libmerc/tsc_clock.hpp new file mode 100644 index 00000000..b2434c68 --- /dev/null +++ b/src/libmerc/tsc_clock.hpp @@ -0,0 +1,100 @@ +// tsc_clock.hpp +// +// Methods to measure time elapsed using CPU ticks + +#ifndef TSC_CLOCK_HPP +#define TSC_CLOCK_HPP + +#include +#include + +using namespace std::chrono_literals; + +class tsc_clock +{ + uint64_t start_tick; + +public: + static uint64_t get_clock_ticks_per_sec() { + tsc_clock start; + std::this_thread::sleep_for(1s); + tsc_clock end; + return (end.get_tick() - start.get_tick()); + } + static uint64_t clock_ticks_per_sec; + + static void initialize() { + clock_ticks_per_sec = get_clock_ticks_per_sec(); + } + + tsc_clock() { + start_tick = read_timestamp_counter(); + } + + time_t time_in_seconds() const { + if (!is_valid()) { + return 0; + } + + return (start_tick / clock_ticks_per_sec); + } + + uint64_t elapsed_time() const { + if (!is_valid()) { + return 0; + } + + return(read_timestamp_counter() - get_tick()); + } + + time_t elapsed_time_in_sec() const { + if (!is_valid()) { + return 0; + } + + return (elapsed_time() / clock_ticks_per_sec); + } + + + static uint64_t read_timestamp_counter() { +#if defined(__i386__) || defined(__x86_64__) + uint32_t lo, hi; + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); + return ((uint64_t)hi << 32) | lo; +#elif defined(__aarch64__) + uint64_t ticks; + asm volatile("mrs %0, CNTVCT_EL0" : "=r" (ticks)); + return ticks; +#else + return 0; +#endif + } + + uint64_t get_tick() const { + return start_tick; + } + + static bool is_valid() { + if (clock_ticks_per_sec) { + return true; + } + + return false; + } + +#ifndef NDEBUG + static bool unit_test() { + tsc_clock start; + // Pass this test for unsupported platform + if (is_valid()) { + return true; + } + std::this_thread::sleep_for(1s); + if (start.elapsed_time_in_sec() == 1) { + return true; + } + return false; + } +#endif //NDEBUG +}; +#endif //TSC_CLOCK_HPP diff --git a/unit_tests/functional_unit_test.cc b/unit_tests/functional_unit_test.cc index 97594864..000e9f15 100644 --- a/unit_tests/functional_unit_test.cc +++ b/unit_tests/functional_unit_test.cc @@ -11,6 +11,7 @@ #include "snmp.h" #include "tofsee.hpp" #include "utf8.hpp" +#include "tsc_clock.hpp" /* * The unit_test() functions defined in header files @@ -24,4 +25,5 @@ TEST_CASE("Testing unit_test() defined in class") { CHECK(tofsee_initial_message::unit_test() == true); CHECK(tls_extensions::unit_test() == true); CHECK(utf8_string::unit_test() == true); + CHECK(tsc_clock::unit_test() == true); } From fa217522726e3d871a1391a711e080272a64cd61 Mon Sep 17 00:00:00 2001 From: vignvisw Date: Tue, 23 Jul 2024 15:28:30 +0530 Subject: [PATCH 2/9] minor code improvements --- src/libmerc/libmerc.cc | 3 --- src/libmerc/tsc_clock.hpp | 51 +++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/libmerc/libmerc.cc b/src/libmerc/libmerc.cc index c2bb8104..f7eb8b6c 100644 --- a/src/libmerc/libmerc.cc +++ b/src/libmerc/libmerc.cc @@ -14,7 +14,6 @@ #include "pkt_proc.h" #include "config_generator.h" #include "global_config.h" -#include "tsc_clock.hpp" #ifndef MERCURY_SEMANTIC_VERSION #warning MERCURY_SEMANTIC_VERSION is not defined @@ -42,7 +41,6 @@ static const uint32_t git_count = GIT_COUNT; static char init_time[128] = { '\0' }; -uint64_t tsc_clock::clock_ticks_per_sec = 0; void mercury_print_version_string(FILE *f) { struct semantic_version mercury_version(MERCURY_SEMANTIC_VERSION); @@ -91,7 +89,6 @@ mercury_context mercury_init(const struct libmerc_config *vars, int verbosity) { // taking place // assert(printf_err(log_info, "libmerc is running assert() tests\n") != 0); - tsc_clock::initialize(); try { m = new mercury{vars, verbosity}; diff --git a/src/libmerc/tsc_clock.hpp b/src/libmerc/tsc_clock.hpp index b2434c68..0158934a 100644 --- a/src/libmerc/tsc_clock.hpp +++ b/src/libmerc/tsc_clock.hpp @@ -5,6 +5,25 @@ #ifndef TSC_CLOCK_HPP #define TSC_CLOCK_HPP +#if defined(__i386__) || defined(__x86_64__) + #define read_timestamp_counter() ({ \ + uint32_t lo, hi; \ + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); \ + ((uint64_t)hi << 32) | lo; \ + }) + #define tsc_clock_is_valid true +#elif defined(__aarch64__) + #define read_timestamp_counter() ({ \ + uint64_t ticks; \ + asm volatile("mrs %0, CNTVCT_EL0" : "=r" (ticks)); \ + ticks; \ + }) + #define tsc_clock_is_valid true +#else + #define read_timestamp_counter() 0 + #define tsc_clock_is_valid false +#endif + #include #include @@ -15,16 +34,12 @@ class tsc_clock uint64_t start_tick; public: + static uint64_t get_clock_ticks_per_sec() { tsc_clock start; std::this_thread::sleep_for(1s); tsc_clock end; - return (end.get_tick() - start.get_tick()); - } - static uint64_t clock_ticks_per_sec; - - static void initialize() { - clock_ticks_per_sec = get_clock_ticks_per_sec(); + return (end.get_start_tick() - start.get_start_tick()); } tsc_clock() { @@ -32,6 +47,7 @@ class tsc_clock } time_t time_in_seconds() const { + static const uint64_t clock_ticks_per_sec = get_clock_ticks_per_sec(); if (!is_valid()) { return 0; } @@ -44,10 +60,11 @@ class tsc_clock return 0; } - return(read_timestamp_counter() - get_tick()); + return(read_timestamp_counter() - get_start_tick()); } time_t elapsed_time_in_sec() const { + static const uint64_t clock_ticks_per_sec = get_clock_ticks_per_sec(); if (!is_valid()) { return 0; } @@ -55,27 +72,12 @@ class tsc_clock return (elapsed_time() / clock_ticks_per_sec); } - - static uint64_t read_timestamp_counter() { -#if defined(__i386__) || defined(__x86_64__) - uint32_t lo, hi; - asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); - return ((uint64_t)hi << 32) | lo; -#elif defined(__aarch64__) - uint64_t ticks; - asm volatile("mrs %0, CNTVCT_EL0" : "=r" (ticks)); - return ticks; -#else - return 0; -#endif - } - - uint64_t get_tick() const { + uint64_t get_start_tick() const { return start_tick; } static bool is_valid() { - if (clock_ticks_per_sec) { + if (tsc_clock_is_valid) { return true; } @@ -97,4 +99,5 @@ class tsc_clock } #endif //NDEBUG }; + #endif //TSC_CLOCK_HPP From 4adab007681de09e225ee5745d19cffc0a7a696b Mon Sep 17 00:00:00 2001 From: vignvisw Date: Wed, 24 Jul 2024 15:40:04 +0530 Subject: [PATCH 3/9] minor revision --- src/libmerc/libmerc.cc | 5 ++++- src/libmerc/pkt_proc.cc | 1 + src/libmerc/tsc_clock.hpp | 28 +++++++++++++++++----------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/libmerc/libmerc.cc b/src/libmerc/libmerc.cc index f7eb8b6c..ddf414f7 100644 --- a/src/libmerc/libmerc.cc +++ b/src/libmerc/libmerc.cc @@ -14,6 +14,7 @@ #include "pkt_proc.h" #include "config_generator.h" #include "global_config.h" +#include "tsc_clock.hpp" #ifndef MERCURY_SEMANTIC_VERSION #warning MERCURY_SEMANTIC_VERSION is not defined @@ -89,7 +90,9 @@ mercury_context mercury_init(const struct libmerc_config *vars, int verbosity) { // taking place // assert(printf_err(log_info, "libmerc is running assert() tests\n") != 0); - + // Calculate the cpu ticks per sec during initialization time + // to avoid delay during packet processing path + tsc_clock::get_ticks_per_sec(); try { m = new mercury{vars, verbosity}; return m; diff --git a/src/libmerc/pkt_proc.cc b/src/libmerc/pkt_proc.cc index 950d09c7..f8c1bc56 100644 --- a/src/libmerc/pkt_proc.cc +++ b/src/libmerc/pkt_proc.cc @@ -791,6 +791,7 @@ bool stateful_pkt_proc::analyze_ip_packet(const uint8_t *packet, if (reassembler) { reassembler->dump_pkt = false; } + if (ts->tv_sec == 0) { tsc_clock time_now; ts->tv_sec = time_now.time_in_seconds(); diff --git a/src/libmerc/tsc_clock.hpp b/src/libmerc/tsc_clock.hpp index 0158934a..9eedd02e 100644 --- a/src/libmerc/tsc_clock.hpp +++ b/src/libmerc/tsc_clock.hpp @@ -35,11 +35,19 @@ class tsc_clock public: - static uint64_t get_clock_ticks_per_sec() { - tsc_clock start; - std::this_thread::sleep_for(1s); - tsc_clock end; - return (end.get_start_tick() - start.get_start_tick()); + static uint64_t get_ticks_per_sec() { + if (!tsc_clock_is_valid) { + return 0; + } + + static uint64_t ticks_per_second = 0; + if (ticks_per_second == 0) { + tsc_clock start; + std::this_thread::sleep_for(1s); + tsc_clock end; + ticks_per_second = end.get_start_tick() - start.get_start_tick(); + } + return ticks_per_second; } tsc_clock() { @@ -47,15 +55,14 @@ class tsc_clock } time_t time_in_seconds() const { - static const uint64_t clock_ticks_per_sec = get_clock_ticks_per_sec(); if (!is_valid()) { return 0; } - return (start_tick / clock_ticks_per_sec); + return (get_start_tick() / get_ticks_per_sec()); } - uint64_t elapsed_time() const { + uint64_t elapsed_tick() const { if (!is_valid()) { return 0; } @@ -64,12 +71,11 @@ class tsc_clock } time_t elapsed_time_in_sec() const { - static const uint64_t clock_ticks_per_sec = get_clock_ticks_per_sec(); if (!is_valid()) { return 0; } - return (elapsed_time() / clock_ticks_per_sec); + return (elapsed_tick() / get_ticks_per_sec()); } uint64_t get_start_tick() const { @@ -88,7 +94,7 @@ class tsc_clock static bool unit_test() { tsc_clock start; // Pass this test for unsupported platform - if (is_valid()) { + if (!is_valid()) { return true; } std::this_thread::sleep_for(1s); From b1969a08cecade7b859863c994cad7d375b6c9a1 Mon Sep 17 00:00:00 2001 From: vignvisw Date: Wed, 24 Jul 2024 20:18:22 +0530 Subject: [PATCH 4/9] Fixing unit test --- src/libmerc/tsc_clock.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libmerc/tsc_clock.hpp b/src/libmerc/tsc_clock.hpp index 9eedd02e..0894f34c 100644 --- a/src/libmerc/tsc_clock.hpp +++ b/src/libmerc/tsc_clock.hpp @@ -98,7 +98,8 @@ class tsc_clock return true; } std::this_thread::sleep_for(1s); - if (start.elapsed_time_in_sec() == 1) { + uint64_t elapsed_time = start.elapsed_time_in_sec(); + if (elapsed_time == 1) { return true; } return false; From 17f7e7e1566d9c9f389afe3274bd6db4fb280a30 Mon Sep 17 00:00:00 2001 From: vignvisw Date: Wed, 31 Jul 2024 17:04:00 +0530 Subject: [PATCH 5/9] Code improvements to measure cpu ticks per second --- src/libmerc/bench.h | 37 +----------------- src/libmerc/libmerc.cc | 2 +- src/libmerc/tsc_clock.hpp | 79 ++++++++++++++++++++++----------------- src/pcap_file_io.c | 4 +- 4 files changed, 49 insertions(+), 73 deletions(-) diff --git a/src/libmerc/bench.h b/src/libmerc/bench.h index 269f2c5e..2f06e3f3 100644 --- a/src/libmerc/bench.h +++ b/src/libmerc/bench.h @@ -5,46 +5,13 @@ #ifndef BENCH_H #define BENCH_H -// The cycle_counter class will compile anywhere, but will only work -// correctly on platforms that provide a function to read the -// timestamp counter. The following preprocessor conditionals -// identify the appropriate function, if one is present, and set -// benchmark_is_valid to true or false. That value can be accessed -// through the constexpr static boolean benchmark::is_valid. -// -#ifdef HAVE_X86INTRIN_H - #include - #define read_timestamp_counter() __rdtsc() - #define benchmark_is_valid true -#else - #define read_timestamp_counter() 0 - #define benchmark_is_valid false -#endif -// -// TODO: add the corresponding ARM equivalent function - #include // for sqrt() +#include "tsc_clock.hpp" namespace benchmark { - static constexpr bool is_valid = benchmark_is_valid; - - // An object of class cycle_counter counts the number of clock - // cycles between its construction and the invocation of the - // delta() function - // - class cycle_counter { - uint64_t value; - - public: - - cycle_counter() : value{read_timestamp_counter()} { } - - uint64_t delta() const { return read_timestamp_counter() - value; } - - }; + static bool is_valid = tsc_clock::is_valid(); - // An object of class count_and_mean maintains a count and mean of // all of the observed numbers. Each observation is reported with // the member function +=, e.g. 's += x' observes x. // diff --git a/src/libmerc/libmerc.cc b/src/libmerc/libmerc.cc index ddf414f7..45c3d585 100644 --- a/src/libmerc/libmerc.cc +++ b/src/libmerc/libmerc.cc @@ -92,7 +92,7 @@ mercury_context mercury_init(const struct libmerc_config *vars, int verbosity) { assert(printf_err(log_info, "libmerc is running assert() tests\n") != 0); // Calculate the cpu ticks per sec during initialization time // to avoid delay during packet processing path - tsc_clock::get_ticks_per_sec(); + tsc_clock::init(); try { m = new mercury{vars, verbosity}; return m; diff --git a/src/libmerc/tsc_clock.hpp b/src/libmerc/tsc_clock.hpp index 0894f34c..010a11e7 100644 --- a/src/libmerc/tsc_clock.hpp +++ b/src/libmerc/tsc_clock.hpp @@ -1,31 +1,18 @@ -// tsc_clock.hpp -// -// Methods to measure time elapsed using CPU ticks +/* + * tsc_clock.hpp + * + * Methods to measure time elapsed using CPU ticks + * + * Copyright (c) 2021 Cisco Systems, Inc. All rights reserved. License at + * https://github.com/cisco/mercury/blob/master/LICENSE + */ #ifndef TSC_CLOCK_HPP #define TSC_CLOCK_HPP -#if defined(__i386__) || defined(__x86_64__) - #define read_timestamp_counter() ({ \ - uint32_t lo, hi; \ - asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); \ - ((uint64_t)hi << 32) | lo; \ - }) - #define tsc_clock_is_valid true -#elif defined(__aarch64__) - #define read_timestamp_counter() ({ \ - uint64_t ticks; \ - asm volatile("mrs %0, CNTVCT_EL0" : "=r" (ticks)); \ - ticks; \ - }) - #define tsc_clock_is_valid true -#else - #define read_timestamp_counter() 0 - #define tsc_clock_is_valid false -#endif - #include #include +#include using namespace std::chrono_literals; @@ -36,30 +23,39 @@ class tsc_clock public: static uint64_t get_ticks_per_sec() { - if (!tsc_clock_is_valid) { + if (!is_valid()) { return 0; } - static uint64_t ticks_per_second = 0; + /* + * Calculating the number of cpu ticks per second + * by counting the number of cpu ticks in 1/100th of second + * and then upscaling to get the number of cpu ticks per second + */ + if (ticks_per_second == 0) { tsc_clock start; - std::this_thread::sleep_for(1s); + std::this_thread::sleep_for(10ms); tsc_clock end; - ticks_per_second = end.get_start_tick() - start.get_start_tick(); + ticks_per_second = (end.get_start_tick() - start.get_start_tick()) * 100; } return ticks_per_second; } + static void init() { + get_ticks_per_sec(); + } + tsc_clock() { start_tick = read_timestamp_counter(); } - time_t time_in_seconds() const { + uint64_t time_in_seconds() const { if (!is_valid()) { return 0; } - return (get_start_tick() / get_ticks_per_sec()); + return (std::round(static_cast(get_start_tick()) / get_ticks_per_sec())); } uint64_t elapsed_tick() const { @@ -75,22 +71,36 @@ class tsc_clock return 0; } - return (elapsed_tick() / get_ticks_per_sec()); + return (std::round(static_cast(elapsed_tick()) / get_ticks_per_sec())); } uint64_t get_start_tick() const { return start_tick; } - static bool is_valid() { - if (tsc_clock_is_valid) { - return true; + static inline bool is_valid() { + static bool tsc_counter = read_timestamp_counter(); + if (tsc_counter == 0) { + return false; } - return false; + return true; + } + + static inline uint64_t read_timestamp_counter() { +#if defined(__i386__) || defined(__x86_64__) + uint32_t lo, hi; + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); + return ((uint64_t)hi << 32) | lo; +#elif defined(__aarch64__) + uint64_t ticks; + asm volatile("mrs %0, CNTVCT_EL0" : "=r" (ticks)); + return ticks; +#else + return 0; +#endif } -#ifndef NDEBUG static bool unit_test() { tsc_clock start; // Pass this test for unsupported platform @@ -104,7 +114,6 @@ class tsc_clock } return false; } -#endif //NDEBUG }; #endif //TSC_CLOCK_HPP diff --git a/src/pcap_file_io.c b/src/pcap_file_io.c index 127e6826..d8cda5f6 100644 --- a/src/pcap_file_io.c +++ b/src/pcap_file_io.c @@ -484,9 +484,9 @@ enum status pcap_file_dispatch_pkt_processor(struct pcap_file *f, packet_info_init_from_pkthdr(&pi, &pkthdr); pi.linktype = f->linktype; // process the packet that was read - benchmark::cycle_counter cc; + tsc_clock cc; pkt_processor->apply(&pi, packet_data); - s += cc.delta(); + s += cc.elapsed_tick(); num_packets++; total_length += pkthdr.caplen + sizeof(struct pcap_packet_hdr); } From 674c83b12302c62cc30e0776d9cf80329c4fa163 Mon Sep 17 00:00:00 2001 From: David McGrew Date: Mon, 5 Aug 2024 18:09:30 -0400 Subject: [PATCH 6/9] adding (client or server) tls_certificate --- src/libmerc/pkt_proc.cc | 4 ++- src/libmerc/pkt_proc_util.h | 6 ++++ src/libmerc/tls.h | 68 +++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/libmerc/pkt_proc.cc b/src/libmerc/pkt_proc.cc index 6719d1a0..697a3fb1 100644 --- a/src/libmerc/pkt_proc.cc +++ b/src/libmerc/pkt_proc.cc @@ -217,9 +217,11 @@ void stateful_pkt_proc::set_tcp_protocol(protocol &x, break; } case tcp_msg_type_tls_server_hello: - case tcp_msg_type_tls_certificate: x.emplace(pkt, tcp_pkt); break; + case tcp_msg_type_tls_certificate: + x.emplace(pkt, tcp_pkt); + break; case tcp_msg_type_ssh: x.emplace(pkt); break; diff --git a/src/libmerc/pkt_proc_util.h b/src/libmerc/pkt_proc_util.h index 03d38c8a..28279473 100644 --- a/src/libmerc/pkt_proc_util.h +++ b/src/libmerc/pkt_proc_util.h @@ -38,6 +38,7 @@ struct http_request; // start of tcp protocols struct http_response; struct tls_client_hello; class tls_server_hello_and_certificate; +class tls_certificate; struct ssh_init_packet; struct ssh_kex_init; class smtp_client; @@ -72,6 +73,7 @@ using protocol = std::variantreassembly_needed(certificate.additional_bytes_needed); + } + } + + bool is_not_empty() { + return certificate.is_not_empty(); + } + + void write_json(struct json_object &record, bool metadata_output, bool certs_json_output) { + (void)metadata_output; + + bool have_certificate = certificate.is_not_empty(); + if (have_certificate) { + + // output certificate + // + struct json_object tls{record, "tls"}; + struct json_array certs{tls, "certs"}; + certificate.write_json(certs, certs_json_output); + certs.close(); + tls.close(); + + } + } + +}; + + static uint16_t degrease_uint16(uint16_t x) { switch(x) { case 0x0a0a: From d615598ffb4f2b70d2be340d74021e963781f545 Mon Sep 17 00:00:00 2001 From: David McGrew Date: Thu, 15 Aug 2024 09:21:30 -0400 Subject: [PATCH 7/9] adding client/server key exchange detection --- src/libmerc/tls.h | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/libmerc/tls.h b/src/libmerc/tls.h index 8d0d5504..b41ad7b9 100644 --- a/src/libmerc/tls.h +++ b/src/libmerc/tls.h @@ -203,8 +203,10 @@ enum class handshake_type : uint8_t { end_of_early_data = 5, encrypted_extensions = 8, certificate = 11, + server_key_exchange = 12, certificate_request = 13, certificate_verify = 15, + client_key_exchange = 16, finished = 20, key_update = 24, message_hash = 254 @@ -591,12 +593,19 @@ class tls_server_hello_and_certificate : public base_protocol { // } KeyExchangeAlgorithm; +enum role { + client, + server, + undetected +}; + class tls_certificate : public base_protocol { struct tls_server_certificate certificate; + role entity; public: - tls_certificate(struct datum &pkt, struct tcp_packet *tcp_pkt) : certificate{} { + tls_certificate(struct datum &pkt, struct tcp_packet *tcp_pkt) : certificate{}, entity{undetected} { parse(pkt, tcp_pkt); } @@ -608,6 +617,24 @@ class tls_certificate : public base_protocol { struct tls_handshake handshake{rec.fragment}; if (handshake.msg_type == handshake_type::certificate) { certificate.parse(handshake.body); + + if (rec.fragment.is_not_empty()) { + tls_handshake handshake{rec.fragment}; + if (handshake.msg_type == handshake_type::client_key_exchange) { + entity = client; + } else if (handshake.msg_type == handshake_type::server_key_exchange) { + entity = server; + } + } else if (pkt.is_not_empty()) { + tls_record rec2{pkt}; + tls_handshake handshake{rec2.fragment}; + if (handshake.msg_type == handshake_type::client_key_exchange) { + entity = client; + } else if (handshake.msg_type == handshake_type::server_key_exchange) { + entity = server; + } + } + } if (tcp_pkt && certificate.additional_bytes_needed) { tcp_pkt->reassembly_needed(certificate.additional_bytes_needed); @@ -626,10 +653,18 @@ class tls_certificate : public base_protocol { // output certificate // + const char *role = "undetermined"; + if (entity == client) { + role = "client"; + } else if (entity == server) { + role = "server"; + } struct json_object tls{record, "tls"}; - struct json_array certs{tls, "certs"}; + json_object client_or_server{tls, role}; + struct json_array certs{client_or_server, "certs"}; certificate.write_json(certs, certs_json_output); certs.close(); + client_or_server.close(); tls.close(); } From 092ef58d08f0a132359b2cee790f392a0bde4710 Mon Sep 17 00:00:00 2001 From: David McGrew Date: Thu, 22 Aug 2024 13:52:31 -0400 Subject: [PATCH 8/9] incrementing patchlevel --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index cf43527f..5cdd6f64 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.5.30 +2.5.31 From ccdbed3655a3c2c7e53d4221db42c53e397ef286 Mon Sep 17 00:00:00 2001 From: David McGrew Date: Thu, 22 Aug 2024 13:53:06 -0400 Subject: [PATCH 9/9] adding changelog --- doc/CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 38f370b7..fb45effd 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,5 +1,17 @@ # CHANGELOG for Mercury +## Version 2.5.31 +* Mercury now outputs `tls.client.certs` and `tls.undetermined.certs` + as well as `tls.server.certs`, for TLS version 1.2 and earlier. + Client and server certificate chains are distinguished by the + handshake type of the key exchange data that follows the + `Certificate` data. If no key exchange data is present, then the + certificate is reported as `tls.undetermined.certs`. +* Timestamp counter reading support for ARM added in + [tsc_clock.hpp](src/libmerc/tsc_clock.hpp). +* If a timestamp of `0` is passed to `libmerc`, a timestamp is + computed in order to improve the reassembly of TCP messages, as needed. + ## Version 2.5.30 * Dramatic improvements to TCP reassembly for output, performance and TCP segments handling. * Improved error handling for malformed UTF-8 strings encountered in protocol fields.