nghttpx: Disable TLS renegotiation

This commit is contained in:
Tatsuhiro Tsujikawa 2014-01-18 19:53:52 +09:00
parent 8f3d4fdeec
commit 4ed4efc241
3 changed files with 57 additions and 2 deletions

View File

@ -48,6 +48,10 @@ namespace {
void upstream_readcb(bufferevent *bev, void *arg) void upstream_readcb(bufferevent *bev, void *arg)
{ {
auto handler = reinterpret_cast<ClientHandler*>(arg); auto handler = reinterpret_cast<ClientHandler*>(arg);
if(handler->get_tls_renegotiation()) {
delete handler;
return;
}
int rv = handler->on_read(); int rv = handler->on_read();
if(rv != 0) { if(rv != 0) {
delete handler; delete handler;
@ -106,8 +110,9 @@ void upstream_eventcb(bufferevent *bev, short events, void *arg)
delete handler; delete handler;
} else { } else {
if(events & BEV_EVENT_CONNECTED) { if(events & BEV_EVENT_CONNECTED) {
handler->set_tls_handshake(true);
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
CLOG(INFO, handler) << "SSL/TLS handleshake completed"; CLOG(INFO, handler) << "SSL/TLS handshake completed";
} }
if(handler->validate_next_proto() != 0) { if(handler->validate_next_proto() != 0) {
delete handler; delete handler;
@ -226,7 +231,9 @@ ClientHandler::ClientHandler(bufferevent *bev, int fd, SSL *ssl,
ssl_(ssl), ssl_(ssl),
left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_HEADER_LEN), left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_HEADER_LEN),
fd_(fd), fd_(fd),
should_close_after_write_(false) should_close_after_write_(false),
tls_handshake_(false),
tls_renegotiation_(false)
{ {
int rv; int rv;
rv = bufferevent_set_rate_limit(bev_, get_config()->rate_limit_cfg); 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, set_upstream_timeouts(&get_config()->upstream_read_timeout,
&get_config()->upstream_write_timeout); &get_config()->upstream_write_timeout);
if(ssl_) { if(ssl_) {
SSL_set_app_data(ssl_, reinterpret_cast<char*>(this));
set_bev_cb(nullptr, upstream_writecb, upstream_eventcb); set_bev_cb(nullptr, upstream_writecb, upstream_eventcb);
} else { } else {
// For non-TLS version, first create HttpsUpstream. It may be // For non-TLS version, first create HttpsUpstream. It may be
@ -254,6 +262,7 @@ ClientHandler::~ClientHandler()
CLOG(INFO, this) << "Deleting"; CLOG(INFO, this) << "Deleting";
} }
if(ssl_) { if(ssl_) {
SSL_set_app_data(ssl_, nullptr);
SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN); SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN);
SSL_shutdown(ssl_); 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 } // namespace shrpx

View File

@ -77,6 +77,10 @@ public:
bool get_http2_upgrade_allowed() const; bool get_http2_upgrade_allowed() const;
// Returns upstream scheme, either "http" or "https" // Returns upstream scheme, either "http" or "https"
std::string get_upstream_scheme() const; 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: private:
std::set<DownstreamConnection*> dconn_pool_; std::set<DownstreamConnection*> dconn_pool_;
std::unique_ptr<Upstream> upstream_; std::unique_ptr<Upstream> upstream_;
@ -90,6 +94,8 @@ private:
size_t left_connhd_len_; size_t left_connhd_len_;
int fd_; int fd_;
bool should_close_after_write_; bool should_close_after_write_;
bool tls_handshake_;
bool tls_renegotiation_;
}; };
} // namespace shrpx } // namespace shrpx

View File

@ -132,6 +132,25 @@ int servername_callback(SSL *ssl, int *al, void *arg)
} }
} // namespace } // 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<ClientHandler*>(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 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
namespace { namespace {
int alpn_select_proto_cb(SSL* ssl, int alpn_select_proto_cb(SSL* ssl,
@ -301,6 +320,7 @@ SSL_CTX* create_ssl_context(const char *private_key_file,
verify_callback); verify_callback);
} }
SSL_CTX_set_tlsext_servername_callback(ssl_ctx, servername_callback); SSL_CTX_set_tlsext_servername_callback(ssl_ctx, servername_callback);
SSL_CTX_set_info_callback(ssl_ctx, info_callback);
// NPN advertisement // NPN advertisement
auto proto_list_len = set_npn_prefs(proto_list, get_config()->npn_list, auto proto_list_len = set_npn_prefs(proto_list, get_config()->npn_list,