diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 4d4fb7e4..c394486f 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -155,6 +155,8 @@ OPTIONS = [ "frontend-keep-alive-timeout", "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 c31ae514..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 @@ -2091,9 +2094,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 +3105,9 @@ 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}, + {SHRPX_OPT_CLIENT_CIPHERS.c_str(), required_argument, &flag, 150}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -3794,6 +3806,15 @@ 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; + 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 4bd4efdf..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)) { @@ -2004,6 +2007,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 +3282,15 @@ 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_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 118ecc1a..efdc50a5 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -322,6 +322,9 @@ 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 auto SHRPX_OPT_CLIENT_CIPHERS = StringRef::from_lit("client-ciphers"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -556,6 +559,8 @@ struct TLSConfig { } psk; StringRef private_key_file; StringRef cert_file; + StringRef ciphers; + bool no_http2_cipher_black_list; } client; // PSK secrets. The key is identity, and the associated value is @@ -924,6 +929,8 @@ 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, 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 { 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; }