diff --git a/gennghttpxfun.py b/gennghttpxfun.py index f741920a..fffa3f8e 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -191,6 +191,8 @@ LOGVARS = [ "tls_session_id", "tls_session_reused", "tls_sni", + "tls_client_fingerprint", + "tls_client_subject_name", "backend_host", "backend_port", ] diff --git a/src/shrpx.cc b/src/shrpx.cc index cc5bfd5b..2656b717 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -2482,6 +2482,10 @@ Logging: the response. For HTTP/1, ALPN is always http/1.1, regardless of minor version. * $tls_cipher: cipher used for SSL/TLS connection. + * $tls_client_fingerprint: SHA-256 fingerprint of client + certificate. + * $tls_client_subject_name: subject name in client + certificate. * $tls_protocol: protocol for SSL/TLS connection. * $tls_session_id: session ID for SSL/TLS connection. * $tls_session_reused: "r" if SSL/TLS session was diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index e0ff9de2..6969c4de 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -510,6 +510,24 @@ LogFragmentType log_var_lookup_token(const char *name, size_t namelen) { break; } break; + case 22: + switch (name[21]) { + case 't': + if (util::strieq_l("tls_client_fingerprin", name, 21)) { + return SHRPX_LOGF_TLS_CLIENT_FINGERPRINT; + } + break; + } + break; + case 23: + switch (name[22]) { + case 'e': + if (util::strieq_l("tls_client_subject_nam", name, 22)) { + return SHRPX_LOGF_TLS_CLIENT_SUBJECT_NAME; + } + break; + } + break; } return SHRPX_LOGF_NONE; } diff --git a/src/shrpx_log.cc b/src/shrpx_log.cc index 83c4ba2a..c803378c 100644 --- a/src/shrpx_log.cc +++ b/src/shrpx_log.cc @@ -533,6 +533,45 @@ void upstream_accesslog(const std::vector &lfv, } std::tie(p, last) = copy_escape(lgsp.sni, p, last); break; + case SHRPX_LOGF_TLS_CLIENT_FINGERPRINT: { + if (!lgsp.ssl) { + std::tie(p, last) = copy('-', p, last); + break; + } + auto x = SSL_get_peer_certificate(lgsp.ssl); + if (!x) { + std::tie(p, last) = copy('-', p, last); + break; + } + std::array buf; + auto len = tls::get_x509_fingerprint(buf.data(), buf.size(), x); + X509_free(x); + if (len <= 0) { + std::tie(p, last) = copy('-', p, last); + break; + } + std::tie(p, last) = copy_hex_low(buf.data(), len, p, last); + break; + } + case SHRPX_LOGF_TLS_CLIENT_SUBJECT_NAME: { + if (!lgsp.ssl) { + std::tie(p, last) = copy('-', p, last); + break; + } + auto x = SSL_get_peer_certificate(lgsp.ssl); + if (!x) { + std::tie(p, last) = copy('-', p, last); + break; + } + auto name = tls::get_x509_subject_name(balloc, x); + X509_free(x); + if (name.empty()) { + std::tie(p, last) = copy('-', p, last); + break; + } + std::tie(p, last) = copy(name, p, last); + break; + } case SHRPX_LOGF_BACKEND_HOST: if (!downstream_addr) { std::tie(p, last) = copy('-', p, last); diff --git a/src/shrpx_log.h b/src/shrpx_log.h index 780d81f0..a413ce85 100644 --- a/src/shrpx_log.h +++ b/src/shrpx_log.h @@ -138,6 +138,8 @@ enum LogFragmentType { SHRPX_LOGF_TLS_SESSION_REUSED, SHRPX_LOGF_SSL_SESSION_REUSED = SHRPX_LOGF_TLS_SESSION_REUSED, SHRPX_LOGF_TLS_SNI, + SHRPX_LOGF_TLS_CLIENT_FINGERPRINT, + SHRPX_LOGF_TLS_CLIENT_SUBJECT_NAME, SHRPX_LOGF_BACKEND_HOST, SHRPX_LOGF_BACKEND_PORT, };