From 4ed4efc24113c25d7f59aab42bcccd406f7e708e Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 18 Jan 2014 19:53:52 +0900 Subject: [PATCH] nghttpx: Disable TLS renegotiation --- src/shrpx_client_handler.cc | 33 +++++++++++++++++++++++++++++++-- src/shrpx_client_handler.h | 6 ++++++ src/shrpx_ssl.cc | 20 ++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index f8b0cf95..f24c5fe4 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -48,6 +48,10 @@ namespace { void upstream_readcb(bufferevent *bev, void *arg) { auto handler = reinterpret_cast(arg); + if(handler->get_tls_renegotiation()) { + delete handler; + return; + } int rv = handler->on_read(); if(rv != 0) { delete handler; @@ -106,8 +110,9 @@ void upstream_eventcb(bufferevent *bev, short events, void *arg) delete handler; } else { if(events & BEV_EVENT_CONNECTED) { + handler->set_tls_handshake(true); if(LOG_ENABLED(INFO)) { - CLOG(INFO, handler) << "SSL/TLS handleshake completed"; + CLOG(INFO, handler) << "SSL/TLS handshake completed"; } if(handler->validate_next_proto() != 0) { delete handler; @@ -226,7 +231,9 @@ ClientHandler::ClientHandler(bufferevent *bev, int fd, SSL *ssl, ssl_(ssl), left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_HEADER_LEN), fd_(fd), - should_close_after_write_(false) + should_close_after_write_(false), + tls_handshake_(false), + tls_renegotiation_(false) { int rv; rv = bufferevent_set_rate_limit(bev_, get_config()->rate_limit_cfg); @@ -238,6 +245,7 @@ ClientHandler::ClientHandler(bufferevent *bev, int fd, SSL *ssl, set_upstream_timeouts(&get_config()->upstream_read_timeout, &get_config()->upstream_write_timeout); if(ssl_) { + SSL_set_app_data(ssl_, reinterpret_cast(this)); set_bev_cb(nullptr, upstream_writecb, upstream_eventcb); } else { // For non-TLS version, first create HttpsUpstream. It may be @@ -254,6 +262,7 @@ ClientHandler::~ClientHandler() CLOG(INFO, this) << "Deleting"; } if(ssl_) { + SSL_set_app_data(ssl_, nullptr); SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN); SSL_shutdown(ssl_); } @@ -498,4 +507,24 @@ std::string ClientHandler::get_upstream_scheme() const } } +void ClientHandler::set_tls_handshake(bool f) +{ + tls_handshake_ = f; +} + +bool ClientHandler::get_tls_handshake() const +{ + return tls_handshake_; +} + +void ClientHandler::set_tls_renegotiation(bool f) +{ + tls_renegotiation_ = f; +} + +bool ClientHandler::get_tls_renegotiation() const +{ + return tls_renegotiation_; +} + } // namespace shrpx diff --git a/src/shrpx_client_handler.h b/src/shrpx_client_handler.h index e2039efc..bc76a48f 100644 --- a/src/shrpx_client_handler.h +++ b/src/shrpx_client_handler.h @@ -77,6 +77,10 @@ public: bool get_http2_upgrade_allowed() const; // Returns upstream scheme, either "http" or "https" std::string get_upstream_scheme() const; + void set_tls_handshake(bool f); + bool get_tls_handshake() const; + void set_tls_renegotiation(bool f); + bool get_tls_renegotiation() const; private: std::set dconn_pool_; std::unique_ptr upstream_; @@ -90,6 +94,8 @@ private: size_t left_connhd_len_; int fd_; bool should_close_after_write_; + bool tls_handshake_; + bool tls_renegotiation_; }; } // namespace shrpx diff --git a/src/shrpx_ssl.cc b/src/shrpx_ssl.cc index 269d7ab3..ad7b3eef 100644 --- a/src/shrpx_ssl.cc +++ b/src/shrpx_ssl.cc @@ -132,6 +132,25 @@ int servername_callback(SSL *ssl, int *al, void *arg) } } // namespace +namespace { +void info_callback(const SSL *ssl, int where, int ret) +{ + // To mitigate possible DOS attack using lots of renegotiations, we + // disable renegotiation. Since OpenSSL does not provide an easy way + // to disable it, we check that renegotiation is started in this + // callback. + if(where & SSL_CB_HANDSHAKE_START) { + auto handler = static_cast(SSL_get_app_data(ssl)); + if(handler && handler->get_tls_handshake()) { + handler->set_tls_renegotiation(true); + if(LOG_ENABLED(INFO)) { + CLOG(INFO, handler) << "TLS renegotiation started"; + } + } + } +} +} // namespace + #if OPENSSL_VERSION_NUMBER >= 0x10002000L namespace { int alpn_select_proto_cb(SSL* ssl, @@ -301,6 +320,7 @@ SSL_CTX* create_ssl_context(const char *private_key_file, verify_callback); } SSL_CTX_set_tlsext_servername_callback(ssl_ctx, servername_callback); + SSL_CTX_set_info_callback(ssl_ctx, info_callback); // NPN advertisement auto proto_list_len = set_npn_prefs(proto_list, get_config()->npn_list,