From 60baca27e4f3c61408d269e939d6a703b7a30ff4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 29 Oct 2017 22:42:30 +0900 Subject: [PATCH] nghttpx: Add more TLS related attributes to mruby Env object The added attributes are: * tls_cipher * tls_protocol * tls_session_id * tls_session_reused * alpn --- doc/nghttpx.h2r | 20 ++++++++ src/shrpx_client_handler.cc | 2 + src/shrpx_client_handler.h | 3 ++ src/shrpx_mruby_module_env.cc | 95 +++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+) diff --git a/doc/nghttpx.h2r b/doc/nghttpx.h2r index a1dc59f5..46138042 100644 --- a/doc/nghttpx.h2r +++ b/doc/nghttpx.h2r @@ -376,6 +376,26 @@ respectively. Return the subject name of a client certificate. + .. rb:attr_reader:: tls_cipher + + Return a TLS cipher negotiated in this connection. + + .. rb:attr_reader:: tls_protocol + + Return a TLS protocol version negotiated in this connection. + + .. rb:attr_reader:: tls_session_id + + Return a session ID for this connection in hex string. + + .. rb:attr_reader:: tls_session_reused + + Return true if, and only if a SSL/TLS session is reused. + + .. rb:attr_reader:: alpn + + Return ALPN identifier negotiated in this connection. + .. rb:class:: Request Object to represent request from client. The modification to diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index 97040266..9d1eefa2 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -1481,6 +1481,8 @@ void ClientHandler::set_tls_sni(const StringRef &sni) { StringRef ClientHandler::get_tls_sni() const { return sni_; } +StringRef ClientHandler::get_alpn() const { return alpn_; } + BlockAllocator &ClientHandler::get_block_allocator() { return balloc_; } } // namespace shrpx diff --git a/src/shrpx_client_handler.h b/src/shrpx_client_handler.h index 37451d0c..9575d988 100644 --- a/src/shrpx_client_handler.h +++ b/src/shrpx_client_handler.h @@ -166,6 +166,9 @@ public: // Returns TLS SNI extension value client sent in this connection. StringRef get_tls_sni() const; + // Returns ALPN negotiated in this connection. + StringRef get_alpn() const; + BlockAllocator &get_block_allocator(); private: diff --git a/src/shrpx_mruby_module_env.cc b/src/shrpx_mruby_module_env.cc index 06a5195b..5a7b9469 100644 --- a/src/shrpx_mruby_module_env.cc +++ b/src/shrpx_mruby_module_env.cc @@ -198,6 +198,92 @@ mrb_value env_get_tls_client_subject_name(mrb_state *mrb, mrb_value self) { } } // namespace +namespace { +mrb_value env_get_tls_cipher(mrb_state *mrb, mrb_value self) { + auto data = static_cast(mrb->ud); + auto downstream = data->downstream; + auto upstream = downstream->get_upstream(); + auto handler = upstream->get_client_handler(); + auto ssl = handler->get_ssl(); + + if (!ssl) { + return mrb_str_new_static(mrb, "", 0); + } + + return mrb_str_new_cstr(mrb, SSL_get_cipher_name(ssl)); +} +} // namespace + +namespace { +mrb_value env_get_tls_protocol(mrb_state *mrb, mrb_value self) { + auto data = static_cast(mrb->ud); + auto downstream = data->downstream; + auto upstream = downstream->get_upstream(); + auto handler = upstream->get_client_handler(); + auto ssl = handler->get_ssl(); + + if (!ssl) { + return mrb_str_new_static(mrb, "", 0); + } + + return mrb_str_new_cstr(mrb, nghttp2::tls::get_tls_protocol(ssl)); +} +} // namespace + +namespace { +mrb_value env_get_tls_session_id(mrb_state *mrb, mrb_value self) { + auto data = static_cast(mrb->ud); + auto downstream = data->downstream; + auto upstream = downstream->get_upstream(); + auto handler = upstream->get_client_handler(); + auto ssl = handler->get_ssl(); + + if (!ssl) { + return mrb_str_new_static(mrb, "", 0); + } + + auto session = SSL_get_session(ssl); + if (!session) { + return mrb_str_new_static(mrb, "", 0); + } + + unsigned int session_id_length = 0; + auto session_id = SSL_SESSION_get_id(session, &session_id_length); + + // TODO Use template version of util::format_hex. + auto &balloc = downstream->get_block_allocator(); + auto id = util::format_hex(balloc, StringRef{session_id, session_id_length}); + return mrb_str_new(mrb, id.c_str(), id.size()); +} +} // namespace + +namespace { +mrb_value env_get_tls_session_reused(mrb_state *mrb, mrb_value self) { + auto data = static_cast(mrb->ud); + auto downstream = data->downstream; + auto upstream = downstream->get_upstream(); + auto handler = upstream->get_client_handler(); + auto ssl = handler->get_ssl(); + + if (!ssl) { + return mrb_false_value(); + } + + return SSL_session_reused(ssl) ? mrb_true_value() : mrb_false_value(); +} +} // namespace + +namespace { +mrb_value env_get_alpn(mrb_state *mrb, mrb_value self) { + auto data = static_cast(mrb->ud); + auto downstream = data->downstream; + auto upstream = downstream->get_upstream(); + auto handler = upstream->get_client_handler(); + auto alpn = handler->get_alpn(); + return mrb_str_new(mrb, alpn.c_str(), alpn.size()); +} +} // namespace + void init_env_class(mrb_state *mrb, RClass *module) { auto env_class = mrb_define_class_under(mrb, module, "Env", mrb->object_class); @@ -221,6 +307,15 @@ void init_env_class(mrb_state *mrb, RClass *module) { env_get_tls_client_fingerprint, MRB_ARGS_NONE()); mrb_define_method(mrb, env_class, "tls_client_subject_name", env_get_tls_client_subject_name, MRB_ARGS_NONE()); + mrb_define_method(mrb, env_class, "tls_cipher", env_get_tls_cipher, + MRB_ARGS_NONE()); + mrb_define_method(mrb, env_class, "tls_protocol", env_get_tls_protocol, + MRB_ARGS_NONE()); + mrb_define_method(mrb, env_class, "tls_session_id", env_get_tls_session_id, + MRB_ARGS_NONE()); + mrb_define_method(mrb, env_class, "tls_session_reused", + env_get_tls_session_reused, MRB_ARGS_NONE()); + mrb_define_method(mrb, env_class, "alpn", env_get_alpn, MRB_ARGS_NONE()); } } // namespace mruby