Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ check_symbol_exists(SSL_get_shared_curve "openssl/ssl.h" HAVE_SSL_GET_SHARED_CUR
check_symbol_exists(SSL_get_curve_name "openssl/ssl.h" HAVE_SSL_GET_CURVE_NAME)
check_symbol_exists(SSL_get0_group_name "openssl/ssl.h" HAVE_SSL_GET0_GROUP_NAME)
check_symbol_exists(SSL_get_negotiated_group "openssl/ssl.h" HAVE_SSL_GET_NEGOTIATED_GROUP)
check_symbol_exists(SSL_CTX_get0_implemented_groups "openssl/ssl.h" HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS)
check_symbol_exists(SSL_get_group_id "openssl/ssl.h" HAVE_SSL_GET_GROUP_ID)
check_symbol_exists(SSL_get_group_name "openssl/ssl.h" HAVE_SSL_GET_GROUP_NAME)
check_symbol_exists(SSL_group_to_name "openssl/ssl.h" HAVE_SSL_GROUP_TO_NAME)
Expand Down
1 change: 1 addition & 0 deletions include/tscore/ink_config.h.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ const int DEFAULT_STACKSIZE = @DEFAULT_STACK_SIZE@;
#cmakedefine01 HAVE_SSL_GET_CURVE_NAME
#cmakedefine01 HAVE_SSL_GET0_GROUP_NAME
#cmakedefine01 HAVE_SSL_GET_NEGOTIATED_GROUP
#cmakedefine01 HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS
#cmakedefine01 HAVE_SSL_GET_GROUP_ID
#cmakedefine01 HAVE_SSL_GET_GROUP_NAME
#cmakedefine01 HAVE_SSL_GROUP_TO_NAME
Expand Down
75 changes: 54 additions & 21 deletions src/iocore/net/SSLStats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
SSLStatsBlock ssl_rsb;
std::unordered_map<std::string, Metrics::Counter::AtomicType *> cipher_map;

#ifdef OPENSSL_IS_BORINGSSL
#if defined(OPENSSL_IS_BORINGSSL) || HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS
std::unordered_map<std::string, Metrics::Counter::AtomicType *> tls_group_map;
std::unordered_map<std::string, Metrics::Counter::AtomicType *> tls_group_handshake_time_map;
#elif defined(SSL_get_negotiated_group)
#elif HAVE_SSL_GET_NEGOTIATED_GROUP
std::unordered_map<int, Metrics::Counter::AtomicType *> tls_group_map;
std::unordered_map<int, Metrics::Counter::AtomicType *> tls_group_handshake_time_map;
#endif
Expand All @@ -50,7 +50,7 @@ DbgCtl dbg_ctl_ssl{"ssl"};
constexpr std::string_view UNKNOWN_CIPHER{"(NONE)"};
#endif

#if defined(OPENSSL_IS_BORINGSSL) || defined(SSL_get_negotiated_group)
#if defined(OPENSSL_IS_BORINGSSL) || HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS || HAVE_SSL_GET_NEGOTIATED_GROUP

template <typename T>
void
Expand All @@ -73,9 +73,10 @@ add_group_stat(T key, const std::string &name)
Dbg(dbg_ctl_ssl, "registering SSL group handshake time metric '%s.handshake_time'", name.c_str());
}
}
#endif // OPENSSL_IS_BORINGSSL or SSL_get_negotiated_group
#endif // OPENSSL_IS_BORINGSSL or HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS or HAVE_SSL_GET_NEGOTIATED_GROUP

#if not defined(OPENSSL_IS_BORINGSSL) and defined(SSL_get_negotiated_group) // OPENSSL 3.x
#if not defined(OPENSSL_IS_BORINGSSL) and not HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS and \
HAVE_SSL_GET_NEGOTIATED_GROUP // OPENSSL 3.x without SSL_CTX_get0_implemented_groups

struct TLSGroup {
int nid;
Expand Down Expand Up @@ -115,7 +116,7 @@ const TLSGroup TLS_GROUPS[] = {
#endif
};

#endif // OPENSSL 3.x
#endif // OPENSSL 3.x without SSL_CTX_get0_implemented_groups

} // end anonymous namespace

