diff --git a/src/HttpServer.cc b/src/HttpServer.cc index f4dec3c5..7dc16765 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -2122,6 +2122,13 @@ int HttpServer::run() { SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); + if (nghttp2::ssl::ssl_ctx_set_proto_versions( + ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION, + nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) { + std::cerr << "Could not set TLS versions" << std::endl; + return -1; + } + if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) { std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl; return -1; diff --git a/src/h2load.cc b/src/h2load.cc index 6fdd0b9b..cbf0e51a 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -2242,6 +2242,13 @@ int main(int argc, char **argv) { SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); + if (nghttp2::ssl::ssl_ctx_set_proto_versions( + ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION, + nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) { + std::cerr << "Could not set TLS versions" << std::endl; + exit(EXIT_FAILURE); + } + if (SSL_CTX_set_cipher_list(ssl_ctx, config.ciphers.c_str()) == 0) { std::cerr << "SSL_CTX_set_cipher_list with " << config.ciphers << " failed: " << ERR_error_string(ERR_get_error(), nullptr) diff --git a/src/nghttp.cc b/src/nghttp.cc index 38e85a82..b94e2ba9 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -2246,6 +2246,15 @@ int communicate( SSL_CTX_set_options(ssl_ctx, ssl_opts); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); + + if (nghttp2::ssl::ssl_ctx_set_proto_versions( + ssl_ctx, nghttp2::ssl::NGHTTP2_TLS_MIN_VERSION, + nghttp2::ssl::NGHTTP2_TLS_MAX_VERSION) != 0) { + std::cerr << "[ERROR] Could not set TLS versions" << std::endl; + result = -1; + goto fin; + } + if (SSL_CTX_set_cipher_list(ssl_ctx, ssl::DEFAULT_CIPHER_LIST) == 0) { std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr) << std::endl; diff --git a/src/shrpx.cc b/src/shrpx.cc index 87b4577a..88e41d89 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1369,7 +1369,11 @@ constexpr auto DEFAULT_NPN_LIST = StringRef::from_lit("h2,h2-16,h2-14," namespace { constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.1"); +#ifdef TLS1_3_VERSION +constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.3"); +#else // !TLS1_3_VERSION constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.2"); +#endif // !TLS1_3_VERSION } // namespace namespace { @@ -1427,8 +1431,10 @@ void fill_default_config(Config *config) { tlsconf.ciphers = StringRef::from_lit(nghttp2::ssl::DEFAULT_CIPHER_LIST); tlsconf.client.ciphers = StringRef::from_lit(nghttp2::ssl::DEFAULT_CIPHER_LIST); - tlsconf.min_proto_version = TLS1_1_VERSION; - tlsconf.max_proto_version = TLS1_2_VERSION; + tlsconf.min_proto_version = + ssl::proto_version_from_string(DEFAULT_TLS_MIN_PROTO_VERSION); + tlsconf.max_proto_version = + ssl::proto_version_from_string(DEFAULT_TLS_MAX_PROTO_VERSION); #if OPENSSL_1_1_API tlsconf.ecdh_curves = StringRef::from_lit("X25519:P-256:P-384:P-521"); #else // !OPENSSL_1_1_API @@ -2058,23 +2064,33 @@ SSL/TLS: Path to file that contains client certificate used in backend client authentication. --tls-min-proto-version= - Specify minimum SSL/TLS protocol. The following - protocols are available: TLSv1.2, TLSv1.1 and TLSv1.0. - The name matching is done in case-insensitive manner. - The versions between --tls-min-proto-version and - --tls-max-proto-version are enabled. If the protocol - list advertised by client does not overlap this range, - you will receive the error message "unknown protocol". + Specify minimum SSL/TLS protocol. The name matching is + done in case-insensitive manner. The versions between + --tls-min-proto-version and --tls-max-proto-version are + enabled. If the protocol list advertised by client does + not overlap this range, you will receive the error + message "unknown protocol". The available versions are: + )" +#ifdef TLS1_3_VERSION + "TLSv1.3, " +#endif // TLS1_3_VERSION + "TLSv1.2, TLSv1.1, and TLSv1.0" + R"( Default: )" << DEFAULT_TLS_MIN_PROTO_VERSION << R"( --tls-max-proto-version= - Specify maximum SSL/TLS protocol. The following - protocols are available: TLSv1.2, TLSv1.1 and TLSv1.0. - The name matching is done in case-insensitive manner. - The versions between --tls-min-proto-version and - --tls-max-proto-version are enabled. If the protocol - list advertised by client does not overlap this range, - you will receive the error message "unknown protocol". + Specify maximum SSL/TLS protocol. The name matching is + done in case-insensitive manner. The versions between + --tls-min-proto-version and --tls-max-proto-version are + enabled. If the protocol list advertised by client does + not overlap this range, you will receive the error + message "unknown protocol". The available versions are: + )" +#ifdef TLS1_3_VERSION + "TLSv1.3, " +#endif // TLS1_3_VERSION + "TLSv1.2, TLSv1.1, and TLSv1.0" + R"( Default: )" << DEFAULT_TLS_MAX_PROTO_VERSION << R"( --tls-ticket-key-file= diff --git a/src/shrpx_ssl.cc b/src/shrpx_ssl.cc index 26379586..f648bda2 100644 --- a/src/shrpx_ssl.cc +++ b/src/shrpx_ssl.cc @@ -639,55 +639,6 @@ long int create_tls_proto_mask(const std::vector &tls_proto_list) { return res; } -#if defined(OPENSSL_IS_BORINGSSL) -namespace { -int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) { - SSL_CTX_set_min_version(ssl_ctx, min); - SSL_CTX_set_max_version(ssl_ctx, max); - return 0; -} -} // namespace -#elif OPENSSL_1_1_API -namespace { -int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) { - if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 || - SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) { - return -1; - } - return 0; -} -} // namespace -#else // !OPENSSL_1_1_API -namespace { -int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) { - long int opts = 0; - - // TODO We depends on the ordering of protocol version macro in - // OpenSSL. - if (min > TLS1_VERSION) { - opts |= SSL_OP_NO_TLSv1; - } - if (min > TLS1_1_VERSION) { - opts |= SSL_OP_NO_TLSv1_1; - } - if (min > TLS1_2_VERSION) { - opts |= SSL_OP_NO_TLSv1_2; - } - - if (max < TLS1_2_VERSION) { - opts |= SSL_OP_NO_TLSv1_2; - } - if (max < TLS1_1_VERSION) { - opts |= SSL_OP_NO_TLSv1_1; - } - - SSL_CTX_set_options(ssl_ctx, opts); - - return 0; -} -} // namespace -#endif // !OPENSSL_1_1_API - SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file, const std::vector &sct_data #ifdef HAVE_NEVERBLEED @@ -712,10 +663,9 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file, SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask); - if (ssl_ctx_set_proto_versions(ssl_ctx, tlsconf.min_proto_version, - tlsconf.max_proto_version) != 0) { - LOG(FATAL) << "Could not set TLS protocol version: " - << ERR_error_string(ERR_get_error(), nullptr); + if (nghttp2::ssl::ssl_ctx_set_proto_versions( + ssl_ctx, tlsconf.min_proto_version, tlsconf.max_proto_version) != 0) { + LOG(FATAL) << "Could not set TLS protocol version"; DIE(); } @@ -953,10 +903,9 @@ SSL_CTX *create_ssl_client_context( SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask); - if (ssl_ctx_set_proto_versions(ssl_ctx, tlsconf.min_proto_version, - tlsconf.max_proto_version) != 0) { - LOG(FATAL) << "Could not set TLS protocol version: " - << ERR_error_string(ERR_get_error(), nullptr); + if (nghttp2::ssl::ssl_ctx_set_proto_versions( + ssl_ctx, tlsconf.min_proto_version, tlsconf.max_proto_version) != 0) { + LOG(FATAL) << "Could not set TLS protocol version"; DIE(); } @@ -1742,6 +1691,11 @@ SSL_SESSION *reuse_tls_session(const TLSSessionCache &cache) { } int proto_version_from_string(const StringRef &v) { +#ifdef TLS1_3_VERSION + if (util::strieq_l("TLSv1.3", v)) { + return TLS1_3_VERSION; + } +#endif // TLS1_3_VERSION if (util::strieq_l("TLSv1.2", v)) { return TLS1_2_VERSION; } diff --git a/src/ssl.cc b/src/ssl.cc index ed7ec056..5425cb8e 100644 --- a/src/ssl.cc +++ b/src/ssl.cc @@ -83,6 +83,10 @@ const char *get_tls_protocol(SSL *ssl) { return "SSLv2"; case SSL3_VERSION: return "SSLv3"; +#ifdef TLS1_3_VERSION + case TLS1_3_VERSION: + return "TLSv1.3"; +#endif // TLS1_3_VERSION case TLS1_2_VERSION: return "TLSv1.2"; case TLS1_1_VERSION: @@ -159,6 +163,45 @@ void libssl_init() { OpenSSL_add_all_algorithms(); } +int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) { +#if OPENSSL_1_1_API + if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 || + SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) { + return -1; + } + return 0; +#elif defined(OPENSSL_IS_BORINGSSL) + SSL_CTX_set_min_version(ssl_ctx, min); + SSL_CTX_set_max_version(ssl_ctx, max); + return 0; +#else // !defined(OPENSSL_IS_BORINGSSL) + long int opts = 0; + + // TODO We depends on the ordering of protocol version macro in + // OpenSSL. + if (min > TLS1_VERSION) { + opts |= SSL_OP_NO_TLSv1; + } + if (min > TLS1_1_VERSION) { + opts |= SSL_OP_NO_TLSv1_1; + } + if (min > TLS1_2_VERSION) { + opts |= SSL_OP_NO_TLSv1_2; + } + + if (max < TLS1_2_VERSION) { + opts |= SSL_OP_NO_TLSv1_2; + } + if (max < TLS1_1_VERSION) { + opts |= SSL_OP_NO_TLSv1_1; + } + + SSL_CTX_set_options(ssl_ctx, opts); + + return 0; +#endif // !defined(OPENSSL_IS_BORINGSSL) +} + } // namespace ssl } // namespace nghttp2 diff --git a/src/ssl.h b/src/ssl.h index 2b3f232b..23c71fa9 100644 --- a/src/ssl.h +++ b/src/ssl.h @@ -49,7 +49,25 @@ public: // suites by mozilla. // // https://wiki.mozilla.org/Security/Server_Side_TLS +// +// Plus TLSv1.3 cipher suites if defined. constexpr char DEFAULT_CIPHER_LIST[] = +#ifdef TLS1_3_TXT_AES_256_GCM_SHA384 + TLS1_3_TXT_AES_256_GCM_SHA384 + ":" +#endif // TLS1_3_TXT_AES_256_GCM_SHA384 +#ifdef TLS1_3_TXT_CHACHA20_POLY1305_SHA256 + TLS1_3_TXT_CHACHA20_POLY1305_SHA256 ":" +#endif // TLS1_3_TXT_CHACHA20_POLY1305_SHA256 +#ifdef TLS1_3_TXT_AES_128_GCM_SHA256 + TLS1_3_TXT_AES_128_GCM_SHA256 ":" +#endif // TLS1_3_TXT_AES_128_GCM_SHA256 +#ifdef TLS1_3_TXT_AES_128_CCM_SHA256 + TLS1_3_TXT_AES_128_CCM_SHA256 ":" +#endif // TLS1_3_TXT_AES_128_CCM_SHA256 +#ifdef TLS1_3_TXT_AES_128_CCM_8_SHA256 + TLS1_3_TXT_AES_128_CCM_8_SHA256 ":" +#endif // TLS1_3_TXT_AES_128_CCM_8_SHA256 "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-" "AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-" "SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-" @@ -61,6 +79,13 @@ constexpr char DEFAULT_CIPHER_LIST[] = "SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-" "SHA:DES-CBC3-SHA:!DSS"; +constexpr auto NGHTTP2_TLS_MIN_VERSION = TLS1_VERSION; +#ifdef TLS1_3_VERSION +constexpr auto NGHTTP2_TLS_MAX_VERSION = TLS1_3_VERSION; +#else // !TLS1_3_VERSION +constexpr auto NGHTTP2_TLS_MAX_VERSION = TLS1_2_VERSION; +#endif // !TLS1_3_VERSION + const char *get_tls_protocol(SSL *ssl); struct TLSSessionInfo { @@ -91,6 +116,10 @@ bool check_http2_requirement(SSL *ssl); // Initializes OpenSSL library void libssl_init(); +// Sets TLS min and max versions to |ssl_ctx|. This function returns +// 0 if it succeeds, or -1. +int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max); + } // namespace ssl } // namespace nghttp2