This is an automated email from the ASF dual-hosted git repository. masaori pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new c811aea Cleanup: Separate SSLStats and SSLDiags from SSLUtils c811aea is described below commit c811aea9e0484433fbdd63e0fa6b9fbab87085eb Author: Masaori Koshiba <masa...@apache.org> AuthorDate: Thu Feb 21 15:43:58 2019 +0900 Cleanup: Separate SSLStats and SSLDiags from SSLUtils --- iocore/net/Makefile.am | 2 + iocore/net/OCSPStapling.cc | 1 + iocore/net/P_SSLUtils.h | 104 ---------- iocore/net/SSLClientUtils.cc | 2 + iocore/net/SSLConfig.cc | 16 +- iocore/net/SSLDiags.cc | 224 +++++++++++++++++++++ iocore/net/SSLDiags.h | 43 ++++ iocore/net/SSLNetProcessor.cc | 1 + iocore/net/SSLNetVConnection.cc | 16 +- iocore/net/SSLSessionCache.cc | 2 + iocore/net/SSLStats.cc | 239 +++++++++++++++++++++++ iocore/net/SSLStats.h | 115 +++++++++++ iocore/net/SSLUtils.cc | 420 ++-------------------------------------- 13 files changed, 660 insertions(+), 525 deletions(-) diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index 9eb9396..0971d5f 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -136,6 +136,7 @@ libinknet_a_SOURCES = \ SSLCertLookup.cc \ SSLSessionCache.cc \ SSLConfig.cc \ + SSLDiags.cc \ SSLInternal.cc \ SSLNetAccept.cc \ SSLNetProcessor.cc \ @@ -143,6 +144,7 @@ libinknet_a_SOURCES = \ SSLNextProtocolAccept.cc \ SSLNextProtocolSet.cc \ SSLSNIConfig.cc \ + SSLStats.cc \ SSLUtils.cc \ SSLClientUtils.cc \ OCSPStapling.cc \ diff --git a/iocore/net/OCSPStapling.cc b/iocore/net/OCSPStapling.cc index b4fcd77..26316ce 100644 --- a/iocore/net/OCSPStapling.cc +++ b/iocore/net/OCSPStapling.cc @@ -27,6 +27,7 @@ #include "P_Net.h" #include "P_SSLConfig.h" #include "P_SSLUtils.h" +#include "SSLStats.h" // Maxiumum OCSP stapling response size. // This should be the response for a single certificate and will typically include the responder certificate chain, diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h index e70dbc5..a61d8bc 100644 --- a/iocore/net/P_SSLUtils.h +++ b/iocore/net/P_SSLUtils.h @@ -33,92 +33,12 @@ #endif #include <openssl/ssl.h> -#include <unordered_map> - struct SSLConfigParams; struct SSLCertLookup; class SSLNetVConnection; -struct RecRawStatBlock; typedef int ssl_error_t; -enum SSL_Stats { - ssl_origin_server_expired_cert_stat, - ssl_user_agent_expired_cert_stat, - ssl_origin_server_revoked_cert_stat, - ssl_user_agent_revoked_cert_stat, - ssl_origin_server_unknown_cert_stat, - ssl_user_agent_unknown_cert_stat, - ssl_origin_server_cert_verify_failed_stat, - ssl_user_agent_cert_verify_failed_stat, - ssl_origin_server_bad_cert_stat, - ssl_user_agent_bad_cert_stat, - ssl_origin_server_decryption_failed_stat, - ssl_user_agent_decryption_failed_stat, - ssl_origin_server_wrong_version_stat, - ssl_user_agent_wrong_version_stat, - ssl_origin_server_other_errors_stat, - ssl_user_agent_other_errors_stat, - ssl_origin_server_unknown_ca_stat, - ssl_user_agent_unknown_ca_stat, - ssl_user_agent_sessions_stat, - ssl_user_agent_session_hit_stat, - ssl_user_agent_session_miss_stat, - ssl_user_agent_session_timeout_stat, - ssl_total_handshake_time_stat, - ssl_total_success_handshake_count_in_stat, - ssl_total_tickets_created_stat, - ssl_total_tickets_verified_stat, - ssl_total_tickets_verified_old_key_stat, // verified with old key. - ssl_total_ticket_keys_renewed_stat, // number of keys renewed. - ssl_total_tickets_not_found_stat, - ssl_total_tickets_renewed_stat, - ssl_total_dyn_def_tls_record_count, - ssl_total_dyn_max_tls_record_count, - ssl_total_dyn_redo_tls_record_count, - ssl_session_cache_hit, - ssl_session_cache_miss, - ssl_session_cache_eviction, - ssl_session_cache_lock_contention, - ssl_session_cache_new_session, - - /* error stats */ - ssl_error_want_write, - ssl_error_want_read, - ssl_error_want_client_hello_cb, - ssl_error_want_x509_lookup, - ssl_error_syscall, - ssl_error_read_eos, - ssl_error_zero_return, - ssl_error_ssl, - ssl_sni_name_set_failure, - ssl_total_success_handshake_count_out_stat, - - /* ocsp stapling stats */ - ssl_ocsp_revoked_cert_stat, - ssl_ocsp_unknown_cert_stat, - ssl_ocsp_refreshed_cert_stat, - ssl_ocsp_refresh_cert_failure_stat, - - ssl_cipher_stats_start = 100, - ssl_cipher_stats_end = 300, - - Ssl_Stat_Count -}; - -extern RecRawStatBlock *ssl_rsb; - -/* Stats should only be accessed using these macros */ -#define SSL_INCREMENT_DYN_STAT(x) RecIncrRawStat(ssl_rsb, nullptr, (int)x, 1) -#define SSL_DECREMENT_DYN_STAT(x) RecIncrRawStat(ssl_rsb, nullptr, (int)x, -1) -#define SSL_SET_COUNT_DYN_STAT(x, count) RecSetRawStatCount(ssl_rsb, x, count) -#define SSL_INCREMENT_DYN_STAT_EX(x, y) RecIncrRawStat(ssl_rsb, nullptr, (int)x, y) -#define SSL_CLEAR_DYN_STAT(x) \ - do { \ - RecSetRawStatSum(ssl_rsb, (x), 0); \ - RecSetRawStatCount(ssl_rsb, (x), 0); \ - } while (0) - // Create a default SSL server context. SSL_CTX *SSLDefaultServerContext(); @@ -131,9 +51,6 @@ void SSLInitializeLibrary(); // Initialize SSL library based on configuration settings void SSLPostConfigInitialize(); -// Initialize SSL statistics. -void SSLInitializeStatistics(); - // Release SSL_CTX and the associated data. This works for both // client and server contexts and gracefully accepts nullptr. void SSLReleaseContext(SSL_CTX *ctx); @@ -144,27 +61,6 @@ ssl_error_t SSLReadBuffer(SSL *ssl, void *buf, int64_t nbytes, int64_t &nread); ssl_error_t SSLAccept(SSL *ssl); ssl_error_t SSLConnect(SSL *ssl); -// Log an SSL error. -#define SSLError(fmt, ...) SSLDiagnostic(MakeSourceLocation(), false, nullptr, fmt, ##__VA_ARGS__) -#define SSLErrorVC(vc, fmt, ...) SSLDiagnostic(MakeSourceLocation(), false, (vc), fmt, ##__VA_ARGS__) -// Log a SSL diagnostic using the "ssl" diagnostic tag. -#define SSLDebug(fmt, ...) SSLDiagnostic(MakeSourceLocation(), true, nullptr, fmt, ##__VA_ARGS__) -#define SSLVCDebug(vc, fmt, ...) SSLDiagnostic(MakeSourceLocation(), true, (vc), fmt, ##__VA_ARGS__) - -#define SSL_CLR_ERR_INCR_DYN_STAT(vc, x, fmt, ...) \ - do { \ - SSLVCDebug((vc), fmt, ##__VA_ARGS__); \ - RecIncrRawStat(ssl_rsb, nullptr, (int)x, 1); \ - } while (0) - -void SSLDiagnostic(const SourceLocation &loc, bool debug, SSLNetVConnection *vc, const char *fmt, ...) TS_PRINTFLIKE(4, 5); - -// Return a static string name for a SSL_ERROR constant. -const char *SSLErrorName(int ssl_error); - -// Log a SSL network buffer. -void SSLDebugBufferPrint(const char *tag, const char *buffer, unsigned buflen, const char *message); - // Load the SSL certificate configuration. bool SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *lookup); diff --git a/iocore/net/SSLClientUtils.cc b/iocore/net/SSLClientUtils.cc index 89842f5..dd67e88 100644 --- a/iocore/net/SSLClientUtils.cc +++ b/iocore/net/SSLClientUtils.cc @@ -23,9 +23,11 @@ #include "records/I_RecHttp.h" #include "tscore/ink_platform.h" #include "tscore/X509HostnameValidator.h" + #include "P_Net.h" #include "P_SSLClientUtils.h" #include "YamlSNIConfig.h" +#include "SSLDiags.h" #include <openssl/err.h> #include <openssl/pem.h> diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc index 2d67244..1fd1955 100644 --- a/iocore/net/SSLConfig.cc +++ b/iocore/net/SSLConfig.cc @@ -29,19 +29,23 @@ SSL Configurations ****************************************************************************/ -#include "tscore/ink_platform.h" -#include "tscore/I_Layout.h" +#include "P_SSLConfig.h" #include <cstring> #include <cmath> + +#include "tscore/ink_platform.h" +#include "tscore/I_Layout.h" +#include "records/I_RecHttp.h" + +#include "HttpConfig.h" + #include "P_Net.h" -#include "P_SSLConfig.h" -#include "YamlSNIConfig.h" #include "P_SSLUtils.h" #include "P_SSLCertLookup.h" #include "SSLSessionCache.h" -#include <records/I_RecHttp.h> -#include <HttpConfig.h> +#include "SSLDiags.h" +#include "YamlSNIConfig.h" int SSLConfig::configid = 0; int SSLCertificateConfig::configid = 0; diff --git a/iocore/net/SSLDiags.cc b/iocore/net/SSLDiags.cc new file mode 100644 index 0000000..549a4d3 --- /dev/null +++ b/iocore/net/SSLDiags.cc @@ -0,0 +1,224 @@ +/** @file + + Diags for TLS + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "SSLDiags.h" + +#include <openssl/err.h> + +#include "P_Net.h" +#include "SSLStats.h" + +// return true if we have a stat for the error +static bool +increment_ssl_client_error(unsigned long err) +{ + // we only look for LIB_SSL errors atm + if (ERR_LIB_SSL != ERR_GET_LIB(err)) { + SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat); + return false; + } + + // error was in LIB_SSL, now just switch on REASON + // (we ignore FUNCTION with the prejudice that we don't care what function + // the error came from, hope that's ok?) + switch (ERR_GET_REASON(err)) { +#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED + case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_expired_cert_stat); + break; +#endif +#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED + case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_revoked_cert_stat); + break; +#endif +#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN + case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_cert_stat); + break; +#endif + case SSL_R_CERTIFICATE_VERIFY_FAILED: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_cert_verify_failed_stat); + break; +#ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE + case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_bad_cert_stat); + break; +#endif +#ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED + case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_decryption_failed_stat); + break; +#endif + case SSL_R_WRONG_VERSION_NUMBER: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_wrong_version_stat); + break; +#ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA + case SSL_R_TLSV1_ALERT_UNKNOWN_CA: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_ca_stat); + break; +#endif + default: + SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat); + return false; + } + + return true; +} + +// return true if we have a stat for the error + +static bool +increment_ssl_server_error(unsigned long err) +{ + // we only look for LIB_SSL errors atm + if (ERR_LIB_SSL != ERR_GET_LIB(err)) { + SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat); + return false; + } + + // error was in LIB_SSL, now just switch on REASON + // (we ignore FUNCTION with the prejudice that we don't care what function + // the error came from, hope that's ok?) + switch (ERR_GET_REASON(err)) { +#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED + case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_expired_cert_stat); + break; +#endif +#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED + case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_revoked_cert_stat); + break; +#endif +#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN + case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_cert_stat); + break; +#endif + case SSL_R_CERTIFICATE_VERIFY_FAILED: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_cert_verify_failed_stat); + break; +#ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE + case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_bad_cert_stat); + break; +#endif +#ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED + case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_decryption_failed_stat); + break; +#endif + case SSL_R_WRONG_VERSION_NUMBER: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_wrong_version_stat); + break; +#ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA + case SSL_R_TLSV1_ALERT_UNKNOWN_CA: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_ca_stat); + break; +#endif + default: + SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat); + return false; + } + + return true; +} + +void +SSLDiagnostic(const SourceLocation &loc, bool debug, SSLNetVConnection *vc, const char *fmt, ...) +{ + unsigned long l; + char buf[256]; + const char *file, *data; + int line, flags; + unsigned long es; + va_list ap; + ip_text_buffer ip_buf = {'\0'}; + + if (vc) { + ats_ip_ntop(vc->get_remote_addr(), ip_buf, sizeof(ip_buf)); + } + + es = (unsigned long)pthread_self(); + while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) { + if (debug) { + if (unlikely(diags->on())) { + diags->log("ssl-diag", DL_Debug, &loc, "SSL::%lu:%s:%s:%d%s%s%s%s", es, ERR_error_string(l, buf), file, line, + (flags & ERR_TXT_STRING) ? ":" : "", (flags & ERR_TXT_STRING) ? data : "", vc ? ": peer address is " : "", + ip_buf); + } + } else { + diags->error(DL_Error, &loc, "SSL::%lu:%s:%s:%d%s%s%s%s", es, ERR_error_string(l, buf), file, line, + (flags & ERR_TXT_STRING) ? ":" : "", (flags & ERR_TXT_STRING) ? data : "", vc ? ": peer address is " : "", + ip_buf); + } + + // Tally desired stats (only client/server connection stats, not init + // issues where vc is nullptr) + if (vc) { + // get_context() == NET_VCONNECTION_OUT if ats is client (we update server stats) + if (vc->get_context() == NET_VCONNECTION_OUT) { + increment_ssl_server_error(l); // update server error stats + } else { + increment_ssl_client_error(l); // update client error stat + } + } + } + + va_start(ap, fmt); + if (debug) { + diags->log_va("ssl-diag", DL_Debug, &loc, fmt, ap); + } else { + diags->error_va(DL_Error, &loc, fmt, ap); + } + va_end(ap); +} + +const char * +SSLErrorName(int ssl_error) +{ + static const char *names[] = { + "SSL_ERROR_NONE", "SSL_ERROR_SSL", "SSL_ERROR_WANT_READ", "SSL_ERROR_WANT_WRITE", "SSL_ERROR_WANT_X509_LOOKUP", + "SSL_ERROR_SYSCALL", "SSL_ERROR_ZERO_RETURN", "SSL_ERROR_WANT_CONNECT", "SSL_ERROR_WANT_ACCEPT"}; + + if (ssl_error < 0 || ssl_error >= (int)countof(names)) { + return "unknown SSL error"; + } + + return names[ssl_error]; +} + +void +SSLDebugBufferPrint(const char *tag, const char *buffer, unsigned buflen, const char *message) +{ + if (is_debug_tag_set(tag)) { + if (message != nullptr) { + fprintf(stdout, "%s\n", message); + } + for (unsigned ii = 0; ii < buflen; ii++) { + putc(buffer[ii], stdout); + } + putc('\n', stdout); + } +} diff --git a/iocore/net/SSLDiags.h b/iocore/net/SSLDiags.h new file mode 100644 index 0000000..52ccd08 --- /dev/null +++ b/iocore/net/SSLDiags.h @@ -0,0 +1,43 @@ +/** @file + + Diags for TLS + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "tscore/Diags.h" + +class SSLNetVConnection; + +// Log an SSL error. +#define SSLError(fmt, ...) SSLDiagnostic(MakeSourceLocation(), false, nullptr, fmt, ##__VA_ARGS__) +#define SSLErrorVC(vc, fmt, ...) SSLDiagnostic(MakeSourceLocation(), false, (vc), fmt, ##__VA_ARGS__) +// Log a SSL diagnostic using the "ssl" diagnostic tag. +#define SSLDebug(fmt, ...) SSLDiagnostic(MakeSourceLocation(), true, nullptr, fmt, ##__VA_ARGS__) +#define SSLVCDebug(vc, fmt, ...) SSLDiagnostic(MakeSourceLocation(), true, (vc), fmt, ##__VA_ARGS__) + +void SSLDiagnostic(const SourceLocation &loc, bool debug, SSLNetVConnection *vc, const char *fmt, ...) TS_PRINTFLIKE(4, 5); + +// Return a static string name for a SSL_ERROR constant. +const char *SSLErrorName(int ssl_error); + +// Log a SSL network buffer. +void SSLDebugBufferPrint(const char *tag, const char *buffer, unsigned buflen, const char *message); diff --git a/iocore/net/SSLNetProcessor.cc b/iocore/net/SSLNetProcessor.cc index cff8992..90c7a4e 100644 --- a/iocore/net/SSLNetProcessor.cc +++ b/iocore/net/SSLNetProcessor.cc @@ -27,6 +27,7 @@ #include "P_SSLUtils.h" #include "P_OCSPStapling.h" #include "P_SSLSNI.h" +#include "SSLStats.h" // // Global Data diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc index 5d08d3d..2c55571 100644 --- a/iocore/net/SSLNetVConnection.cc +++ b/iocore/net/SSLNetVConnection.cc @@ -20,22 +20,26 @@ See the License for the specific language governing permissions and limitations under the License. */ + #include "tscore/ink_config.h" #include "tscore/EventNotify.h" #include "tscore/I_Layout.h" #include "records/I_RecHttp.h" + +#include "InkAPIInternal.h" // Added to include the ssl_hook definitions +#include "Log.h" +#include "HttpTunnel.h" +#include "ProxyProtocol.h" +#include "HttpConfig.h" + #include "P_Net.h" #include "P_SSLNextProtocolSet.h" #include "P_SSLUtils.h" -#include "InkAPIInternal.h" // Added to include the ssl_hook definitions #include "P_SSLConfig.h" -#include "BIO_fastopen.h" -#include "Log.h" #include "P_SSLClientUtils.h" #include "P_SSLSNI.h" -#include "HttpTunnel.h" -#include "ProxyProtocol.h" -#include <HttpConfig.h> +#include "BIO_fastopen.h" +#include "SSLStats.h" #include <climits> #include <string> diff --git a/iocore/net/SSLSessionCache.cc b/iocore/net/SSLSessionCache.cc index bbe52a9..1238b4b 100644 --- a/iocore/net/SSLSessionCache.cc +++ b/iocore/net/SSLSessionCache.cc @@ -21,6 +21,8 @@ #include "P_SSLConfig.h" #include "SSLSessionCache.h" +#include "SSLStats.h" + #include <cstring> #define SSLSESSIONCACHE_STRINGIFY0(x) #x diff --git a/iocore/net/SSLStats.cc b/iocore/net/SSLStats.cc new file mode 100644 index 0000000..c748b94 --- /dev/null +++ b/iocore/net/SSLStats.cc @@ -0,0 +1,239 @@ +/** @file + + Stats of TLS + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "SSLStats.h" + +#include <openssl/err.h> + +#include "P_SSLConfig.h" + +RecRawStatBlock *ssl_rsb = nullptr; +std::unordered_map<std::string, intptr_t> cipher_map; + +static int +SSLRecRawStatSyncCount(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) +{ + // Grab all the stats we want from OpenSSL and set the stats. This function only needs to be called by one of the + // involved stats, all others *must* call RecRawStatSyncSum. + SSLCertificateConfig::scoped_config certLookup; + + int64_t sessions = 0; + int64_t hits = 0; + int64_t misses = 0; + int64_t timeouts = 0; + + if (certLookup) { + const unsigned ctxCount = certLookup->count(); + for (size_t i = 0; i < ctxCount; i++) { + SSLCertContext *cc = certLookup->get(i); + if (cc && cc->ctx) { + sessions += SSL_CTX_sess_accept_good(cc->ctx); + hits += SSL_CTX_sess_hits(cc->ctx); + misses += SSL_CTX_sess_misses(cc->ctx); + timeouts += SSL_CTX_sess_timeouts(cc->ctx); + } + } + } + + SSL_SET_COUNT_DYN_STAT(ssl_user_agent_sessions_stat, sessions); + SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_hit_stat, hits); + SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_miss_stat, misses); + SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_timeout_stat, timeouts); + + return RecRawStatSyncCount(name, data_type, data, rsb, id); +} + +void +SSLInitializeStatistics() +{ + SSL_CTX *ctx; + SSL *ssl; + STACK_OF(SSL_CIPHER) * ciphers; + + // Allocate SSL statistics block. + ssl_rsb = RecAllocateRawStatBlock((int)Ssl_Stat_Count); + ink_assert(ssl_rsb != nullptr); + + // SSL client errors. + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_other_errors", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_other_errors_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_expired_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_expired_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_revoked_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_revoked_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_unknown_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_cert_verify_failed", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_cert_verify_failed_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_bad_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_bad_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_decryption_failed", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_decryption_failed_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_wrong_version", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_wrong_version_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_ca", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_user_agent_unknown_ca_stat, RecRawStatSyncSum); + + // Polled SSL context statistics. + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_sessions", RECD_COUNTER, RECP_NON_PERSISTENT, + (int)ssl_user_agent_sessions_stat, + SSLRecRawStatSyncCount); //<- only use this fn once + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_hit", RECD_COUNTER, RECP_NON_PERSISTENT, + (int)ssl_user_agent_session_hit_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_miss", RECD_COUNTER, RECP_NON_PERSISTENT, + (int)ssl_user_agent_session_miss_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_timeout", RECD_COUNTER, RECP_NON_PERSISTENT, + (int)ssl_user_agent_session_timeout_stat, RecRawStatSyncCount); + + // SSL server errors. + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_other_errors", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_other_errors_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_expired_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_expired_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_revoked_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_revoked_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_unknown_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_cert_verify_failed", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_cert_verify_failed_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_bad_cert", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_bad_cert_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_decryption_failed", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_decryption_failed_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_wrong_version", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_wrong_version_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_ca", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_origin_server_unknown_ca_stat, RecRawStatSyncSum); + + // SSL handshake time + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_handshake_time", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_handshake_time_stat, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_success_handshake_count_in", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_success_handshake_count_in_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_success_handshake_count_out", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_success_handshake_count_out_stat, RecRawStatSyncCount); + + // TLS tickets + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_created", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_tickets_created_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_verified", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_tickets_verified_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_not_found", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_tickets_not_found_stat, RecRawStatSyncCount); + // TODO: ticket renewal is not used right now. + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_renewed", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_tickets_renewed_stat, RecRawStatSyncCount); + // The number of session tickets verified with an "old" key. + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_verified_old_key", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_tickets_verified_old_key_stat, RecRawStatSyncCount); + // The number of ticket keys renewed. + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_ticket_keys_renewed", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_ticket_keys_renewed_stat, RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_hit", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_session_cache_hit, RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_new_session", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_session_cache_new_session, RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_miss", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_session_cache_miss, RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_eviction", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_session_cache_eviction, RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_lock_contention", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_session_cache_lock_contention, RecRawStatSyncCount); + + /* Track dynamic record size */ + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.default_record_size_count", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_dyn_def_tls_record_count, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.max_record_size_count", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_dyn_max_tls_record_count, RecRawStatSyncSum); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.redo_record_size_count", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_total_dyn_redo_tls_record_count, RecRawStatSyncCount); + + /* error stats */ + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_write", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_error_want_write, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_read", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_error_want_read, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_x509_lookup", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_error_want_x509_lookup, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_syscall", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_error_syscall, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_read_eos", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_error_read_eos, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_zero_return", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_error_zero_return, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_ssl", RECD_COUNTER, RECP_PERSISTENT, (int)ssl_error_ssl, + RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_sni_name_set_failure", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_sni_name_set_failure, RecRawStatSyncCount); + + /* ocsp stapling stats */ + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_revoked_cert_stat", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_ocsp_revoked_cert_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_unknown_cert_stat", RECD_COUNTER, RECP_PERSISTENT, + (int)ssl_ocsp_unknown_cert_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_refreshed_cert", RECD_INT, RECP_PERSISTENT, + (int)ssl_ocsp_refreshed_cert_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_refresh_cert_failure", RECD_INT, RECP_PERSISTENT, + (int)ssl_ocsp_refresh_cert_failure_stat, RecRawStatSyncCount); + + // 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. + + ctx = SSLDefaultServerContext(); + ssl = SSL_new(ctx); + 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); + std::string statName = "proxy.process.ssl.cipher.user_agent." + std::string(cipherName); + + // If room in allocated space ... + if ((ssl_cipher_stats_start + index) > ssl_cipher_stats_end) { + // Too many ciphers, increase ssl_cipher_stats_end. + SSLError("too many ciphers to register metric '%s', increase SSL_Stats::ssl_cipher_stats_end", statName.c_str()); + continue; + } + + // If not already registered ... + if (cipherName && cipher_map.find(cipherName) == cipher_map.end()) { + cipher_map.emplace(cipherName, (intptr_t)(ssl_cipher_stats_start + index)); + // Register as non-persistent since the order/index is dependent upon configuration. + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, statName.c_str(), RECD_INT, RECP_NON_PERSISTENT, + (int)ssl_cipher_stats_start + index, RecRawStatSyncSum); + SSL_CLEAR_DYN_STAT((int)ssl_cipher_stats_start + index); + Debug("ssl", "registering SSL cipher metric '%s'", statName.c_str()); + } + } + + SSL_free(ssl); + SSLReleaseContext(ctx); +} diff --git a/iocore/net/SSLStats.h b/iocore/net/SSLStats.h new file mode 100644 index 0000000..ff38df0 --- /dev/null +++ b/iocore/net/SSLStats.h @@ -0,0 +1,115 @@ +/** @file + + Stats of TLS + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include <unordered_map> + +#include "records/I_RecProcess.h" +#include "SSLDiags.h" + +/* Stats should only be accessed using these macros */ +#define SSL_INCREMENT_DYN_STAT(x) RecIncrRawStat(ssl_rsb, nullptr, (int)x, 1) +#define SSL_DECREMENT_DYN_STAT(x) RecIncrRawStat(ssl_rsb, nullptr, (int)x, -1) +#define SSL_SET_COUNT_DYN_STAT(x, count) RecSetRawStatCount(ssl_rsb, x, count) +#define SSL_INCREMENT_DYN_STAT_EX(x, y) RecIncrRawStat(ssl_rsb, nullptr, (int)x, y) +#define SSL_CLEAR_DYN_STAT(x) \ + do { \ + RecSetRawStatSum(ssl_rsb, (x), 0); \ + RecSetRawStatCount(ssl_rsb, (x), 0); \ + } while (0) +#define SSL_CLR_ERR_INCR_DYN_STAT(vc, x, fmt, ...) \ + do { \ + SSLVCDebug((vc), fmt, ##__VA_ARGS__); \ + RecIncrRawStat(ssl_rsb, nullptr, (int)x, 1); \ + } while (0) + +enum SSL_Stats { + ssl_origin_server_expired_cert_stat, + ssl_user_agent_expired_cert_stat, + ssl_origin_server_revoked_cert_stat, + ssl_user_agent_revoked_cert_stat, + ssl_origin_server_unknown_cert_stat, + ssl_user_agent_unknown_cert_stat, + ssl_origin_server_cert_verify_failed_stat, + ssl_user_agent_cert_verify_failed_stat, + ssl_origin_server_bad_cert_stat, + ssl_user_agent_bad_cert_stat, + ssl_origin_server_decryption_failed_stat, + ssl_user_agent_decryption_failed_stat, + ssl_origin_server_wrong_version_stat, + ssl_user_agent_wrong_version_stat, + ssl_origin_server_other_errors_stat, + ssl_user_agent_other_errors_stat, + ssl_origin_server_unknown_ca_stat, + ssl_user_agent_unknown_ca_stat, + ssl_user_agent_sessions_stat, + ssl_user_agent_session_hit_stat, + ssl_user_agent_session_miss_stat, + ssl_user_agent_session_timeout_stat, + ssl_total_handshake_time_stat, + ssl_total_success_handshake_count_in_stat, + ssl_total_tickets_created_stat, + ssl_total_tickets_verified_stat, + ssl_total_tickets_verified_old_key_stat, // verified with old key. + ssl_total_ticket_keys_renewed_stat, // number of keys renewed. + ssl_total_tickets_not_found_stat, + ssl_total_tickets_renewed_stat, + ssl_total_dyn_def_tls_record_count, + ssl_total_dyn_max_tls_record_count, + ssl_total_dyn_redo_tls_record_count, + ssl_session_cache_hit, + ssl_session_cache_miss, + ssl_session_cache_eviction, + ssl_session_cache_lock_contention, + ssl_session_cache_new_session, + + /* error stats */ + ssl_error_want_write, + ssl_error_want_read, + ssl_error_want_client_hello_cb, + ssl_error_want_x509_lookup, + ssl_error_syscall, + ssl_error_read_eos, + ssl_error_zero_return, + ssl_error_ssl, + ssl_sni_name_set_failure, + ssl_total_success_handshake_count_out_stat, + + /* ocsp stapling stats */ + ssl_ocsp_revoked_cert_stat, + ssl_ocsp_unknown_cert_stat, + ssl_ocsp_refreshed_cert_stat, + ssl_ocsp_refresh_cert_failure_stat, + + ssl_cipher_stats_start = 100, + ssl_cipher_stats_end = 300, + + Ssl_Stat_Count +}; + +extern RecRawStatBlock *ssl_rsb; +extern std::unordered_map<std::string, intptr_t> cipher_map; + +// Initialize SSL statistics. +void SSLInitializeStatistics(); diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index 111ec1b..ad20188 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -19,18 +19,25 @@ limitations under the License. */ +#include "P_SSLUtils.h" + #include "tscore/ink_platform.h" #include "tscore/SimpleTokenizer.h" -#include "records/I_RecHttp.h" #include "tscore/I_Layout.h" -#include "P_Net.h" #include "tscore/ink_cap.h" #include "tscore/ink_mutex.h" +#include "records/I_RecHttp.h" + +#include "P_Net.h" +#include "InkAPIInternal.h" + #include "P_OCSPStapling.h" +#include "P_SSLSNI.h" +#include "P_SSLConfig.h" #include "SSLSessionCache.h" -#include "InkAPIInternal.h" #include "SSLDynlock.h" -#include "P_SSLSNI.h" +#include "SSLDiags.h" +#include "SSLStats.h" #include <string> #include <openssl/err.h> @@ -138,9 +145,6 @@ static int ssl_vc_index = -1; static ink_mutex *mutex_buf = nullptr; static bool open_ssl_initialized = false; -RecRawStatBlock *ssl_rsb = nullptr; -std::unordered_map<std::string, intptr_t> cipher_map; - /* Using pthread thread ID and mutex functions directly, instead of * ATS this_ethread / ProxyMutex, so that other linked libraries * may use pthreads and openssl without confusing us here. (TS-2271). @@ -904,38 +908,6 @@ ssl_private_key_validate_exec(const char *cmdLine) return bReturn; } -static int -SSLRecRawStatSyncCount(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) -{ - // Grab all the stats we want from OpenSSL and set the stats. This function only needs to be called by one of the - // involved stats, all others *must* call RecRawStatSyncSum. - SSLCertificateConfig::scoped_config certLookup; - - int64_t sessions = 0; - int64_t hits = 0; - int64_t misses = 0; - int64_t timeouts = 0; - - if (certLookup) { - const unsigned ctxCount = certLookup->count(); - for (size_t i = 0; i < ctxCount; i++) { - SSLCertContext *cc = certLookup->get(i); - if (cc && cc->ctx) { - sessions += SSL_CTX_sess_accept_good(cc->ctx); - hits += SSL_CTX_sess_hits(cc->ctx); - misses += SSL_CTX_sess_misses(cc->ctx); - timeouts += SSL_CTX_sess_timeouts(cc->ctx); - } - } - } - - SSL_SET_COUNT_DYN_STAT(ssl_user_agent_sessions_stat, sessions); - SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_hit_stat, hits); - SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_miss_stat, misses); - SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_timeout_stat, timeouts); - return RecRawStatSyncCount(name, data_type, data, rsb, id); -} - #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) #define ssl_malloc(size, file, line) ssl_malloc(size) #define ssl_realloc(ptr, size, file, line) ssl_realloc(ptr, size) @@ -1058,376 +1030,6 @@ SSLInitializeLibrary() open_ssl_initialized = true; } -void -SSLInitializeStatistics() -{ - SSL_CTX *ctx; - SSL *ssl; - STACK_OF(SSL_CIPHER) * ciphers; - - // Allocate SSL statistics block. - ssl_rsb = RecAllocateRawStatBlock((int)Ssl_Stat_Count); - ink_assert(ssl_rsb != nullptr); - - // SSL client errors. - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_other_errors", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_other_errors_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_expired_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_expired_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_revoked_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_revoked_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_unknown_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_cert_verify_failed", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_cert_verify_failed_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_bad_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_bad_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_decryption_failed", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_decryption_failed_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_wrong_version", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_wrong_version_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_ca", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_user_agent_unknown_ca_stat, RecRawStatSyncSum); - - // Polled SSL context statistics. - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_sessions", RECD_COUNTER, RECP_NON_PERSISTENT, - (int)ssl_user_agent_sessions_stat, - SSLRecRawStatSyncCount); //<- only use this fn once - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_hit", RECD_COUNTER, RECP_NON_PERSISTENT, - (int)ssl_user_agent_session_hit_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_miss", RECD_COUNTER, RECP_NON_PERSISTENT, - (int)ssl_user_agent_session_miss_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_timeout", RECD_COUNTER, RECP_NON_PERSISTENT, - (int)ssl_user_agent_session_timeout_stat, RecRawStatSyncCount); - - // SSL server errors. - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_other_errors", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_other_errors_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_expired_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_expired_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_revoked_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_revoked_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_unknown_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_cert_verify_failed", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_cert_verify_failed_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_bad_cert", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_bad_cert_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_decryption_failed", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_decryption_failed_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_wrong_version", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_wrong_version_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_ca", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_origin_server_unknown_ca_stat, RecRawStatSyncSum); - - // SSL handshake time - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_handshake_time", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_handshake_time_stat, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_success_handshake_count_in", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_success_handshake_count_in_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_success_handshake_count_out", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_success_handshake_count_out_stat, RecRawStatSyncCount); - - // TLS tickets - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_created", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_tickets_created_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_verified", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_tickets_verified_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_not_found", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_tickets_not_found_stat, RecRawStatSyncCount); - // TODO: ticket renewal is not used right now. - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_renewed", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_tickets_renewed_stat, RecRawStatSyncCount); - // The number of session tickets verified with an "old" key. - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_verified_old_key", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_tickets_verified_old_key_stat, RecRawStatSyncCount); - // The number of ticket keys renewed. - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_ticket_keys_renewed", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_ticket_keys_renewed_stat, RecRawStatSyncCount); - - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_hit", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_session_cache_hit, RecRawStatSyncCount); - - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_new_session", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_session_cache_new_session, RecRawStatSyncCount); - - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_miss", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_session_cache_miss, RecRawStatSyncCount); - - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_eviction", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_session_cache_eviction, RecRawStatSyncCount); - - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_lock_contention", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_session_cache_lock_contention, RecRawStatSyncCount); - - /* Track dynamic record size */ - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.default_record_size_count", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_dyn_def_tls_record_count, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.max_record_size_count", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_dyn_max_tls_record_count, RecRawStatSyncSum); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.redo_record_size_count", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_total_dyn_redo_tls_record_count, RecRawStatSyncCount); - - /* error stats */ - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_write", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_error_want_write, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_read", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_error_want_read, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_x509_lookup", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_error_want_x509_lookup, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_syscall", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_error_syscall, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_read_eos", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_error_read_eos, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_zero_return", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_error_zero_return, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_ssl", RECD_COUNTER, RECP_PERSISTENT, (int)ssl_error_ssl, - RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_sni_name_set_failure", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_sni_name_set_failure, RecRawStatSyncCount); - - /* ocsp stapling stats */ - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_revoked_cert_stat", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_ocsp_revoked_cert_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_unknown_cert_stat", RECD_COUNTER, RECP_PERSISTENT, - (int)ssl_ocsp_unknown_cert_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_refreshed_cert", RECD_INT, RECP_PERSISTENT, - (int)ssl_ocsp_refreshed_cert_stat, RecRawStatSyncCount); - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_ocsp_refresh_cert_failure", RECD_INT, RECP_PERSISTENT, - (int)ssl_ocsp_refresh_cert_failure_stat, RecRawStatSyncCount); - - // 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. - - ctx = SSLDefaultServerContext(); - ssl = SSL_new(ctx); - 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); - std::string statName = "proxy.process.ssl.cipher.user_agent." + std::string(cipherName); - - // If room in allocated space ... - if ((ssl_cipher_stats_start + index) > ssl_cipher_stats_end) { - // Too many ciphers, increase ssl_cipher_stats_end. - SSLError("too many ciphers to register metric '%s', increase SSL_Stats::ssl_cipher_stats_end", statName.c_str()); - continue; - } - - // If not already registered ... - if (cipherName && cipher_map.find(cipherName) == cipher_map.end()) { - cipher_map.emplace(cipherName, (intptr_t)(ssl_cipher_stats_start + index)); - // Register as non-persistent since the order/index is dependent upon configuration. - RecRegisterRawStat(ssl_rsb, RECT_PROCESS, statName.c_str(), RECD_INT, RECP_NON_PERSISTENT, - (int)ssl_cipher_stats_start + index, RecRawStatSyncSum); - SSL_CLEAR_DYN_STAT((int)ssl_cipher_stats_start + index); - Debug("ssl", "registering SSL cipher metric '%s'", statName.c_str()); - } - } - - SSL_free(ssl); - SSLReleaseContext(ctx); -} - -// return true if we have a stat for the error -static bool -increment_ssl_client_error(unsigned long err) -{ - // we only look for LIB_SSL errors atm - if (ERR_LIB_SSL != ERR_GET_LIB(err)) { - SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat); - return false; - } - - // error was in LIB_SSL, now just switch on REASON - // (we ignore FUNCTION with the prejudice that we don't care what function - // the error came from, hope that's ok?) - switch (ERR_GET_REASON(err)) { -#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED - case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_expired_cert_stat); - break; -#endif -#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED - case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_revoked_cert_stat); - break; -#endif -#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN - case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_cert_stat); - break; -#endif - case SSL_R_CERTIFICATE_VERIFY_FAILED: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_cert_verify_failed_stat); - break; -#ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE - case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_bad_cert_stat); - break; -#endif -#ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED - case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_decryption_failed_stat); - break; -#endif - case SSL_R_WRONG_VERSION_NUMBER: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_wrong_version_stat); - break; -#ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA - case SSL_R_TLSV1_ALERT_UNKNOWN_CA: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_ca_stat); - break; -#endif - default: - SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat); - return false; - } - - return true; -} - -// return true if we have a stat for the error - -static bool -increment_ssl_server_error(unsigned long err) -{ - // we only look for LIB_SSL errors atm - if (ERR_LIB_SSL != ERR_GET_LIB(err)) { - SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat); - return false; - } - - // error was in LIB_SSL, now just switch on REASON - // (we ignore FUNCTION with the prejudice that we don't care what function - // the error came from, hope that's ok?) - switch (ERR_GET_REASON(err)) { -#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED - case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_expired_cert_stat); - break; -#endif -#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED - case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_revoked_cert_stat); - break; -#endif -#ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN - case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_cert_stat); - break; -#endif - case SSL_R_CERTIFICATE_VERIFY_FAILED: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_cert_verify_failed_stat); - break; -#ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE - case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_bad_cert_stat); - break; -#endif -#ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED - case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_decryption_failed_stat); - break; -#endif - case SSL_R_WRONG_VERSION_NUMBER: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_wrong_version_stat); - break; -#ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA - case SSL_R_TLSV1_ALERT_UNKNOWN_CA: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_ca_stat); - break; -#endif - default: - SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat); - return false; - } - - return true; -} - -void -SSLDiagnostic(const SourceLocation &loc, bool debug, SSLNetVConnection *vc, const char *fmt, ...) -{ - unsigned long l; - char buf[256]; - const char *file, *data; - int line, flags; - unsigned long es; - va_list ap; - ip_text_buffer ip_buf = {'\0'}; - - if (vc) { - ats_ip_ntop(vc->get_remote_addr(), ip_buf, sizeof(ip_buf)); - } - - es = (unsigned long)pthread_self(); - while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) { - if (debug) { - if (unlikely(diags->on())) { - diags->log("ssl-diag", DL_Debug, &loc, "SSL::%lu:%s:%s:%d%s%s%s%s", es, ERR_error_string(l, buf), file, line, - (flags & ERR_TXT_STRING) ? ":" : "", (flags & ERR_TXT_STRING) ? data : "", vc ? ": peer address is " : "", - ip_buf); - } - } else { - diags->error(DL_Error, &loc, "SSL::%lu:%s:%s:%d%s%s%s%s", es, ERR_error_string(l, buf), file, line, - (flags & ERR_TXT_STRING) ? ":" : "", (flags & ERR_TXT_STRING) ? data : "", vc ? ": peer address is " : "", - ip_buf); - } - - // Tally desired stats (only client/server connection stats, not init - // issues where vc is nullptr) - if (vc) { - // get_context() == NET_VCONNECTION_OUT if ats is client (we update server stats) - if (vc->get_context() == NET_VCONNECTION_OUT) { - increment_ssl_server_error(l); // update server error stats - } else { - increment_ssl_client_error(l); // update client error stat - } - } - } - - va_start(ap, fmt); - if (debug) { - diags->log_va("ssl-diag", DL_Debug, &loc, fmt, ap); - } else { - diags->error_va(DL_Error, &loc, fmt, ap); - } - va_end(ap); -} - -const char * -SSLErrorName(int ssl_error) -{ - static const char *names[] = { - "SSL_ERROR_NONE", "SSL_ERROR_SSL", "SSL_ERROR_WANT_READ", "SSL_ERROR_WANT_WRITE", "SSL_ERROR_WANT_X509_LOOKUP", - "SSL_ERROR_SYSCALL", "SSL_ERROR_ZERO_RETURN", "SSL_ERROR_WANT_CONNECT", "SSL_ERROR_WANT_ACCEPT"}; - - if (ssl_error < 0 || ssl_error >= (int)countof(names)) { - return "unknown SSL error"; - } - - return names[ssl_error]; -} - -void -SSLDebugBufferPrint(const char *tag, const char *buffer, unsigned buflen, const char *message) -{ - if (is_debug_tag_set(tag)) { - if (message != nullptr) { - fprintf(stdout, "%s\n", message); - } - for (unsigned ii = 0; ii < buflen; ii++) { - putc(buffer[ii], stdout); - } - putc('\n', stdout); - } -} - SSL_CTX * SSLDefaultServerContext() {