Expand Down Expand Up @@ -294,16 +295,18 @@ SSLInitializeStatistics()
add_cipher_stat(cipher_name, stat_name);
}
#else
// Get and register the SSL cipher stats. Note that we are using the default SSL context to obtain
// the cipher list. This means that the set of ciphers is fixed by the build configuration and not
// filtered by proxy.config.ssl.server.cipher_suite. This keeps the set of cipher suites stable across
// configuration reloads and works for the case where we honor the client cipher preference.
SSLMultiCertConfigLoader loader(nullptr);
SSL_CTX *ctx = loader.default_server_ssl_ctx();
SSL *ssl = SSL_new(ctx);
// Acquire the loaded SSL certificate configuration to enumerate ciphers and groups.
// This must be called AFTER SSLCertificateConfig::startup().
SSLCertificateConfig::scoped_config lookup;
if (!lookup || !lookup->ssl_default) {
Dbg(dbg_ctl_ssl, "No SSL configuration, skipping cipher/group statistics initialization");
return;
}

SSL_CTX *ctx = lookup->ssl_default.get();
SSL *ssl = SSL_new(ctx);
STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);

// BoringSSL has sk_SSL_CIPHER_num() return a size_t (well, sk_num() is)
for (int index = 0; index < static_cast<int>(sk_SSL_CIPHER_num(ciphers)); index++) {
SSL_CIPHER *cipher = const_cast<SSL_CIPHER *>(sk_SSL_CIPHER_value(ciphers, index));
const char *cipherName = SSL_CIPHER_get_name(cipher);
Expand All @@ -312,14 +315,48 @@ SSLInitializeStatistics()
add_cipher_stat(cipherName, statName);
}

// TLS Group
#if HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS
STACK_OF(OPENSSL_CSTRING) *group_names = sk_OPENSSL_CSTRING_new_null();
if (group_names == nullptr) {
Error("Failed to allocate stack for TLS group names");
} else {
constexpr int ALL_GROUPS = 1;
Dbg(dbg_ctl_ssl, "Calling SSL_CTX_get0_implemented_groups on loaded SSL context");
if (SSL_CTX_get0_implemented_groups(ctx, ALL_GROUPS, group_names) != 1) {
Error("Failed to get implemented groups via SSL_CTX_get0_implemented_groups");
}
int const num_groups = sk_OPENSSL_CSTRING_num(group_names);
Dbg(dbg_ctl_ssl, "SSL_CTX_get0_implemented_groups returned %d groups", num_groups);

for (int index = 0; index < num_groups; index++) {
const char *name = sk_OPENSSL_CSTRING_value(group_names, index);
if (name == nullptr) {
Error("NULL group name returned for index %d in SSL_CTX_get0_implemented_groups", index);
continue;
}
add_group_stat<std::string>(name, name);
}

// Note: We don't free group_names as the strings are owned by OpenSSL's internal structures.
sk_OPENSSL_CSTRING_free(group_names);
}

// Add "OTHER" for groups not discovered.
add_group_stat<std::string>("OTHER", "OTHER");
#elif HAVE_SSL_GET_NEGOTIATED_GROUP
// Use static NID table for group registration.
for (auto group : TLS_GROUPS) {
add_group_stat<int>(group.nid, group.name);
}
#endif // HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS or HAVE_SSL_GET_NEGOTIATED_GROUP

SSL_free(ssl);
SSLReleaseContext(ctx);
#endif

// 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<const char *> group_list(list_size);
Expand All @@ -328,9 +365,5 @@ SSLInitializeStatistics()
for (const char *name : group_list) {
add_group_stat<std::string>(name, name);
}
#elif defined(SSL_get_negotiated_group)
for (auto group : TLS_GROUPS) {
add_group_stat<int>(group.nid, group.name);
}
#endif // OPENSSL_IS_BORINGSSL or SSL_get_negotiated_group
#endif // OPENSSL_IS_BORINGSSL
}
6 changes: 4 additions & 2 deletions src/iocore/net/SSLStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#pragma once

