This is an automated email from the ASF dual-hosted git repository.

shinrich pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 34d9c4e  Add valid_tls_protocols_in to allow for per-domain protocols.
34d9c4e is described below

commit 34d9c4eaac536a2f27debd15326c58da91d711af
Author: Susan Hinrichs <[email protected]>
AuthorDate: Wed Jan 16 20:50:27 2019 +0000

    Add valid_tls_protocols_in to allow for per-domain protocols.
---
 build/crypto.m4                                   |  41 ++++++++
 configure.ac                                      |   3 +
 doc/admin-guide/files/ssl_server_name.yaml.en.rst |  11 ++-
 include/tscore/ink_config.h.in                    |   1 +
 iocore/net/P_SNIActionPerformer.h                 |  26 +++++
 iocore/net/P_SSLNetVConnection.h                  |   3 +
 iocore/net/P_SSLUtils.h                           |   1 +
 iocore/net/SSLSNIConfig.cc                        |   3 +
 iocore/net/SSLUtils.cc                            |  64 ++++++++++++-
 iocore/net/YamlSNIConfig.cc                       |  50 +++++++++-
 iocore/net/YamlSNIConfig.h                        |   6 ++
 tests/gold_tests/tls/tls_client_versions.test.py  | 112 ++++++++++++++++++++++
 12 files changed, 315 insertions(+), 6 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 9600c4f..bec8ef5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1195,6 +1195,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 e95c3dd..ac8068b 100644
--- a/doc/admin-guide/files/ssl_server_name.yaml.en.rst
+++ b/doc/admin-guide/files/ssl_server_name.yaml.en.rst
@@ -71,9 +71,18 @@ verify_client             One of the values :code:`NONE`, 
:code:`MODERATE`, or :
                           fail the TLS handshake if new certificate is 
presented.  If ``STRICT`` is specified
                           the client must resent a certificate during the TLS 
handshake.
 
-
                           By default this is 
:ts:cv:`proxy.config.ssl.client.certification_level`.
 
+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_cert               The file containing the client certificate to use 
for the outbound connection.
 
                           If this is relative, it is relative to the path in
diff --git a/include/tscore/ink_config.h.in b/include/tscore/ink_config.h.in
index d6c1a54..770bd76 100644
--- a/include/tscore/ink_config.h.in
+++ b/include/tscore/ink_config.h.in
@@ -72,6 +72,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 d515fdc..f940490 100644
--- a/iocore/net/P_SNIActionPerformer.h
+++ b/iocore/net/P_SNIActionPerformer.h
@@ -115,6 +115,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) const 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 19976be..4de0038 100644
--- a/iocore/net/P_SSLNetVConnection.h
+++ b/iocore/net/P_SSLNetVConnection.h
@@ -370,6 +370,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 3d2b01a..e3ec9f6 100644
--- a/iocore/net/P_SSLUtils.h
+++ b/iocore/net/P_SSLUtils.h
@@ -177,6 +177,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 470a544..06f15cd 100644
--- a/iocore/net/SSLSNIConfig.cc
+++ b/iocore/net/SSLSNIConfig.cc
@@ -71,6 +71,9 @@ SNIConfigParams::loadSNIConfig()
     if (item.verify_client_level != 255) {
       
ai->actions.push_back(std::make_unique<VerifyClient>(item.verify_client_level));
     }
+    if (!item.protocol_unset) {
+      
ai->actions.push_back(std::make_unique<TLSValidProtocols>(item.protocol_mask));
+    }
     if (item.tunnel_destination.length() > 0) {
       
ai->actions.push_back(std::make_unique<TunnelDestination>(item.tunnel_destination,
 item.tunnel_decrypt));
     }
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 7c9fbaf..e7a6444 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -418,6 +418,57 @@ PerformAction(Continuation *cont, const char *servername)
   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->has_tunnel_destination() && !netvc->decrypt_tunnel()) {
+    netvc->attributes = HttpProxyPort::TRANSPORT_BLIND_TUNNEL;
+  }
+  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
@@ -471,6 +522,8 @@ ssl_servername_only_callback(SSL *ssl, int * /* ad */, void 
* /*arg*/)
   if (nullptr == netvc->serverName) {
     netvc->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;
@@ -478,7 +531,6 @@ ssl_servername_only_callback(SSL *ssl, int * /* ad */, void 
* /*arg*/)
   if (netvc->has_tunnel_destination() && !netvc->decrypt_tunnel()) {
     netvc->attributes = HttpProxyPort::TRANSPORT_BLIND_TUNNEL;
   }
-
   return SSL_TLSEXT_ERR_OK;
 }
 
@@ -1592,6 +1644,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 8a542cd..84e118e 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)
@@ -55,9 +57,37 @@ YamlSNIConfig::loader(const char *cfgFilename)
   return ts::Errata();
 }
 
-TsEnumDescriptor LEVEL_DESCRIPTOR      = {{{"NONE", 0}, {"MODERATE", 1}, 
{"STRICT", 2}}};
-TsEnumDescriptor POLICY_DESCRIPTOR     = {{{"DISABLED", 0}, {"PERMISSIVE", 1}, 
{"ENFORCED", 2}}};
-TsEnumDescriptor PROPERTIES_DESCRIPTOR = {{{"NONE", 0}, {"SIGNATURE", 0x1}, 
{"NAME", 0x2}, {"ALL", 0x3}}};
+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 LEVEL_DESCRIPTOR         = {{{"NONE", 0}, {"MODERATE", 1}, 
{"STRICT", 2}}};
+TsEnumDescriptor POLICY_DESCRIPTOR        = {{{"DISABLED", 0}, {"PERMISSIVE", 
1}, {"ENFORCED", 2}}};
+TsEnumDescriptor PROPERTIES_DESCRIPTOR    = {{{"NONE", 0}, {"SIGNATURE", 0x1}, 
{"NAME", 0x2}, {"ALL", 0x3}}};
+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,
@@ -69,7 +99,12 @@ std::set<std::string> valid_sni_config_keys = {TS_fqdn,
                                                TS_verify_server_properties,
                                                TS_client_cert,
                                                TS_client_key,
-                                               TS_ip_allow};
+                                               TS_ip_allow
+#if TS_USE_HELLO_CB
+                                               ,
+                                               TS_valid_tls_versions_in
+#endif
+};
 
 namespace YAML
 {
@@ -158,6 +193,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 0acf4f2..babd016 100644
--- a/iocore/net/YamlSNIConfig.h
+++ b/iocore/net/YamlSNIConfig.h
@@ -38,6 +38,7 @@ TSDECL(verify_origin_server);
 TSDECL(client_cert);
 TSDECL(client_key);
 TSDECL(ip_allow);
+TSDECL(valid_tls_versions_in);
 #undef TSDECL
 
 const int start = 0;
@@ -54,6 +55,7 @@ struct YamlSNIConfig {
   enum class Level { NONE = 0, MODERATE, STRICT };
   enum class Policy : uint8_t { DISABLED = 0, PERMISSIVE, ENFORCED, UNSET };
   enum class Property : uint8_t { NONE = 0, SIGNATURE_MASK = 0x1, NAME_MASK = 
0x2, ALL_MASK = 0x3, UNSET };
+  enum class TLSProtocol : uint8_t { TLSv1 = 0, TLSv1_1, TLSv1_2, TLSv1_3, 
TLS_MAX = TLSv1_3 };
 
   YamlSNIConfig() {}
 
@@ -68,6 +70,10 @@ struct YamlSNIConfig {
     std::string client_cert;
     std::string client_key;
     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..1855799
--- /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
+

Reply via email to