Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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;
DbgPrint(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);
DbgPrint(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
}