This is an automated email from the ASF dual-hosted git repository. zwoop pushed a commit to branch 8.1.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 6319f29c8ff5d106ec0b68ed0c17ad2d33ec09d8 Author: Susan Hinrichs <shinr...@oath.com> AuthorDate: Wed Jan 16 20:50:27 2019 +0000 Add valid_tls_protocols_in to allow for per-domain protocols. (cherry picked from commit 34d9c4eaac536a2f27debd15326c58da91d711af) Conflicts: doc/admin-guide/files/ssl_server_name.yaml.en.rst iocore/net/SSLSNIConfig.cc iocore/net/SSLUtils.cc iocore/net/YamlSNIConfig.cc iocore/net/YamlSNIConfig.h --- build/crypto.m4 | 41 ++++++++ configure.ac | 3 + doc/admin-guide/files/ssl_server_name.yaml.en.rst | 9 ++ include/tscore/ink_config.h.in | 1 + iocore/net/P_SNIActionPerformer.h | 26 +++++ iocore/net/P_SSLNetVConnection.h | 5 +- iocore/net/P_SSLUtils.h | 1 + iocore/net/SSLSNIConfig.cc | 3 + iocore/net/SSLUtils.cc | 95 ++++++++++++++++-- iocore/net/YamlSNIConfig.cc | 52 +++++++++- iocore/net/YamlSNIConfig.h | 20 ++-- tests/gold_tests/tls/tls_client_versions.test.py | 112 ++++++++++++++++++++++ 12 files changed, 350 insertions(+), 18 deletions(-) diff --git a/build/crypto.m4 b/build/crypto.m4 index e3ac31b..248be9e 100644 --- a/build/crypto.m4 +++ b/build/crypto.m4 @@ -144,6 +144,47 @@ AC_DEFUN([TS_CHECK_CRYPTO_CERT_CB], [ AC_SUBST(use_cert_cb) ]) +AC_DEFUN([TS_CHECK_CRYPTO_HELLO_CB], [ + _hello_saved_LIBS=$LIBS + enable_hello_cb=yes + + TS_ADDTO(LIBS, [$OPENSSL_LIBS]) + AC_CHECK_HEADERS(openssl/ssl.h openssl/ts.h) + AC_CHECK_HEADERS(openssl/tls1.h, [], [], +[ #if HAVE_OPENSSL_SSL_H +#include <openssl/ssl.h> +#include <openssl/tls1.h> +#endif ]) + + AC_MSG_CHECKING([for SSL_CTX_set_client_hello_cb]) + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM([[ +#if HAVE_OPENSSL_SSL_H +#include <openssl/ssl.h> +#endif +#if HAVE_OPENSSL_TLS1_H +#include <openssl/tls1.h> +#endif + ]], + [[SSL_CTX_set_client_hello_cb(NULL, NULL, NULL);]]) + ], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + enable_hello_cb=no + ]) + + LIBS=$_hello_saved_LIBS + + AC_MSG_CHECKING(whether to enable TLS client hello callback support) + AC_MSG_RESULT([$enable_hello_cb]) + TS_ARG_ENABLE_VAR([use], [hello-cb]) + AC_SUBST(use_hello_cb) +]) + AC_DEFUN([TS_CHECK_CRYPTO_SET_RBIO], [ _rbio_saved_LIBS=$LIBS enable_set_rbio=yes diff --git a/configure.ac b/configure.ac index 0a19722..0cd0f72 100644 --- a/configure.ac +++ b/configure.ac @@ -1196,6 +1196,9 @@ TS_CHECK_CRYPTO_EC_KEYS # Check for the presense of the certificate callback in the ssl library TS_CHECK_CRYPTO_CERT_CB +# Check for the client hello callback +TS_CHECK_CRYPTO_HELLO_CB + # # Check for SSL_set0_rbio call TS_CHECK_CRYPTO_SET_RBIO diff --git a/doc/admin-guide/files/ssl_server_name.yaml.en.rst b/doc/admin-guide/files/ssl_server_name.yaml.en.rst index 4da0c0f..3778f1f 100644 --- a/doc/admin-guide/files/ssl_server_name.yaml.en.rst +++ b/doc/admin-guide/files/ssl_server_name.yaml.en.rst @@ -70,6 +70,15 @@ disable_h2 :code:`true` or :code:`false`. for proxy ports on which HTTP/2 is not enabled. tunnel_route Destination as an FQDN and port, separated by a colon ``:``. + +valid_tls_versions_in This specifies the list of TLS protocols that will be offered to user agents during + the TLS negotiaton. This replaces the global settings in :ts:cv:`proxy.config.ssl.TSLv1`, + :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. You must list all protocols that |TS| should offer to the client when using + this key. This key is only valid for openssl 1.1.0 and later. 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. ======================= ============================================================================== Client verification, via ``verify_client``, correponds to setting diff --git a/include/tscore/ink_config.h.in b/include/tscore/ink_config.h.in index d8d0c56..04b1f56 100644 --- a/include/tscore/ink_config.h.in +++ b/include/tscore/ink_config.h.in @@ -73,6 +73,7 @@ #define TS_USE_TLS_ALPN @use_tls_alpn@ #define TS_USE_TLS_ASYNC @use_tls_async@ #define TS_USE_CERT_CB @use_cert_cb@ +#define TS_USE_HELLO_CB @use_hello_cb@ #define TS_USE_SET_RBIO @use_set_rbio@ #define TS_USE_GET_DH_2048_256 @use_dh_get_2048_256@ #define TS_USE_TLS_ECKEY @use_tls_eckey@ diff --git a/iocore/net/P_SNIActionPerformer.h b/iocore/net/P_SNIActionPerformer.h index c8fce5d..2385b73 100644 --- a/iocore/net/P_SNIActionPerformer.h +++ b/iocore/net/P_SNIActionPerformer.h @@ -92,6 +92,32 @@ public: } }; +class TLSValidProtocols : public ActionItem +{ + bool unset; + unsigned long protocol_mask; + +public: +#ifdef SSL_OP_NO_TLSv1_3 + static const unsigned long max_mask = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3; +#else + static const unsigned long max_mask = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; +#endif + TLSValidProtocols() : unset(true), protocol_mask(max_mask) {} + TLSValidProtocols(unsigned long protocols) : unset(false), protocol_mask(protocols) {} + int + SNIAction(Continuation *cont) override + { + if (!unset) { + auto ssl_vc = dynamic_cast<SSLNetVConnection *>(cont); + Debug("ssl_sni", "TLSValidProtocol param 0%x", static_cast<unsigned int>(this->protocol_mask)); + ssl_vc->protocol_mask_set = true; + ssl_vc->protocol_mask = protocol_mask; + } + return SSL_TLSEXT_ERR_OK; + } +}; + class SNI_IpAllow : public ActionItem { IpMap ip_map; diff --git a/iocore/net/P_SSLNetVConnection.h b/iocore/net/P_SSLNetVConnection.h index ff7a801..531abdb 100644 --- a/iocore/net/P_SSLNetVConnection.h +++ b/iocore/net/P_SSLNetVConnection.h @@ -318,7 +318,7 @@ public: ink_hrtime sslHandshakeEndTime = 0; ink_hrtime sslLastWriteTime = 0; int64_t sslTotalBytesSent = 0; - char *serverName = nullptr; + const char *serverName = nullptr; /// Set by asynchronous hooks to request a specific operation. SslVConnOp hookOpRequested = SSL_HOOK_OP_DEFAULT; @@ -327,6 +327,9 @@ public: SSLNetVConnection(const SSLNetVConnection &) = delete; SSLNetVConnection &operator=(const SSLNetVConnection &) = delete; + bool protocol_mask_set = false; + unsigned long protocol_mask; + private: std::string_view map_tls_protocol_to_tag(const char *proto_string) const; bool update_rbio(bool move_to_socket); diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h index 4f829d1..c0737b3 100644 --- a/iocore/net/P_SSLUtils.h +++ b/iocore/net/P_SSLUtils.h @@ -175,6 +175,7 @@ void SSLNetVCDetach(SSL *ssl); SSLNetVConnection *SSLNetVCAccess(const SSL *ssl); void setClientCertLevel(SSL *ssl, uint8_t certLevel); +void setTLSValidProtocols(SSL *ssl, unsigned long proto_mask, unsigned long max_mask); namespace ssl { diff --git a/iocore/net/SSLSNIConfig.cc b/iocore/net/SSLSNIConfig.cc index a0d5f5b..90e71a7 100644 --- a/iocore/net/SSLSNIConfig.cc +++ b/iocore/net/SSLSNIConfig.cc @@ -77,6 +77,9 @@ SNIConfigParams::loadSNIConfig() } else { sni_action_map.put(ats_strdup(servername), aiVec); } + if (!item.protocol_unset) { + aiVec->push_back(new TLSValidProtocols(item.protocol_mask)); + } if (item.tunnel_destination.length()) { TunnelMap.emplace(item.fqdn.data(), item.tunnel_destination); diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index 7fe3a74..888ffee 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -46,6 +46,7 @@ #include <termios.h> #include <vector> #include "P_SNIActionPerformer.h" +#include "P_SSLSNI.h" #if HAVE_OPENSSL_EVP_H #include <openssl/evp.h> @@ -406,6 +407,72 @@ ssl_verify_client_callback(int preverify_ok, X509_STORE_CTX *ctx) return SSL_TLSEXT_ERR_OK; } +static int +PerformAction(Continuation *cont, const char *servername) +{ + SNIConfig::scoped_config params; + const actionVector *actionvec = params->get(servername); + if (!actionvec) { + Debug("ssl_sni", "%s not available in the map", servername); + } else { + for (auto &&item : *actionvec) { + auto ret = item->SNIAction(cont); + if (ret != SSL_TLSEXT_ERR_OK) { + return ret; + } + } + } + return SSL_TLSEXT_ERR_OK; +} + +#if TS_USE_HELLO_CB +// Pausable callback +static int +ssl_client_hello_callback(SSL *s, int *al, void *arg) +{ + const char *servername = nullptr; + const unsigned char *p; + size_t remaining, len; + if (SSL_client_hello_get0_ext(s, TLSEXT_TYPE_server_name, &p, &remaining) || remaining <= 2) { + // Parse to get to the name, originally from test/handshake_helper.c in openssl tree + /* Extract the length of the supplied list of names. */ + len = *(p++) << 8; + len += *(p++); + if (len + 2 == remaining) { + remaining = len; + /* + * The list in practice only has a single element, so we only consider + * the first one. + */ + if (remaining != 0 && *p++ == TLSEXT_NAMETYPE_host_name) { + remaining--; + /* Now we can finally pull out the byte array with the actual hostname. */ + if (remaining > 2) { + len = *(p++) << 8; + len += *(p++); + if (len + 2 <= remaining) { + remaining = len; + servername = reinterpret_cast<const char *>(p); + } + } + } + } + } + + SSLNetVConnection *netvc = SSLNetVCAccess(s); + + netvc->serverName = servername ? servername : ""; + int ret = PerformAction(netvc, netvc->serverName); + if (ret != SSL_TLSEXT_ERR_OK) { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + if (netvc->protocol_mask_set) { + setTLSValidProtocols(s, netvc->protocol_mask, TLSValidProtocols::max_mask); + } + return 1; +} +#endif + // Use the certificate callback for openssl 1.0.2 and greater // otherwise use the SNI callback #if TS_USE_CERT_CB @@ -448,17 +515,19 @@ extern SNIActionPerformer sni_action_performer; static int ssl_servername_only_callback(SSL *ssl, int * /* ad */, void * /*arg*/) { - int ret = SSL_TLSEXT_ERR_OK; SSLNetVConnection *netvc = SSLNetVCAccess(ssl); - const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - Debug("ssl", "Requested servername is %s", servername); - if (servername != nullptr) { - ret = sni_action_performer.PerformAction(netvc, servername); + netvc->callHooks(TS_EVENT_SSL_SERVERNAME); + + netvc->serverName = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if (nullptr == netvc->serverName) { + netvc->serverName = ""; } - if (ret != SSL_TLSEXT_ERR_OK) - return SSL_TLSEXT_ERR_ALERT_FATAL; - netvc->callHooks(TS_EVENT_SSL_SERVERNAME); + // Rerun the actions in case a plugin changed the server name + int ret = PerformAction(netvc, netvc->serverName); + if (ret != SSL_TLSEXT_ERR_OK) { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } return SSL_TLSEXT_ERR_OK; } @@ -1563,6 +1632,16 @@ ssl_set_handshake_callbacks(SSL_CTX *ctx) #else SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_and_cert_callback); #endif +#if TS_USE_HELLO_CB + SSL_CTX_set_client_hello_cb(ctx, ssl_client_hello_callback, nullptr); +#endif +} + +void +setTLSValidProtocols(SSL *ssl, unsigned long proto_mask, unsigned long max_mask) +{ + SSL_set_options(ssl, proto_mask); + SSL_clear_options(ssl, max_mask & ~proto_mask); } void diff --git a/iocore/net/YamlSNIConfig.cc b/iocore/net/YamlSNIConfig.cc index 6f31777..1b64a47 100644 --- a/iocore/net/YamlSNIConfig.cc +++ b/iocore/net/YamlSNIConfig.cc @@ -26,10 +26,12 @@ #include <string_view> #include <yaml-cpp/yaml.h> +#include <openssl/ssl.h> #include "tscore/Diags.h" #include "tscore/EnumDescriptor.h" #include "tsconfig/Errata.h" +#include "P_SNIActionPerformer.h" ts::Errata YamlSNIConfig::loader(const char *cfgFilename) @@ -57,8 +59,47 @@ YamlSNIConfig::loader(const char *cfgFilename) TsEnumDescriptor LEVEL_DESCRIPTOR = {{{"NONE", 0}, {"MODERATE", 1}, {"STRICT", 2}}}; -std::set<std::string> valid_sni_config_keys = { - TS_fqdn, TS_disable_H2, TS_verify_client, TS_tunnel_route, TS_verify_origin_server, TS_client_cert, TS_ip_allow}; +void +YamlSNIConfig::Item::EnableProtocol(YamlSNIConfig::TLSProtocol proto) +{ + if (proto <= YamlSNIConfig::TLSProtocol::TLS_MAX) { + if (protocol_unset) { + protocol_mask = TLSValidProtocols::max_mask; + protocol_unset = false; + } + switch (proto) { + case YamlSNIConfig::TLSProtocol::TLSv1: + protocol_mask &= ~SSL_OP_NO_TLSv1; + break; + case YamlSNIConfig::TLSProtocol::TLSv1_1: + protocol_mask &= ~SSL_OP_NO_TLSv1_1; + break; + case YamlSNIConfig::TLSProtocol::TLSv1_2: + protocol_mask &= ~SSL_OP_NO_TLSv1_2; + break; + case YamlSNIConfig::TLSProtocol::TLSv1_3: +#ifdef SSL_OP_NO_TLSv1_3 + protocol_mask &= ~SSL_OP_NO_TLSv1_3; +#endif + break; + } + } +} + +TsEnumDescriptor TLS_PROTOCOLS_DESCRIPTOR = {{{"TLSv1", 0}, {"TLSv1_1", 1}, {"TLSv1_2", 2}, {"TLSv1_3", 3}}}; + +std::set<std::string> valid_sni_config_keys = {TS_fqdn, + TS_disable_H2, + TS_verify_client, + TS_tunnel_route, + TS_verify_origin_server, + TS_client_cert, + TS_ip_allow +#if TS_USE_HELLO_CB + , + TS_valid_tls_versions_in +#endif +}; namespace YAML { @@ -112,6 +153,13 @@ template <> struct convert<YamlSNIConfig::Item> { if (node[TS_ip_allow]) { item.ip_allow = node[TS_ip_allow].as<std::string>(); } + if (node[TS_valid_tls_versions_in]) { + for (unsigned int i = 0; i < node[TS_valid_tls_versions_in].size(); i++) { + auto value = node[TS_valid_tls_versions_in][i].as<std::string>(); + int protocol = TLS_PROTOCOLS_DESCRIPTOR.get(value); + item.EnableProtocol(static_cast<YamlSNIConfig::TLSProtocol>(protocol)); + } + } return true; } }; diff --git a/iocore/net/YamlSNIConfig.h b/iocore/net/YamlSNIConfig.h index cb57d5b..7bdd619 100644 --- a/iocore/net/YamlSNIConfig.h +++ b/iocore/net/YamlSNIConfig.h @@ -26,13 +26,14 @@ #include "tsconfig/Errata.h" -constexpr char TS_fqdn[] = "fqdn"; -constexpr char TS_disable_H2[] = "disable_h2"; -constexpr char TS_verify_client[] = "verify_client"; -constexpr char TS_tunnel_route[] = "tunnel_route"; -constexpr char TS_verify_origin_server[] = "verify_origin_server"; -constexpr char TS_client_cert[] = "client_cert"; -constexpr char TS_ip_allow[] = "ip_allow"; +constexpr char TS_fqdn[] = "fqdn"; +constexpr char TS_disable_H2[] = "disable_h2"; +constexpr char TS_verify_client[] = "verify_client"; +constexpr char TS_tunnel_route[] = "tunnel_route"; +constexpr char TS_verify_origin_server[] = "verify_origin_server"; +constexpr char TS_client_cert[] = "client_cert"; +constexpr char TS_ip_allow[] = "ip_allow"; +constexpr char TS_valid_tls_versions_in[] = "valid_tls_versions_in"; const int start = 0; struct YamlSNIConfig { @@ -45,6 +46,7 @@ struct YamlSNIConfig { }; enum class Level { NONE = 0, MODERATE, STRICT }; + enum class TLSProtocol : uint8_t { TLSv1 = 0, TLSv1_1, TLSv1_2, TLSv1_3, TLS_MAX = TLSv1_3 }; YamlSNIConfig() {} @@ -56,6 +58,10 @@ struct YamlSNIConfig { uint8_t verify_origin_server = 0; std::string client_cert; std::string ip_allow; + bool protocol_unset = true; + unsigned long protocol_mask; + + void EnableProtocol(YamlSNIConfig::TLSProtocol proto); }; ts::Errata loader(const char *cfgFilename); diff --git a/tests/gold_tests/tls/tls_client_versions.test.py b/tests/gold_tests/tls/tls_client_versions.test.py new file mode 100644 index 0000000..dc83455 --- /dev/null +++ b/tests/gold_tests/tls/tls_client_versions.test.py @@ -0,0 +1,112 @@ +''' +''' +# 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. + +import os +Test.Summary = ''' +Test TLS protocol offering based on SNI +''' + +# By default only offer TLSv1_2 +# for special doman foo.com only offer TLSv1 and TLSv1_1 + +# need Curl +Test.SkipUnless( + Condition.HasProgram("curl", "Curl need to be installed on system for this test to work"), + Condition.HasOpenSSLVersion("1.1.1") +) + +# Define default ATS +ts = Test.MakeATSProcess("ts", select_ports=False) +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") + +ts.Variables.ssl_port = 4443 + +# Need no remap rules. Everything should be proccessed by ssl_server_name + +# 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.diags.debug.enabled': 0, + 'proxy.config.diags.debug.tags': 'http|ssl', + 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir), + # enable ssl port + 'proxy.config.http.server_ports': '{0} {1}:proto=http2;http:ssl'.format(ts.Variables.port, ts.Variables.ssl_port), + '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.TLSv1': 0, + 'proxy.config.ssl.TLSv1_1': 0, + 'proxy.config.ssl.TLSv1_2': 1 +}) + +# foo.com should only offer the older TLS protocols +# bar.com should terminate. +# empty SNI should tunnel to server_bar +ts.Disk.ssl_server_name_yaml.AddLines([ + '- fqdn: foo.com', + ' valid_tls_versions_in: [ TLSv1, 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, ready=When.PortOpen(ts.Variables.ssl_port)) +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 +tr.Processes.Default.TimeOut = 5 +tr.TimeOut = 5 +tr.Processes.Default.Streams.All += Testers.ContainsExpression("ssl_choose_client_version:unsupported protocol", "Should not allow TLSv1_2") + +# 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 +tr.Processes.Default.TimeOut = 5 +tr.TimeOut = 5 + +# 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 +tr.Processes.Default.TimeOut = 5 +tr.Processes.Default.Streams.All += Testers.ContainsExpression("alert protocol version", "Should not allow TLSv1_0") +tr.TimeOut = 5 + +# 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 +tr.Processes.Default.TimeOut = 5 +tr.TimeOut = 5 +