From 3c03024881e9673949ba4bf989f5728e711f1128 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 8 Jan 2017 22:33:19 +0900 Subject: [PATCH 1/2] nghttpx: Add client-no-http2-cipher-black-list option This commit adds client-no-http2-cipher-black-list option to disable enforcement of HTTP/2 cipher black list on backend HTTP/2 connection. Previously, existing no-http2-cipher-black-list option disables it for both frontend and backend connections. Now no-http2-cipher-black-list option only disables it for frontend connection. --- gennghttpxfun.py | 1 + src/shrpx.cc | 19 ++++++++++++++++--- src/shrpx_config.cc | 10 ++++++++++ src/shrpx_config.h | 4 ++++ src/shrpx_connection.cc | 15 +++++++++++++-- src/shrpx_connection.h | 2 ++ 6 files changed, 46 insertions(+), 5 deletions(-) diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 4d4fb7e4..cac3a548 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -155,6 +155,7 @@ OPTIONS = [ "frontend-keep-alive-timeout", "psk-secrets", "client-psk-secrets", + "client-no-http2-cipher-black-list", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index c31ae514..4dc79b70 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -2091,9 +2091,15 @@ SSL/TLS: Default: )" << util::duration_str(config->tls.dyn_rec.idle_timeout) << R"( --no-http2-cipher-black-list - Allow black listed cipher suite on HTTP/2 connection. - See https://tools.ietf.org/html/rfc7540#appendix-A for - the complete HTTP/2 cipher suites black list. + Allow black listed cipher suite on frontend HTTP/2 + connection. See + https://tools.ietf.org/html/rfc7540#appendix-A for the + complete HTTP/2 cipher suites black list. + --client-no-http2-cipher-black-list + Allow black listed cipher suite on backend HTTP/2 + connection. See + https://tools.ietf.org/html/rfc7540#appendix-A for the + complete HTTP/2 cipher suites black list. --tls-sct-dir= Specifies the directory where *.sct files exist. All *.sct files in are read, and sent as @@ -3096,6 +3102,8 @@ int main(int argc, char **argv) { &flag, 146}, {SHRPX_OPT_PSK_SECRETS.c_str(), required_argument, &flag, 147}, {SHRPX_OPT_CLIENT_PSK_SECRETS.c_str(), required_argument, &flag, 148}, + {SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument, + &flag, 149}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -3794,6 +3802,11 @@ int main(int argc, char **argv) { // --client-psk-secrets cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PSK_SECRETS, StringRef{optarg}); break; + case 149: + // --client-no-http2-cipher-black-list + cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST, + StringRef::from_lit("yes")); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 4bd4efdf..4fc3f841 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -2004,6 +2004,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL; } break; + case 't': + if (util::strieq_l("client-no-http2-cipher-black-lis", name, 32)) { + return SHRPX_OPTID_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST; + } + break; } break; case 34: @@ -3274,6 +3279,11 @@ int parse_config(Config *config, int optid, const StringRef &opt, return parse_psk_secrets(config, optarg); case SHRPX_OPTID_CLIENT_PSK_SECRETS: return parse_client_psk_secrets(config, optarg); + case SHRPX_OPTID_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST: + config->tls.client.no_http2_cipher_black_list = + util::strieq_l("yes", optarg); + + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 118ecc1a..0d9c8c81 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -322,6 +322,8 @@ constexpr auto SHRPX_OPT_FRONTEND_KEEP_ALIVE_TIMEOUT = constexpr auto SHRPX_OPT_PSK_SECRETS = StringRef::from_lit("psk-secrets"); constexpr auto SHRPX_OPT_CLIENT_PSK_SECRETS = StringRef::from_lit("client-psk-secrets"); +constexpr auto SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST = + StringRef::from_lit("client-no-http2-cipher-black-list"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -556,6 +558,7 @@ struct TLSConfig { } psk; StringRef private_key_file; StringRef cert_file; + bool no_http2_cipher_black_list; } client; // PSK secrets. The key is identity, and the associated value is @@ -924,6 +927,7 @@ enum { SHRPX_OPTID_CIPHERS, SHRPX_OPTID_CLIENT, SHRPX_OPTID_CLIENT_CERT_FILE, + SHRPX_OPTID_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST, SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE, SHRPX_OPTID_CLIENT_PROXY, SHRPX_OPTID_CLIENT_PSK_SECRETS, diff --git a/src/shrpx_connection.cc b/src/shrpx_connection.cc index a10f4358..914c7ccb 100644 --- a/src/shrpx_connection.cc +++ b/src/shrpx_connection.cc @@ -141,7 +141,10 @@ void Connection::disconnect() { void Connection::prepare_client_handshake() { SSL_set_connect_state(tls.ssl); } -void Connection::prepare_server_handshake() { SSL_set_accept_state(tls.ssl); } +void Connection::prepare_server_handshake() { + SSL_set_accept_state(tls.ssl); + tls.server_handshake = true; +} // BIO implementation is inspired by openldap implementation: // http://www.openldap.org/devel/cvsweb.cgi/~checkout~/libraries/libldap/tls_o.c @@ -530,7 +533,15 @@ int Connection::check_http2_requirement() { } return -1; } - if (!get_config()->tls.no_http2_cipher_black_list && + + auto check_black_list = false; + if (tls.server_handshake) { + check_black_list = !get_config()->tls.no_http2_cipher_black_list; + } else { + check_black_list = !get_config()->tls.client.no_http2_cipher_black_list; + } + + if (check_black_list && nghttp2::ssl::check_http2_cipher_black_list(tls.ssl)) { if (LOG_ENABLED(INFO)) { LOG(INFO) << "The negotiated cipher suite is in HTTP/2 cipher suite " diff --git a/src/shrpx_connection.h b/src/shrpx_connection.h index 5dc1c37e..990a85ed 100644 --- a/src/shrpx_connection.h +++ b/src/shrpx_connection.h @@ -64,6 +64,8 @@ struct TLSConnection { int handshake_state; bool initial_handshake_done; bool reneg_started; + // true if ssl is prepared to do handshake as server. + bool server_handshake; }; struct TCPHint { From 9c7e54d9b52c19e3dedfe19758dd07d2ab571a55 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 8 Jan 2017 22:40:58 +0900 Subject: [PATCH 2/2] nghttpx: Add client-ciphers option Previously, ciphers option sets cipher list for both frontend and backend TLS connections. With this commit, ciphers option only sets cipher list for frontend connections. The new client-ciphers option sets cipher list for backend connection. --- gennghttpxfun.py | 1 + src/shrpx.cc | 12 ++++++++++-- src/shrpx_config.cc | 7 +++++++ src/shrpx_config.h | 3 +++ src/shrpx_ssl.cc | 4 ++-- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/gennghttpxfun.py b/gennghttpxfun.py index cac3a548..c394486f 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -156,6 +156,7 @@ OPTIONS = [ "psk-secrets", "client-psk-secrets", "client-no-http2-cipher-black-list", + "client-ciphers", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 4dc79b70..ba607db2 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1896,8 +1896,11 @@ Timeout: SSL/TLS: --ciphers= - Set allowed cipher list. The format of the string is - described in OpenSSL ciphers(1). + Set allowed cipher list for frontend connection. The + format of the string is described in OpenSSL ciphers(1). + --client-ciphers= + Set allowed cipher list for backend connection. The + format of the string is described in OpenSSL ciphers(1). --ecdh-curves= Set supported curve list for frontend connections. is a colon separated list of curve NID or names @@ -3104,6 +3107,7 @@ int main(int argc, char **argv) { {SHRPX_OPT_CLIENT_PSK_SECRETS.c_str(), required_argument, &flag, 148}, {SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument, &flag, 149}, + {SHRPX_OPT_CLIENT_CIPHERS.c_str(), required_argument, &flag, 150}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -3807,6 +3811,10 @@ int main(int argc, char **argv) { cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST, StringRef::from_lit("yes")); break; + case 150: + // --client-ciphers + cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CIPHERS, StringRef{optarg}); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 4fc3f841..ac4775ae 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -1585,6 +1585,9 @@ int option_lookup_token(const char *name, size_t namelen) { if (util::strieq_l("backend-no-tl", name, 13)) { return SHRPX_OPTID_BACKEND_NO_TLS; } + if (util::strieq_l("client-cipher", name, 13)) { + return SHRPX_OPTID_CLIENT_CIPHERS; + } break; case 't': if (util::strieq_l("tls-proto-lis", name, 13)) { @@ -3283,6 +3286,10 @@ int parse_config(Config *config, int optid, const StringRef &opt, config->tls.client.no_http2_cipher_black_list = util::strieq_l("yes", optarg); + return 0; + case SHRPX_OPTID_CLIENT_CIPHERS: + config->tls.client.ciphers = make_string_ref(config->balloc, optarg); + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 0d9c8c81..efdc50a5 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -324,6 +324,7 @@ constexpr auto SHRPX_OPT_CLIENT_PSK_SECRETS = StringRef::from_lit("client-psk-secrets"); constexpr auto SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST = StringRef::from_lit("client-no-http2-cipher-black-list"); +constexpr auto SHRPX_OPT_CLIENT_CIPHERS = StringRef::from_lit("client-ciphers"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -558,6 +559,7 @@ struct TLSConfig { } psk; StringRef private_key_file; StringRef cert_file; + StringRef ciphers; bool no_http2_cipher_black_list; } client; @@ -927,6 +929,7 @@ enum { SHRPX_OPTID_CIPHERS, SHRPX_OPTID_CLIENT, SHRPX_OPTID_CLIENT_CERT_FILE, + SHRPX_OPTID_CLIENT_CIPHERS, SHRPX_OPTID_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST, SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE, SHRPX_OPTID_CLIENT_PROXY, diff --git a/src/shrpx_ssl.cc b/src/shrpx_ssl.cc index dee8662a..eb1ea732 100644 --- a/src/shrpx_ssl.cc +++ b/src/shrpx_ssl.cc @@ -874,8 +874,8 @@ SSL_CTX *create_ssl_client_context( SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask); const char *ciphers; - if (!tlsconf.ciphers.empty()) { - ciphers = tlsconf.ciphers.c_str(); + if (!tlsconf.client.ciphers.empty()) { + ciphers = tlsconf.client.ciphers.c_str(); } else { ciphers = nghttp2::ssl::DEFAULT_CIPHER_LIST; }