diff --git a/src/h2load.cc b/src/h2load.cc index 06571047..3338f4da 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -269,27 +269,6 @@ void Client::report_progress() { } } -namespace { -const char *get_tls_protocol(SSL *ssl) { - auto session = SSL_get_session(ssl); - - switch (session->ssl_version) { - case SSL2_VERSION: - return "SSLv2"; - case SSL3_VERSION: - return "SSLv3"; - case TLS1_2_VERSION: - return "TLSv1.2"; - case TLS1_1_VERSION: - return "TLSv1.1"; - case TLS1_VERSION: - return "TLSv1"; - default: - return "unknown"; - } -} -} // namespace - namespace { void print_server_tmp_key(SSL *ssl) { // libressl does not have SSL_get_server_tmp_key @@ -333,7 +312,7 @@ void Client::report_tls_info() { if (worker->id == 0 && !worker->tls_info_report_done) { worker->tls_info_report_done = true; auto cipher = SSL_get_current_cipher(ssl); - std::cout << "Protocol: " << get_tls_protocol(ssl) << "\n" + std::cout << "Protocol: " << ssl::get_tls_protocol(ssl) << "\n" << "Cipher: " << SSL_CIPHER_get_name(cipher) << std::endl; print_server_tmp_key(ssl); } diff --git a/src/shrpx.cc b/src/shrpx.cc index 9610807c..e7e05455 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1345,6 +1345,9 @@ Logging: * $alpn: ALPN identifier of the protocol which generates the response. For HTTP/1, ALPN is always http/1.1, regardless of minor version. + * $ssl_cipher: cipher used for SSL/TLS connection. + * $ssl_protocol: protocol for SSL/TLS connection. + * $ssl_session_id: session ID for SSL/TLS connection. Default: )" << DEFAULT_ACCESSLOG_FORMAT << R"( --errorlog-file= diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index b360bd72..d727fe39 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -733,6 +733,8 @@ std::string construct_absolute_request_uri(Downstream *downstream) { } // namespace void ClientHandler::write_accesslog(Downstream *downstream) { + nghttp2::ssl::TLSSessionInfo tls_info; + upstream_accesslog( get_config()->accesslog_format, LogSpec{ @@ -747,6 +749,7 @@ void ClientHandler::write_accesslog(Downstream *downstream) { : downstream->get_request_path().c_str(), alpn_.c_str(), + nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl), std::chrono::system_clock::now(), // time_now downstream->get_request_start_time(), // request_start_time @@ -763,13 +766,16 @@ void ClientHandler::write_accesslog(int major, int minor, unsigned int status, int64_t body_bytes_sent) { auto time_now = std::chrono::system_clock::now(); auto highres_now = std::chrono::high_resolution_clock::now(); + nghttp2::ssl::TLSSessionInfo tls_info; upstream_accesslog(get_config()->accesslog_format, LogSpec{ nullptr, ipaddr_.c_str(), "-", // method "-", // path, - alpn_.c_str(), time_now, + alpn_.c_str(), nghttp2::ssl::get_tls_session_info( + &tls_info, conn_.tls.ssl), + time_now, highres_now, // request_start_time TODO is // there a better value? highres_now, // request_end_time diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 7de46e58..d3195d88 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -383,6 +383,12 @@ std::vector parse_log_format(const char *optarg) { type = SHRPX_LOGF_PID; } else if (util::strieq_l("$alpn", var_start, varlen)) { type = SHRPX_LOGF_ALPN; + } else if (util::strieq_l("$ssl_cipher", var_start, varlen)) { + type = SHRPX_LOGF_SSL_CIPHER; + } else if (util::strieq_l("$ssl_protocol", var_start, varlen)) { + type = SHRPX_LOGF_SSL_PROTOCOL; + } else if (util::strieq_l("$ssl_session_id", var_start, varlen)) { + type = SHRPX_LOGF_SSL_SESSION_ID; } else { LOG(WARN) << "Unrecognized log format variable: " << std::string(var_start, varlen); diff --git a/src/shrpx_log.cc b/src/shrpx_log.cc index 199114f7..69434702 100644 --- a/src/shrpx_log.cc +++ b/src/shrpx_log.cc @@ -164,6 +164,24 @@ std::pair copy(const char *src, size_t avail, } } // namespace +namespace { +const char LOWER_XDIGITS[] = "0123456789abcdef"; +} // namespace + +namespace { +template +std::pair copy_hex_low(const uint8_t *src, + size_t srclen, size_t avail, + OutputIterator oitr) { + auto nwrite = std::min(srclen * 2, avail) / 2; + for (auto i = 0; i < nwrite; ++i) { + *oitr++ = LOWER_XDIGITS[src[i] >> 4]; + *oitr++ = LOWER_XDIGITS[src[i] & 0xf]; + } + return std::make_pair(oitr, avail - nwrite); +} +} // namespace + void upstream_accesslog(const std::vector &lfv, const LogSpec &lgsp) { auto lgconf = log_config(); @@ -253,6 +271,29 @@ void upstream_accesslog(const std::vector &lfv, case SHRPX_LOGF_ALPN: std::tie(p, avail) = copy(lgsp.alpn, avail, p); break; + case SHRPX_LOGF_SSL_CIPHER: + if (!lgsp.tls_info) { + std::tie(p, avail) = copy("-", avail, p); + break; + } + std::tie(p, avail) = copy(lgsp.tls_info->cipher, avail, p); + break; + case SHRPX_LOGF_SSL_PROTOCOL: + if (!lgsp.tls_info) { + std::tie(p, avail) = copy("-", avail, p); + break; + } + std::tie(p, avail) = copy(lgsp.tls_info->protocol, avail, p); + break; + case SHRPX_LOGF_SSL_SESSION_ID: + if (!lgsp.tls_info || lgsp.tls_info->session_id_length == 0) { + std::tie(p, avail) = copy("-", avail, p); + break; + } + std::tie(p, avail) = + copy_hex_low(lgsp.tls_info->session_id, + lgsp.tls_info->session_id_length, avail, p); + break; case SHRPX_LOGF_NONE: break; default: diff --git a/src/shrpx_log.h b/src/shrpx_log.h index 41645d88..a42fbbc4 100644 --- a/src/shrpx_log.h +++ b/src/shrpx_log.h @@ -35,6 +35,7 @@ #include #include "shrpx_log_config.h" +#include "ssl.h" namespace shrpx { @@ -115,6 +116,9 @@ enum LogFragmentType { SHRPX_LOGF_REQUEST_TIME, SHRPX_LOGF_PID, SHRPX_LOGF_ALPN, + SHRPX_LOGF_SSL_CIPHER, + SHRPX_LOGF_SSL_PROTOCOL, + SHRPX_LOGF_SSL_SESSION_ID, }; struct LogFragment { @@ -128,6 +132,7 @@ struct LogSpec { const char *method; const char *path; const char *alpn; + const nghttp2::ssl::TLSSessionInfo *tls_info; std::chrono::system_clock::time_point time_now; std::chrono::high_resolution_clock::time_point request_start_time; std::chrono::high_resolution_clock::time_point request_end_time; diff --git a/src/ssl.cc b/src/ssl.cc index 8696801c..bb4018cd 100644 --- a/src/ssl.cc +++ b/src/ssl.cc @@ -78,6 +78,46 @@ LibsslGlobalLock::LibsslGlobalLock() { LibsslGlobalLock::~LibsslGlobalLock() { ssl_global_locks.clear(); } +const char *get_tls_protocol(SSL *ssl) { + auto session = SSL_get_session(ssl); + if (!session) { + return "unknown"; + } + + switch (session->ssl_version) { + case SSL2_VERSION: + return "SSLv2"; + case SSL3_VERSION: + return "SSLv3"; + case TLS1_2_VERSION: + return "TLSv1.2"; + case TLS1_1_VERSION: + return "TLSv1.1"; + case TLS1_VERSION: + return "TLSv1"; + default: + return "unknown"; + } +} + +TLSSessionInfo *get_tls_session_info(TLSSessionInfo *tls_info, SSL *ssl) { + if (!ssl) { + return nullptr; + } + + auto session = SSL_get_session(ssl); + if (!session) { + return nullptr; + } + + tls_info->cipher = SSL_get_cipher_name(ssl); + tls_info->protocol = get_tls_protocol(ssl); + tls_info->session_id = session->session_id; + tls_info->session_id_length = session->session_id_length; + + return tls_info; +} + } // namespace ssl } // namespace nghttp2 diff --git a/src/ssl.h b/src/ssl.h index 97f39338..61826e37 100644 --- a/src/ssl.h +++ b/src/ssl.h @@ -22,8 +22,15 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifndef SSL_H +#define SSL_H + #include "nghttp2_config.h" +#include + +#include + namespace nghttp2 { namespace ssl { @@ -40,6 +47,19 @@ public: extern const char *const DEFAULT_CIPHER_LIST; +const char *get_tls_protocol(SSL *ssl); + +struct TLSSessionInfo { + const char *cipher; + const char *protocol; + const uint8_t *session_id; + size_t session_id_length; +}; + +TLSSessionInfo *get_tls_session_info(TLSSessionInfo *tls_info, SSL *ssl); + } // namespace ssl } // namespace nghttp2 + +#endif // SSL_H