diff --git a/src/iocore/net/SSLStats.cc b/src/iocore/net/SSLStats.cc index 68fe3e72994..8b296551f14 100644 --- a/src/iocore/net/SSLStats.cc +++ b/src/iocore/net/SSLStats.cc @@ -33,10 +33,75 @@ SSLStatsBlock ssl_rsb; std::unordered_map cipher_map; +#ifdef OPENSSL_IS_BORINGSSL +std::unordered_map tls_group_map; +#elif defined(SSL_get_negotiated_group) +std::unordered_map tls_group_map; +#endif + namespace { DbgCtl dbg_ctl_ssl{"ssl"}; +#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_get_negotiated_group) + +template +void +add_group_stat(T key, const std::string &name) +{ + // If not already registered ... + if (tls_group_map.find(key) == tls_group_map.end()) { + Metrics::Counter::AtomicType *metric = Metrics::Counter::createPtr("proxy.process.ssl.group.user_agent." + name); + + tls_group_map.emplace(key, metric); + Dbg(dbg_ctl_ssl, "registering SSL group metric '%s'", name.c_str()); + } +} + +#endif // OPENSSL_IS_BORINGSSL or SSL_get_negotiated_group + +#if not defined(OPENSSL_IS_BORINGSSL) and defined(SSL_get_negotiated_group) // OPENSSL 3.x + +struct TLSGroup { + int nid; + std::string name; +}; + +// NID and Group table. Some groups are not defined by some library. +const TLSGroup TLS_GROUPS[] = { + {SSL_GROUP_STAT_OTHER_KEY, "OTHER" }, + {NID_X9_62_prime256v1, "P-256" }, + {NID_secp384r1, "P-384" }, + {NID_secp521r1, "P-521" }, + {NID_X25519, "X25519" }, +#ifdef NID_secp224r1 + {NID_secp224r1, "P-224" }, +#endif +#ifdef NID_X448 + {NID_X448, "X448" }, +#endif +#ifdef NID_ffdhe2048 + {NID_ffdhe2048, "ffdhe2048" }, +#endif +#ifdef NID_ffdhe3072 + {NID_ffdhe3072, "ffdhe3072" }, +#endif +#ifdef NID_ffdhe4096 + {NID_ffdhe4096, "ffdhe4096" }, +#endif +#ifdef NID_ffdhe6144 + {NID_ffdhe6144, "ffdhe6144" }, +#endif +#ifdef NID_ffdhe8192 + {NID_ffdhe8192, "ffdhe8192" }, +#endif +#ifdef NID_X25519MLKEM768 + {NID_X25519MLKEM768, "X25519MLKEM768"}, +#endif +}; + +#endif // OPENSSL 3.x + } // end anonymous namespace // ToDo: This gets called once per global sync, for now at least. @@ -175,6 +240,21 @@ SSLInitializeStatistics() // Add "OTHER" for ciphers not on the map add_cipher_stat(SSL_CIPHER_STAT_OTHER.c_str(), "proxy.process.ssl.cipher.user_agent." + SSL_CIPHER_STAT_OTHER); + // TLS Group +#if defined(OPENSSL_IS_BORINGSSL) + size_t list_size = SSL_get_all_group_names(nullptr, 0); + std::vector group_list(list_size); + SSL_get_all_group_names(group_list.data(), group_list.size()); + + for (const char *name : group_list) { + add_group_stat(name, name); + } +#elif defined(SSL_get_negotiated_group) + for (auto group : TLS_GROUPS) { + add_group_stat(group.nid, group.name); + } +#endif // OPENSSL_IS_BORINGSSL or SSL_get_negotiated_group + SSL_free(ssl); SSLReleaseContext(ctx); } diff --git a/src/iocore/net/SSLStats.h b/src/iocore/net/SSLStats.h index 6dbf070e422..1630036a300 100644 --- a/src/iocore/net/SSLStats.h +++ b/src/iocore/net/SSLStats.h @@ -30,6 +30,8 @@ #include "tsutil/Metrics.h" +#include + using ts::Metrics; // For some odd reason, these have to be initialized with nullptr, because the order @@ -100,6 +102,13 @@ struct SSLStatsBlock { extern SSLStatsBlock ssl_rsb; extern std::unordered_map cipher_map; +#if defined(OPENSSL_IS_BORINGSSL) +extern std::unordered_map tls_group_map; +#elif defined(SSL_get_negotiated_group) +extern std::unordered_map tls_group_map; +constexpr int SSL_GROUP_STAT_OTHER_KEY = 0; +#endif + // Initialize SSL statistics. void SSLInitializeStatistics(); diff --git a/src/iocore/net/SSLUtils.cc b/src/iocore/net/SSLUtils.cc index b519a0778fc..21684b8a97c 100644 --- a/src/iocore/net/SSLUtils.cc +++ b/src/iocore/net/SSLUtils.cc @@ -1086,6 +1086,28 @@ ssl_callback_info(const SSL *ssl, int where, int ret) } Metrics::Counter::increment(it->second); } + +#if defined(OPENSSL_IS_BORINGSSL) + uint16_t group_id = SSL_get_group_id(ssl); + if (group_id != 0) { + const char *group_name = SSL_get_group_name(group_id); + if (auto it = tls_group_map.find(group_name); it != tls_group_map.end()) { + Metrics::Counter::increment(it->second); + } else { + Warning("Unknown TLS Group"); + } + } +#elif defined(SSL_get_negotiated_group) + int nid = SSL_get_negotiated_group(const_cast(ssl)); + if (nid != NID_undef) { + if (auto it = tls_group_map.find(nid); it != tls_group_map.end()) { + Metrics::Counter::increment(it->second); + } else { + auto other = tls_group_map.find(SSL_GROUP_STAT_OTHER_KEY); + Metrics::Counter::increment(other->second); + } + } +#endif // OPENSSL_IS_BORINGSSL or SSL_get_negotiated_group } }