#include "tscore/ink_config.h"
#include "tsutil/Metrics.h"

#include <openssl/ssl.h>
Expand Down Expand Up @@ -114,16 +115,17 @@ struct SSLStatsBlock {
extern SSLStatsBlock ssl_rsb;
extern std::unordered_map<std::string, Metrics::Counter::AtomicType *> cipher_map;

#if defined(OPENSSL_IS_BORINGSSL)
#if defined(OPENSSL_IS_BORINGSSL) || HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS
extern std::unordered_map<std::string, Metrics::Counter::AtomicType *> tls_group_map;
extern std::unordered_map<std::string, Metrics::Counter::AtomicType *> tls_group_handshake_time_map;
#elif defined(SSL_get_negotiated_group)
#elif HAVE_SSL_GET_NEGOTIATED_GROUP
extern std::unordered_map<int, Metrics::Counter::AtomicType *> tls_group_map;
extern std::unordered_map<int, Metrics::Counter::AtomicType *> tls_group_handshake_time_map;
constexpr int SSL_GROUP_STAT_OTHER_KEY = 0;
#endif

// Initialize SSL statistics.
// Must be called AFTER SSLCertificateConfig::startup() so SSL contexts are loaded.
void SSLInitializeStatistics();

const std::string SSL_CIPHER_STAT_OTHER = "OTHER";
35 changes: 32 additions & 3 deletions src/iocore/net/TLSBasicSupport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
limitations under the License.
*/

#include "P_SSLUtils.h"
#include "SSLStats.h"
#include "iocore/net/TLSBasicSupport.h"
#if defined(OPENSSL_IS_BORINGSSL)
Expand Down Expand Up @@ -249,7 +250,21 @@ TLSBasicSupport::_record_tls_handshake_end_time()
Metrics::Counter::increment(it->second, ssl_handshake_time);
}
}
#elif defined(SSL_get_negotiated_group)
#elif HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS
SSL *ssl = this->_get_ssl_object();
std::string_view group_name = SSLGetGroupName(ssl);
if (!group_name.empty()) {
std::string group_str(group_name);
if (auto it = tls_group_handshake_time_map.find(group_str); it != tls_group_handshake_time_map.end()) {
Metrics::Counter::increment(it->second, ssl_handshake_time);
} else {
auto other = tls_group_handshake_time_map.find("OTHER");
if (other != tls_group_handshake_time_map.end()) {
Metrics::Counter::increment(other->second, ssl_handshake_time);
}
}
}
#elif HAVE_SSL_GET_NEGOTIATED_GROUP
SSL *ssl = this->_get_ssl_object();
int nid = SSL_get_negotiated_group(const_cast<SSL *>(ssl));
if (nid != NID_undef) {
Expand Down Expand Up @@ -281,7 +296,21 @@ TLSBasicSupport::_update_end_of_handshake_stats()
Warning("Unknown TLS Group");
}
}
#elif defined(SSL_get_negotiated_group)
#elif HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS
SSL *ssl = this->_get_ssl_object();
std::string_view group_name = SSLGetGroupName(ssl);
if (!group_name.empty()) {
std::string group_str(group_name);
if (auto it = tls_group_map.find(group_str); it != tls_group_map.end()) {
Metrics::Counter::increment(it->second);
} else {
auto other = tls_group_map.find("OTHER");
if (other != tls_group_map.end()) {
Metrics::Counter::increment(other->second);
}
}
}
#elif HAVE_SSL_GET_NEGOTIATED_GROUP
SSL *ssl = this->_get_ssl_object();
int nid = SSL_get_negotiated_group(const_cast<SSL *>(ssl));
if (nid != NID_undef) {
Expand All @@ -292,5 +321,5 @@ TLSBasicSupport::_update_end_of_handshake_stats()
Metrics::Counter::increment(other->second);
}
}
#endif // OPENSSL_IS_BORINGSSL or SSL_get_negotiated_group
#endif // OPENSSL_IS_BORINGSSL or HAVE_SSL_CTX_GET0_IMPLEMENTED_GROUPS or HAVE_SSL_GET_NEGOTIATED_GROUP
}