From 8170f20ac1ba66fa23bd3cb34a304930d905aeb3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 28 Apr 2023 18:36:34 -0600 Subject: [PATCH 1/2] Add new settings to specify TLS versions to use This adds these new settings: records.yaml: proxy.config.ssl.server.version.min proxy.config.ssl.server.version.max proxy.config.ssl.client.version.min proxy.config.ssl.client.version.max sni.yaml: valid_tls_version_min_in valid_tls_version_max_in and deprecates these settings: records.yaml: proxy.config.ssl.TLSv1 proxy.config.ssl.TLSv1_1 proxy.config.ssl.TLSv1_2 proxy.config.ssl.TLSv1_3 proxy.config.ssl.client.TLSv1 proxy.config.ssl.client.TLSv1_1 proxy.config.ssl.client.TLSv1_2 proxy.config.ssl.client.TLSv1_3 sni.yaml: valid_tls_versions_in --- configs/sni.yaml.default | 4 +- doc/admin-guide/files/records.yaml.en.rst | 84 ++++++++++++++ doc/admin-guide/files/sni.yaml.en.rst | 20 +++- iocore/net/P_SNIActionPerformer.h | 20 +++- iocore/net/P_SSLConfig.h | 4 + iocore/net/P_SSLNetVConnection.h | 9 +- iocore/net/SSLClientUtils.cc | 16 +++ iocore/net/SSLConfig.cc | 102 +++++++++++----- iocore/net/SSLNetVConnection.cc | 33 ++++++ iocore/net/SSLSNIConfig.cc | 8 +- iocore/net/SSLUtils.cc | 17 ++- iocore/net/YamlSNIConfig.cc | 8 ++ iocore/net/YamlSNIConfig.h | 4 + src/records/RecordsConfig.cc | 8 ++ .../tls/tls_client_versions_minmax.test.py | 109 ++++++++++++++++++ 15 files changed, 399 insertions(+), 47 deletions(-) create mode 100644 tests/gold_tests/tls/tls_client_versions_minmax.test.py diff --git a/configs/sni.yaml.default b/configs/sni.yaml.default index 3d95c10b10f..c39363a6ef2 100644 --- a/configs/sni.yaml.default +++ b/configs/sni.yaml.default @@ -20,7 +20,9 @@ # verify_client_ca_certs - specifies an alternate set of certificate authority certs to use to verify the client cert. # host_sni_policy - sets the flag to control how policy impacting mismatches between host header and SNI values are dealt with; # parameters = one of 'DISABLED', 'PERMISSIVE', or 'ENFORCED' -# valid_tls_versions_in - sets the list of TLS protocols that will be offered to user agents during the TLS negotiation; +# valid_tls_version_min_in - sets the minimum TLS version that will be offered to user agents during the TLS negotiation; +# parameters = one of 'TLSv1', 'TLSv1_1', 'TLSv1_2', and 'TLSv1_3'. +# valid_tls_version_max_in - sets the maximum TLS version that will be offered to user agents during the TLS negotiation; # parameters = one of 'TLSv1', 'TLSv1_1', 'TLSv1_2', and 'TLSv1_3'. # client_cert - sets the client certificate to present to the server specified in dest_host; parameters = certificate file . # The location of the certificate file is relative to proxy.config.ssl.server.cert.path directory. diff --git a/doc/admin-guide/files/records.yaml.en.rst b/doc/admin-guide/files/records.yaml.en.rst index c92caca1057..79fcb755a41 100644 --- a/doc/admin-guide/files/records.yaml.en.rst +++ b/doc/admin-guide/files/records.yaml.en.rst @@ -3583,11 +3583,45 @@ SSL Termination This configuration works with OpenSSL v1.0.2 and above. +.. ts:cv:: CONFIG proxy.config.ssl.server.version.min INT -1 + + Specifies the minimum TLS version that will be offered to clients during the TLS negotiation. + + ======== =================================================================== + Value Version + ======== =================================================================== + ``0`` TLS 1.0 + ``1`` TLS 1.1 + ``2`` TLS 1.2 + ``3`` TLS 1.3 + ======== =================================================================== + +.. ts:cv:: CONFIG proxy.config.ssl.server.version.max INT -1 + + Specifies the maximum TLS version that will be offered to clients during the TLS negotiation. + + ======== =================================================================== + Value Version + ======== =================================================================== + ``0`` TLS 1.0 + ``1`` TLS 1.1 + ``2`` TLS 1.2 + ``3`` TLS 1.3 + ======== =================================================================== + .. ts:cv:: CONFIG proxy.config.ssl.TLSv1 INT 0 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1.0. If not specified, disabled by default. .. ts:cv:: CONFIG proxy.config.ssl.TLSv1_1 INT 0 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLS v1.1. If not specified, disabled by default. [Requires OpenSSL v1.0.1 and higher] @@ -3599,10 +3633,18 @@ SSL Termination .. ts:cv:: CONFIG proxy.config.ssl.TLSv1_2 INT 1 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLS v1.2. If not specified, enabled by default. [Requires OpenSSL v1.0.1 and higher] .. ts:cv:: CONFIG proxy.config.ssl.TLSv1_3 INT 1 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLS v1.3. If not specified, enabled by default. [Requires OpenSSL v1.1.1 and higher] @@ -4008,19 +4050,61 @@ Client-Related Configuration warning and return an immediate HTTP 400 response. ===== ====================================================================== +.. ts:cv:: CONFIG proxy.config.ssl.client.version.min INT -1 + + Specifies the minimum TLS version that will be offered to servers during the TLS negotiation. + + ======== =================================================================== + Value Version + ======== =================================================================== + ``0`` TLS 1.0 + ``1`` TLS 1.1 + ``2`` TLS 1.2 + ``3`` TLS 1.3 + ======== =================================================================== + +.. ts:cv:: CONFIG proxy.config.ssl.client.version.max INT -1 + + Specifies the maximum TLS version that will be offered to servers during the TLS negotiation. + + ======== =================================================================== + Value Version + ======== =================================================================== + ``0`` TLS 1.0 + ``1`` TLS 1.1 + ``2`` TLS 1.2 + ``3`` TLS 1.3 + ======== =================================================================== + .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1 INT 0 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1.0 in the ATS client context. If not specified, enabled by default .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1_1 INT 0 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1_1 in the ATS client context. If not specified, enabled by default .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1_2 INT 1 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1_2 in the ATS client context. If not specified, enabled by default .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1_3 INT 1 + :deprecated: + + This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1_3 in the ATS client context. If not specified, enabled by default diff --git a/doc/admin-guide/files/sni.yaml.en.rst b/doc/admin-guide/files/sni.yaml.en.rst index 18d5bdc98fb..3bae9627aa0 100644 --- a/doc/admin-guide/files/sni.yaml.en.rst +++ b/doc/admin-guide/files/sni.yaml.en.rst @@ -122,7 +122,25 @@ host_sni_policy Inbound One of the values :code:`DISABLED`, :code:`P which a malicious user may alter to some other server value whose policies are more lenient than the host he is trying to access. -valid_tls_versions_in Inbound This specifies the list of TLS protocols that will be offered to user agents during +valid_tls_version_min_in Inbound This specifies the minimum TLS version that will be offered to user agents during + the TLS negotiation. This replaces the global settings in + :ts:cv:`proxy.config.ssl.server.version.min`, + :ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`, + :ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The potential + values are TLSv1, TLSv1_1, TLSv1_2, and TLSv1_3. This key is only valid for OpenSSL + 1.1.0 and later and BoringSSL. Older versions of OpenSSL do not provide a hook early enough to update + the SSL object. It is a syntax error for |TS| built against earlier versions. + +valid_tls_version_max_in Inbound This specifies the minimum TLS version that will be offered to user agents during + the TLS negotiation. This replaces the global settings in + :ts:cv:`proxy.config.ssl.server.version.max`, + :ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`, + :ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The potential + values are TLSv1, TLSv1_1, TLSv1_2, and TLSv1_3. This key is only valid for OpenSSL + 1.1.0 and later and BoringSSL. Older versions of OpenSSL do not provide a hook early enough to update + the SSL object. It is a syntax error for |TS| built against earlier versions. + +valid_tls_versions_in Inbound Deprecated. This specifies the list of TLS protocols that will be offered to user agents during the TLS negotiation. This replaces the global settings in :ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`, :ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The potential diff --git a/iocore/net/P_SNIActionPerformer.h b/iocore/net/P_SNIActionPerformer.h index 4d30026ad9f..bc8e9cbff6d 100644 --- a/iocore/net/P_SNIActionPerformer.h +++ b/iocore/net/P_SNIActionPerformer.h @@ -332,6 +332,8 @@ class TLSValidProtocols : public ActionItem { bool unset = true; unsigned long protocol_mask; + int min_ver = -1; + int max_ver = -1; public: #ifdef SSL_OP_NO_TLSv1_3 @@ -341,15 +343,25 @@ class TLSValidProtocols : public ActionItem #endif TLSValidProtocols() : protocol_mask(max_mask) {} TLSValidProtocols(unsigned long protocols) : unset(false), protocol_mask(protocols) {} + TLSValidProtocols(int min_ver, int max_ver) : unset(false), protocol_mask(0), min_ver(min_ver), max_ver(max_ver) {} int SNIAction(TLSSNISupport *snis, const Context & /* ctx */) const override { - if (!unset) { - auto ssl_vc = dynamic_cast(snis); + if (this->min_ver >= 0 || this->max_ver >= 0) { const char *servername = snis->get_sni_server_name(); - Debug("ssl_sni", "TLSValidProtocol param 0%x, fqdn [%s]", static_cast(this->protocol_mask), servername); - ssl_vc->set_valid_tls_protocols(protocol_mask, TLSValidProtocols::max_mask); + Debug("ssl_sni", "TLSValidProtocol min=%d, max=%d, fqdn [%s]", this->min_ver, this->max_ver, servername); + auto ssl_vc = dynamic_cast(snis); + ssl_vc->set_valid_tls_version_min(this->min_ver); + ssl_vc->set_valid_tls_version_max(this->max_ver); + } else { + if (!unset) { + auto ssl_vc = dynamic_cast(snis); + const char *servername = snis->get_sni_server_name(); + Debug("ssl_sni", "TLSValidProtocol param 0%x, fqdn [%s]", static_cast(this->protocol_mask), servername); + ssl_vc->set_valid_tls_protocols(protocol_mask, TLSValidProtocols::max_mask); + Warning("valid_tls_versions_in is deprecated. Use valid_tls_version_min_in and ivalid_tls_version_max_in instead."); + } } return SSL_TLSEXT_ERR_OK; diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h index c28fe0d36bf..aa9c1f9e7fa 100644 --- a/iocore/net/P_SSLConfig.h +++ b/iocore/net/P_SSLConfig.h @@ -111,6 +111,10 @@ struct SSLConfigParams : public ConfigInfo { char *client_tls13_cipher_suites; char *server_groups_list; char *client_groups_list; + int server_tls_ver_min; + int server_tls_ver_max; + int client_tls_ver_min; + int client_tls_ver_max; char *keylog_file; diff --git a/iocore/net/P_SSLNetVConnection.h b/iocore/net/P_SSLNetVConnection.h index 6fcacdf7204..e2f1dcca600 100644 --- a/iocore/net/P_SSLNetVConnection.h +++ b/iocore/net/P_SSLNetVConnection.h @@ -389,12 +389,9 @@ class SSLNetVConnection : public UnixNetVConnection, return _ca_cert_dir.get(); } - void - set_valid_tls_protocols(unsigned long proto_mask, unsigned long max_mask) - { - SSL_set_options(this->ssl, proto_mask); - SSL_clear_options(this->ssl, max_mask & ~proto_mask); - } + void set_valid_tls_protocols(unsigned long proto_mask, unsigned long max_mask); + void set_valid_tls_version_min(int min); + void set_valid_tls_version_max(int max); protected: SSL * diff --git a/iocore/net/SSLClientUtils.cc b/iocore/net/SSLClientUtils.cc index ceb9a8cb735..5c1843bba68 100644 --- a/iocore/net/SSLClientUtils.cc +++ b/iocore/net/SSLClientUtils.cc @@ -204,6 +204,22 @@ SSLInitClientContext(const SSLConfigParams *params) } } + if (params->client_tls_ver_min >= 0 || params->client_tls_ver_max >= 0) { + int ver = 0; + if (params->client_tls_ver_min >= 0) { + ver = TLS1_VERSION + params->client_tls_ver_min; + } + // Setting 0 enables version down to the lowest version supported by the SSL library + SSL_CTX_set_min_proto_version(client_ctx, ver); + + ver = 0; + if (params->client_tls_ver_max >= 0) { + ver = TLS1_VERSION + params->client_tls_ver_max; + } + // Setting 0 enables version up to the highest version supported by the SSL library + SSL_CTX_set_max_proto_version(client_ctx, ver); + } + #if TS_USE_TLS_SET_CIPHERSUITES if (params->client_tls13_cipher_suites != nullptr) { if (!SSL_CTX_set_ciphersuites(client_ctx, params->client_tls13_cipher_suites)) { diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc index 3de6cf6f9a7..17b351256e8 100644 --- a/iocore/net/SSLConfig.cc +++ b/iocore/net/SSLConfig.cc @@ -280,47 +280,85 @@ SSLConfigParams::initialize() int option = 0; - REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1"); - if (!option) { - ssl_ctx_options |= SSL_OP_NO_TLSv1; - } + REC_ReadConfigInteger(client_tls_ver_min, "proxy.config.ssl.client.version.min"); + REC_ReadConfigInteger(client_tls_ver_max, "proxy.config.ssl.client.version.max"); + if (client_tls_ver_min < 0 || client_tls_ver_max < 0) { + REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1"); + if (!option) { + ssl_client_ctx_options |= SSL_OP_NO_TLSv1; + } else { + // This is disabled by default. It it's used if it's enabled. + Warning("proxy.config.ssl.client.TLSv1 is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } - REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1"); - if (!option) { - ssl_client_ctx_options |= SSL_OP_NO_TLSv1; - } + REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_1"); + if (!option) { + ssl_client_ctx_options |= SSL_OP_NO_TLSv1_1; + } else { + // This is disabled by default. It it's used if it's enabled. + Warning("proxy.config.ssl.client.TLSv1_1 is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } - REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_1"); - if (!option) { - ssl_ctx_options |= SSL_OP_NO_TLSv1_1; - } + REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_2"); + if (!option) { + ssl_client_ctx_options |= SSL_OP_NO_TLSv1_2; + // This is enabled by default. It it's used if it's disabled. + Warning("proxy.config.ssl.client.TLSv1_2 is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } - REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_1"); - if (!option) { - ssl_client_ctx_options |= SSL_OP_NO_TLSv1_1; +#ifdef SSL_OP_NO_TLSv1_3 + REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_3.enabled"); + if (!option) { + ssl_client_ctx_options |= SSL_OP_NO_TLSv1_3; + // This is enabled by default. It it's used if it's disabled. + Warning("proxy.config.ssl.client.TLSv1_3.enabled is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } +#endif } - REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_2"); - if (!option) { - ssl_ctx_options |= SSL_OP_NO_TLSv1_2; - } + REC_ReadConfigInteger(server_tls_ver_min, "proxy.config.ssl.server.version.min"); + REC_ReadConfigInteger(server_tls_ver_max, "proxy.config.ssl.server.version.max"); + if (server_tls_ver_min < 0 || server_tls_ver_max < 0) { + REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1"); + if (!option) { + ssl_ctx_options |= SSL_OP_NO_TLSv1; + } else { + // This is disabled by default. It it's used if it's enabled. + Warning("proxy.config.ssl.client.TLSv1 is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } - REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_2"); - if (!option) { - ssl_client_ctx_options |= SSL_OP_NO_TLSv1_2; - } + REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_1"); + if (!option) { + ssl_ctx_options |= SSL_OP_NO_TLSv1_1; + } else { + // This is disabled by default. It it's used if it's enabled. + Warning("proxy.config.ssl.client.TLSv1_1 is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } -#ifdef SSL_OP_NO_TLSv1_3 - REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_3.enabled"); - if (!option) { - ssl_ctx_options |= SSL_OP_NO_TLSv1_3; - } + REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_2"); + if (!option) { + ssl_ctx_options |= SSL_OP_NO_TLSv1_2; + // This is enabled by default. It it's used if it's disabled. + Warning("proxy.config.ssl.client.TLSv1_2 is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } - REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_3.enabled"); - if (!option) { - ssl_client_ctx_options |= SSL_OP_NO_TLSv1_3; - } +#ifdef SSL_OP_NO_TLSv1_3 + REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_3.enabled"); + if (!option) { + ssl_ctx_options |= SSL_OP_NO_TLSv1_3; + // This is enabled by default. It it's used if it's disabled. + Warning("proxy.config.ssl.client.TLSv1_3.enabled is deprecated. Use proxy.config.ssl.client.version.min and " + "proxy.config.ssl.client.version.max instead."); + } #endif + } // Read in the protocol string for ALPN to origin char *clientALPNProtocols = nullptr; diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc index 57e49c4aff1..bcb6b493966 100644 --- a/iocore/net/SSLNetVConnection.cc +++ b/iocore/net/SSLNetVConnection.cc @@ -2456,3 +2456,36 @@ SSLNetVConnection::_ssl_read_buffer(void *buf, int64_t nbytes, int64_t &nread) return ssl_error; } + +void +SSLNetVConnection::set_valid_tls_protocols(unsigned long proto_mask, unsigned long max_mask) +{ + SSL_set_options(this->ssl, proto_mask); + SSL_clear_options(this->ssl, max_mask & ~proto_mask); +} + +void +SSLNetVConnection::set_valid_tls_version_min(int min) +{ + // Ignore available versions set by SSL_(CTX_)set_options if a ragne is specified + SSL_clear_options(this->ssl, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3); + + int ver = 0; + if (min >= 0) { + ver = TLS1_VERSION + min; + } + SSL_set_min_proto_version(this->ssl, ver); +} + +void +SSLNetVConnection::set_valid_tls_version_max(int max) +{ + // Ignore available versions set by SSL_(CTX_)set_options if a ragne is specified + SSL_clear_options(this->ssl, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3); + + int ver = 0; + if (max >= 0) { + ver = TLS1_VERSION + max; + } + SSL_set_max_proto_version(this->ssl, ver); +} diff --git a/iocore/net/SSLSNIConfig.cc b/iocore/net/SSLSNIConfig.cc index 3ee810e5b33..5bc378df6b2 100644 --- a/iocore/net/SSLSNIConfig.cc +++ b/iocore/net/SSLSNIConfig.cc @@ -126,8 +126,12 @@ SNIConfigParams::load_sni_config() if (item.host_sni_policy != 255) { ai->actions.push_back(std::make_unique(item.host_sni_policy)); } - if (!item.protocol_unset) { - ai->actions.push_back(std::make_unique(item.protocol_mask)); + if (item.valid_tls_version_min_in >= 0 || item.valid_tls_version_max_in >= 0) { + ai->actions.push_back(std::make_unique(item.valid_tls_version_min_in, item.valid_tls_version_max_in)); + } else { + if (!item.protocol_unset) { + ai->actions.push_back(std::make_unique(item.protocol_mask)); + } } if (item.tunnel_destination.length() > 0) { ai->actions.push_back( diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index 22dc85ef53c..51a7c9924bf 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -1270,9 +1270,24 @@ SSLMultiCertConfigLoader::init_server_ssl_ctx(CertLoadData const &data, const SS Debug("ssl_load", "Creating new context %p cert_count=%ld initial: %s", ctx, cert_names_list.size(), cert_names_list[0].c_str()); - // disable selected protocols SSL_CTX_set_options(ctx, _params->ssl_ctx_options); + if (_params->server_tls_ver_min >= 0 || _params->server_tls_ver_max >= 0) { + int ver = 0; + if (_params->server_tls_ver_min >= 0) { + ver = TLS1_VERSION + _params->server_tls_ver_min; + } + // Setting 0 enables version down to the lowest version supported by the SSL library + SSL_CTX_set_min_proto_version(ctx, ver); + + ver = 0; + if (_params->server_tls_ver_max >= 0) { + ver = TLS1_VERSION + _params->server_tls_ver_max; + } + // Setting 0 enables version up to the highest version supported by the SSL library + SSL_CTX_set_max_proto_version(ctx, ver); + } + if (!this->_setup_session_cache(ctx)) { goto fail; } diff --git a/iocore/net/YamlSNIConfig.cc b/iocore/net/YamlSNIConfig.cc index 3625fa7049c..209223b8142 100644 --- a/iocore/net/YamlSNIConfig.cc +++ b/iocore/net/YamlSNIConfig.cc @@ -154,6 +154,8 @@ std::set valid_sni_config_keys = {TS_fqdn, TS_ip_allow, #if TS_USE_HELLO_CB || defined(OPENSSL_IS_BORINGSSL) TS_valid_tls_versions_in, + TS_valid_tls_version_min_in, + TS_valid_tls_version_max_in, #endif TS_host_sni_policy}; @@ -349,6 +351,12 @@ template <> struct convert { item.EnableProtocol(static_cast(protocol)); } } + if (node[TS_valid_tls_version_min_in]) { + item.valid_tls_version_min_in = TLS_PROTOCOLS_DESCRIPTOR.get(node[TS_valid_tls_version_min_in].as()); + } + if (node[TS_valid_tls_version_max_in]) { + item.valid_tls_version_max_in = TLS_PROTOCOLS_DESCRIPTOR.get(node[TS_valid_tls_version_max_in].as()); + } return true; } }; diff --git a/iocore/net/YamlSNIConfig.h b/iocore/net/YamlSNIConfig.h index b62d23e4310..fba88a56f4b 100644 --- a/iocore/net/YamlSNIConfig.h +++ b/iocore/net/YamlSNIConfig.h @@ -53,6 +53,8 @@ TSDECL(client_key); TSDECL(client_sni_policy); TSDECL(ip_allow); TSDECL(valid_tls_versions_in); +TSDECL(valid_tls_version_min_in); +TSDECL(valid_tls_version_max_in); TSDECL(http2); TSDECL(http2_buffer_water_mark); TSDECL(host_sni_policy); @@ -83,6 +85,8 @@ struct YamlSNIConfig { std::string ip_allow; bool protocol_unset = true; unsigned long protocol_mask; + int valid_tls_version_min_in = -1; + int valid_tls_version_max_in = -1; std::vector tunnel_alpn{}; std::optional http2_buffer_water_mark; diff --git a/src/records/RecordsConfig.cc b/src/records/RecordsConfig.cc index 039d5250e36..b06ba086023 100644 --- a/src/records/RecordsConfig.cc +++ b/src/records/RecordsConfig.cc @@ -1085,6 +1085,14 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.ssl.server.session_ticket.number", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}, + {RECT_CONFIG, "proxy.config.ssl.client.version.min", RECD_INT, "-1", RECU_RESTART_TS, RR_NULL, RECC_INT, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.ssl.client.version.max", RECD_INT, "-1", RECU_RESTART_TS, RR_NULL, RECC_INT, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.ssl.server.version.min", RECD_INT, "-1", RECU_RESTART_TS, RR_NULL, RECC_INT, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.ssl.server.version.max", RECD_INT, "-1", RECU_RESTART_TS, RR_NULL, RECC_INT, "^-?[0-9]+$", RECA_NULL} + , {RECT_CONFIG, "proxy.config.ssl.TLSv1", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , {RECT_CONFIG, "proxy.config.ssl.TLSv1_1", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} diff --git a/tests/gold_tests/tls/tls_client_versions_minmax.test.py b/tests/gold_tests/tls/tls_client_versions_minmax.test.py new file mode 100644 index 00000000000..e2d9a663f86 --- /dev/null +++ b/tests/gold_tests/tls/tls_client_versions_minmax.test.py @@ -0,0 +1,109 @@ +''' +''' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +Test.Summary = ''' +Test TLS protocol offering based on SNI +''' + +# By default only offer TLSv1_2 +# for special domain foo.com only offer TLSv1 and TLSv1_1 + +Test.SkipUnless( + Condition.HasOpenSSLVersion("1.1.1") +) + +# Define default ATS +ts = Test.MakeATSProcess("ts", enable_tls=True) +server = Test.MakeOriginServer("server", ssl=True) + +request_foo_header = {"headers": "GET / HTTP/1.1\r\n\r\n", "timestamp": "1469733493.993", "body": ""} +response_foo_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": "foo ok"} +server.addResponse("sessionlog.json", request_foo_header, response_foo_header) + +# add ssl materials like key, certificates for the server +ts.addSSLfile("ssl/server.pem") +ts.addSSLfile("ssl/server.key") + +# Need no remap rules. Everything should be processed by sni + +# Make sure the TS server certs are different from the origin certs +ts.Disk.ssl_multicert_config.AddLine( + 'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key' +) + +ts.Disk.records_config.update({ + 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.ssl.server.cipher_suite': 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:RC4-MD5:AES128-SHA:AES256-SHA:DES-CBC3-SHA!SRP:!DSS:!PSK:!aNULL:!eNULL:!SSLv2', + 'proxy.config.ssl.client.CA.cert.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.url_remap.pristine_host_hdr': 1, + 'proxy.config.ssl.server.version.min': 2, + 'proxy.config.ssl.server.version.max': 2, + 'proxy.config.ssl.TLSv1_2': 0, # This setting should be ignored in favor of a version range setting + 'proxy.config.exec_thread.autoconfig.scale': 1.0, + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'ssl', +}) + +# foo.com should only offer the older TLS protocols +# bar.com should terminate. +# empty SNI should tunnel to server_bar +ts.Disk.sni_yaml.AddLines([ + 'sni:', + '- fqdn: foo.com', + ' valid_tls_versions_in: [ TLSv1_2 ]', # This setting should be ignored in favor of a version range setting + ' valid_tls_version_min_in: TLSv1', + ' valid_tls_version_max_in: TLSv1_1' +]) + +# Target foo.com for TLSv1_2. Should fail +tr = Test.AddTestRun("foo.com TLSv1_2") +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(Test.Processes.ts) +tr.Processes.Default.Command = "curl -v --tls-max 1.2 --tlsv1.2 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format( + ts.Variables.ssl_port) +tr.ReturnCode = 35 +tr.StillRunningAfter = ts + +# Target foo.com for TLSv1. Should succeed +tr = Test.AddTestRun("foo.com TLSv1") +tr.Processes.Default.Command = "curl -v --tls-max 1.0 --tlsv1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format( + ts.Variables.ssl_port) +tr.ReturnCode = 0 +tr.StillRunningAfter = ts + +# Target foo.com for TLSv1_1. Should succeed +tr = Test.AddTestRun("foo.com TLSv1_1") +tr.Processes.Default.Command = "curl -v --tls-max 1.1 --tlsv1.1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format( + ts.Variables.ssl_port) +tr.ReturnCode = 0 +tr.StillRunningAfter = ts + +# Target bar.com for TLSv1. Should fail +tr = Test.AddTestRun("bar.com TLSv1") +tr.Processes.Default.Command = "curl -v --tls-max 1.0 --tlsv1 --resolve 'bar.com:{0}:127.0.0.1' -k https://bar.com:{0}".format( + ts.Variables.ssl_port) +tr.ReturnCode = 35 +tr.StillRunningAfter = ts + +# Target bar.com for TLSv1_2. Should succeed +tr = Test.AddTestRun("bar.com TLSv1_2") +tr.Processes.Default.Command = "curl -v --tls-max 1.2 --tlsv1.2 --resolve 'bar.com:{0}:127.0.0.1' -k https://bar.com:{0}".format( + ts.Variables.ssl_port) +tr.ReturnCode = 0 +tr.StillRunningAfter = ts From 2330b46935f68bec79026deb231a428d9f7acf1b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 2 May 2023 09:55:39 -0600 Subject: [PATCH 2/2] Fix typos --- doc/admin-guide/files/records.yaml.en.rst | 16 ++++++++-------- iocore/net/SSLConfig.cc | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/doc/admin-guide/files/records.yaml.en.rst b/doc/admin-guide/files/records.yaml.en.rst index 79fcb755a41..00328c3f31d 100644 --- a/doc/admin-guide/files/records.yaml.en.rst +++ b/doc/admin-guide/files/records.yaml.en.rst @@ -3612,7 +3612,7 @@ SSL Termination .. ts:cv:: CONFIG proxy.config.ssl.TLSv1 INT 0 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1.0. If not specified, disabled by default. @@ -3620,7 +3620,7 @@ SSL Termination .. ts:cv:: CONFIG proxy.config.ssl.TLSv1_1 INT 0 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLS v1.1. If not specified, disabled by default. [Requires OpenSSL v1.0.1 and higher] @@ -3635,7 +3635,7 @@ SSL Termination .. ts:cv:: CONFIG proxy.config.ssl.TLSv1_2 INT 1 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLS v1.2. If not specified, enabled by default. [Requires OpenSSL v1.0.1 and higher] @@ -3643,7 +3643,7 @@ SSL Termination .. ts:cv:: CONFIG proxy.config.ssl.TLSv1_3 INT 1 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.server.version.min` and :ts:cv:`proxy.config.ssl.server.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLS v1.3. If not specified, enabled by default. [Requires OpenSSL v1.1.1 and higher] @@ -4079,7 +4079,7 @@ Client-Related Configuration .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1 INT 0 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1.0 in the ATS client context. If not specified, enabled by default @@ -4087,7 +4087,7 @@ Client-Related Configuration .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1_1 INT 0 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1_1 in the ATS client context. If not specified, enabled by default @@ -4095,7 +4095,7 @@ Client-Related Configuration .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1_2 INT 1 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1_2 in the ATS client context. If not specified, enabled by default @@ -4103,7 +4103,7 @@ Client-Related Configuration .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1_3 INT 1 :deprecated: - This setting is depreated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and + This setting is deprecated in favor of :ts:cv:`proxy.config.ssl.client.version.min` and :ts:cv:`proxy.config.ssl.client.version.min`, and will be ignored if those new settings are used. Enables (``1``) or disables (``0``) TLSv1_3 in the ATS client context. If not specified, enabled by default diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc index 17b351256e8..7a5f4629aee 100644 --- a/iocore/net/SSLConfig.cc +++ b/iocore/net/SSLConfig.cc @@ -287,7 +287,7 @@ SSLConfigParams::initialize() if (!option) { ssl_client_ctx_options |= SSL_OP_NO_TLSv1; } else { - // This is disabled by default. It it's used if it's enabled. + // This is disabled by default. It's used if it's enabled. Warning("proxy.config.ssl.client.TLSv1 is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); } @@ -296,7 +296,7 @@ SSLConfigParams::initialize() if (!option) { ssl_client_ctx_options |= SSL_OP_NO_TLSv1_1; } else { - // This is disabled by default. It it's used if it's enabled. + // This is disabled by default. It's used if it's enabled. Warning("proxy.config.ssl.client.TLSv1_1 is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); } @@ -304,7 +304,7 @@ SSLConfigParams::initialize() REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_2"); if (!option) { ssl_client_ctx_options |= SSL_OP_NO_TLSv1_2; - // This is enabled by default. It it's used if it's disabled. + // This is enabled by default. It's used if it's disabled. Warning("proxy.config.ssl.client.TLSv1_2 is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); } @@ -313,7 +313,7 @@ SSLConfigParams::initialize() REC_ReadConfigInteger(option, "proxy.config.ssl.client.TLSv1_3.enabled"); if (!option) { ssl_client_ctx_options |= SSL_OP_NO_TLSv1_3; - // This is enabled by default. It it's used if it's disabled. + // This is enabled by default. It's used if it's disabled. Warning("proxy.config.ssl.client.TLSv1_3.enabled is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); } @@ -327,7 +327,7 @@ SSLConfigParams::initialize() if (!option) { ssl_ctx_options |= SSL_OP_NO_TLSv1; } else { - // This is disabled by default. It it's used if it's enabled. + // This is disabled by default. It's used if it's enabled. Warning("proxy.config.ssl.client.TLSv1 is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); } @@ -336,7 +336,7 @@ SSLConfigParams::initialize() if (!option) { ssl_ctx_options |= SSL_OP_NO_TLSv1_1; } else { - // This is disabled by default. It it's used if it's enabled. + // This is disabled by default. It's used if it's enabled. Warning("proxy.config.ssl.client.TLSv1_1 is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); } @@ -344,7 +344,7 @@ SSLConfigParams::initialize() REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_2"); if (!option) { ssl_ctx_options |= SSL_OP_NO_TLSv1_2; - // This is enabled by default. It it's used if it's disabled. + // This is enabled by default. It's used if it's disabled. Warning("proxy.config.ssl.client.TLSv1_2 is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); } @@ -353,7 +353,7 @@ SSLConfigParams::initialize() REC_ReadConfigInteger(option, "proxy.config.ssl.TLSv1_3.enabled"); if (!option) { ssl_ctx_options |= SSL_OP_NO_TLSv1_3; - // This is enabled by default. It it's used if it's disabled. + // This is enabled by default. It's used if it's disabled. Warning("proxy.config.ssl.client.TLSv1_3.enabled is deprecated. Use proxy.config.ssl.client.version.min and " "proxy.config.ssl.client.version.max instead."); }