nghttpx: Add log variables related to SSL/TLS connection

This commit add following 3 log variables to SSL/TLS connection:
$ssl_cipher, $ssl_protocol, $ssl_session_id.  If no information is
available for them, '-' is produced for each.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-06-28 16:37:17 +09:00
parent b06e339dbb
commit 197493afd4
8 changed files with 123 additions and 23 deletions

View File

@ -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 { namespace {
void print_server_tmp_key(SSL *ssl) { void print_server_tmp_key(SSL *ssl) {
// libressl does not have SSL_get_server_tmp_key // 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) { if (worker->id == 0 && !worker->tls_info_report_done) {
worker->tls_info_report_done = true; worker->tls_info_report_done = true;
auto cipher = SSL_get_current_cipher(ssl); 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; << "Cipher: " << SSL_CIPHER_get_name(cipher) << std::endl;
print_server_tmp_key(ssl); print_server_tmp_key(ssl);
} }

View File

@ -1345,6 +1345,9 @@ Logging:
* $alpn: ALPN identifier of the protocol which generates * $alpn: ALPN identifier of the protocol which generates
the response. For HTTP/1, ALPN is always http/1.1, the response. For HTTP/1, ALPN is always http/1.1,
regardless of minor version. 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"( Default: )" << DEFAULT_ACCESSLOG_FORMAT << R"(
--errorlog-file=<PATH> --errorlog-file=<PATH>

View File

@ -733,6 +733,8 @@ std::string construct_absolute_request_uri(Downstream *downstream) {
} // namespace } // namespace
void ClientHandler::write_accesslog(Downstream *downstream) { void ClientHandler::write_accesslog(Downstream *downstream) {
nghttp2::ssl::TLSSessionInfo tls_info;
upstream_accesslog( upstream_accesslog(
get_config()->accesslog_format, get_config()->accesslog_format,
LogSpec{ LogSpec{
@ -747,6 +749,7 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
: downstream->get_request_path().c_str(), : downstream->get_request_path().c_str(),
alpn_.c_str(), alpn_.c_str(),
nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
std::chrono::system_clock::now(), // time_now std::chrono::system_clock::now(), // time_now
downstream->get_request_start_time(), // request_start_time 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) { int64_t body_bytes_sent) {
auto time_now = std::chrono::system_clock::now(); auto time_now = std::chrono::system_clock::now();
auto highres_now = std::chrono::high_resolution_clock::now(); auto highres_now = std::chrono::high_resolution_clock::now();
nghttp2::ssl::TLSSessionInfo tls_info;
upstream_accesslog(get_config()->accesslog_format, upstream_accesslog(get_config()->accesslog_format,
LogSpec{ LogSpec{
nullptr, ipaddr_.c_str(), nullptr, ipaddr_.c_str(),
"-", // method "-", // method
"-", // path, "-", // 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 highres_now, // request_start_time TODO is
// there a better value? // there a better value?
highres_now, // request_end_time highres_now, // request_end_time

View File

@ -383,6 +383,12 @@ std::vector<LogFragment> parse_log_format(const char *optarg) {
type = SHRPX_LOGF_PID; type = SHRPX_LOGF_PID;
} else if (util::strieq_l("$alpn", var_start, varlen)) { } else if (util::strieq_l("$alpn", var_start, varlen)) {
type = SHRPX_LOGF_ALPN; 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 { } else {
LOG(WARN) << "Unrecognized log format variable: " LOG(WARN) << "Unrecognized log format variable: "
<< std::string(var_start, varlen); << std::string(var_start, varlen);

View File

@ -164,6 +164,24 @@ std::pair<OutputIterator, size_t> copy(const char *src, size_t avail,
} }
} // namespace } // namespace
namespace {
const char LOWER_XDIGITS[] = "0123456789abcdef";
} // namespace
namespace {
template <typename OutputIterator>
std::pair<OutputIterator, size_t> 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<LogFragment> &lfv, void upstream_accesslog(const std::vector<LogFragment> &lfv,
const LogSpec &lgsp) { const LogSpec &lgsp) {
auto lgconf = log_config(); auto lgconf = log_config();
@ -253,6 +271,29 @@ void upstream_accesslog(const std::vector<LogFragment> &lfv,
case SHRPX_LOGF_ALPN: case SHRPX_LOGF_ALPN:
std::tie(p, avail) = copy(lgsp.alpn, avail, p); std::tie(p, avail) = copy(lgsp.alpn, avail, p);
break; 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: case SHRPX_LOGF_NONE:
break; break;
default: default:

View File

@ -35,6 +35,7 @@
#include <chrono> #include <chrono>
#include "shrpx_log_config.h" #include "shrpx_log_config.h"
#include "ssl.h"
namespace shrpx { namespace shrpx {
@ -115,6 +116,9 @@ enum LogFragmentType {
SHRPX_LOGF_REQUEST_TIME, SHRPX_LOGF_REQUEST_TIME,
SHRPX_LOGF_PID, SHRPX_LOGF_PID,
SHRPX_LOGF_ALPN, SHRPX_LOGF_ALPN,
SHRPX_LOGF_SSL_CIPHER,
SHRPX_LOGF_SSL_PROTOCOL,
SHRPX_LOGF_SSL_SESSION_ID,
}; };
struct LogFragment { struct LogFragment {
@ -128,6 +132,7 @@ struct LogSpec {
const char *method; const char *method;
const char *path; const char *path;
const char *alpn; const char *alpn;
const nghttp2::ssl::TLSSessionInfo *tls_info;
std::chrono::system_clock::time_point time_now; 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_start_time;
std::chrono::high_resolution_clock::time_point request_end_time; std::chrono::high_resolution_clock::time_point request_end_time;

View File

@ -78,6 +78,46 @@ LibsslGlobalLock::LibsslGlobalLock() {
LibsslGlobalLock::~LibsslGlobalLock() { ssl_global_locks.clear(); } 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 ssl
} // namespace nghttp2 } // namespace nghttp2

View File

@ -22,8 +22,15 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef SSL_H
#define SSL_H
#include "nghttp2_config.h" #include "nghttp2_config.h"
#include <cinttypes>
#include <openssl/ssl.h>
namespace nghttp2 { namespace nghttp2 {
namespace ssl { namespace ssl {
@ -40,6 +47,19 @@ public:
extern const char *const DEFAULT_CIPHER_LIST; 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 ssl
} // namespace nghttp2 } // namespace nghttp2
#endif // SSL_H