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 4904954  Clean up client certificate specification and add tests
4904954 is described below

commit 490495431f1f11e9e52cff12df54d51115cef2c0
Author: Susan Hinrichs <shinr...@oath.com>
AuthorDate: Fri Oct 19 14:30:49 2018 +0000

    Clean up client certificate specification and add tests
---
 doc/admin-guide/files/records.config.en.rst       |   1 -
 doc/admin-guide/files/ssl_server_name.yaml.en.rst |   9 +
 iocore/net/P_SSLConfig.h                          |   7 +-
 iocore/net/SSLConfig.cc                           |  70 +-----
 iocore/net/SSLSNIConfig.cc                        |   8 +-
 iocore/net/YamlSNIConfig.cc                       |  16 +-
 iocore/net/YamlSNIConfig.h                        |   3 +-
 proxy/http/HttpConfig.cc                          |   4 -
 proxy/http/HttpSM.cc                              |  17 --
 tests/gold_tests/autest-site/microserver.test.ext |  15 +-
 tests/gold_tests/tls/ssl/signed2-bar.pem          |  21 ++
 tests/gold_tests/tls/ssl/signed2-foo.pem          |  21 ++
 tests/gold_tests/tls/ssl/signer2.key              |  28 +++
 tests/gold_tests/tls/ssl/signer2.pem              |  23 ++
 tests/gold_tests/tls/tls_client_cert.test.py      | 254 ++++++++++++++++++++++
 tests/tools/microServer/uWServer.py               |  14 +-
 16 files changed, 409 insertions(+), 102 deletions(-)

diff --git a/doc/admin-guide/files/records.config.en.rst 
b/doc/admin-guide/files/records.config.en.rst
index 9742709..152bf73 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -3497,7 +3497,6 @@ Client-Related Configuration
    :2: The provided certificate will be verified and the connection will be 
established 
 
 .. ts:cv:: CONFIG proxy.config.ssl.client.cert.filename STRING NULL
-   :overridable:
 
    The filename of SSL client certificate installed on |TS|.
 
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 2169d8a..32ab6af 100644
--- a/doc/admin-guide/files/ssl_server_name.yaml.en.rst
+++ b/doc/admin-guide/files/ssl_server_name.yaml.en.rst
@@ -75,6 +75,15 @@ client_cert               The file containing the client 
certificate to use for
                           :ts:cv:`proxy.config.ssl.server.cert.path`. If not 
set
                           :ts:cv:`proxy.config.ssl.client.cert.filename` is 
used.
 
+client_key                The file containing the client private key that 
corresponds to the certificate
+                          for the outbound connection.
+
+                          If this is relative it is relative to the path in
+                          :ts:cv:`proxy.config.ssl.server.private_key.path`. 
If not set,
+                          |TS| tries to use a private key in client_cert.  
Otherwise, 
+                          
:ts:cv:`proxy.config.ssl.client.private_key.filename` is used.
+
+
 disable_h2                :code:`true` or :code:`false`.
 
                           If :code:`false` then HTTP/2 is removed from
diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h
index 152a6bb..5ea0c95 100644
--- a/iocore/net/P_SSLConfig.h
+++ b/iocore/net/P_SSLConfig.h
@@ -126,13 +126,8 @@ struct SSLConfigParams : public ConfigInfo {
   mutable HashMap<cchar *, class StringHashFns, SSL_CTX *> ctx_map;
   mutable ink_mutex ctxMapLock;
 
-  SSL_CTX *getCTX(cchar *client_cert) const;
-  void deleteKey(cchar *key) const;
-  void freeCTXmap() const;
-  void printCTXmap() const;
-  bool InsertCTX(cchar *client_cert, SSL_CTX *cctx) const;
   SSL_CTX *getClientSSL_CTX(void) const;
-  SSL_CTX *getNewCTX(cchar *client_cert) const;
+  SSL_CTX *getNewCTX(cchar *client_cert, cchar *key_file) const;
 
   void initialize();
   void cleanup();
diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc
index 6291a2a..f2290c9 100644
--- a/iocore/net/SSLConfig.cc
+++ b/iocore/net/SSLConfig.cc
@@ -137,7 +137,6 @@ SSLConfigParams::cleanup()
   server_groups_list         = (char *)ats_free_null(server_groups_list);
   client_groups_list         = (char *)ats_free_null(client_groups_list);
 
-  freeCTXmap();
   SSLReleaseContext(client_ctx);
   reset();
 }
@@ -456,62 +455,12 @@ SSLConfigParams::initialize()
   client_ctx = SSLInitClientContext(this);
   if (!client_ctx) {
     SSLError("Can't initialize the SSL client, HTTPS in remap rules will not 
function");
-  } else {
-    InsertCTX(this->clientCertPath, this->client_ctx);
   }
 }
 
-// getCTX: returns the context attached to the given certificate
-SSL_CTX *
-SSLConfigParams::getCTX(cchar *client_cert) const
-{
-  ink_mutex_acquire(&ctxMapLock);
-  auto client_ctx = ctx_map.get(client_cert);
-  ink_mutex_release(&ctxMapLock);
-  return client_ctx;
-}
-
-// InsertCTX hashes on the absolute path to the client certificate file and 
stores in the map
-bool
-SSLConfigParams::InsertCTX(cchar *client_cert, SSL_CTX *cctx) const
-{
-  ink_mutex_acquire(&ctxMapLock);
-  // dup is required here to avoid the nullifying of the keys stored in the 
map.
-  // client_cert is coming from the overridable clientcert config retrieved by 
the remap plugin.
-  cchar *cert = ats_strdup(client_cert);
-  // Hashmap has no delete functionality :(
-  ctx_map.put(cert, cctx);
-  ink_mutex_release(&ctxMapLock);
-  return true;
-}
-
-void
-SSLConfigParams::printCTXmap() const
-{
-  Vec<cchar *> keys;
-  ctx_map.get_keys(keys);
-  for (size_t i = 0; i < keys.length(); i++) {
-    Debug("ssl", "Client certificates in the map %s: %p", keys.get(i), 
ctx_map.get(keys.get(i)));
-  }
-}
-void
-SSLConfigParams::freeCTXmap() const
-{
-  ink_mutex_acquire(&ctxMapLock);
-  Vec<cchar *> keys;
-  ctx_map.get_keys(keys);
-  size_t n = keys.length();
-  Debug("ssl", "freeing CTX Map");
-  for (size_t i = 0; i < n; i++) {
-    deleteKey(keys.get(i));
-    ats_free((char *)keys.get(i));
-  }
-  ctx_map.clear();
-  ink_mutex_release(&ctxMapLock);
-}
 // creates a new context attaching the provided certificate
 SSL_CTX *
-SSLConfigParams::getNewCTX(cchar *client_cert) const
+SSLConfigParams::getNewCTX(cchar *client_cert, cchar *client_key) const
 {
   SSL_CTX *nclient_ctx = nullptr;
   nclient_ctx          = SSLInitClientContext(this);
@@ -519,22 +468,25 @@ SSLConfigParams::getNewCTX(cchar *client_cert) const
     SSLError("Can't initialize the SSL client, HTTPS in remap rules will not 
function");
     return nullptr;
   }
-  if (nclient_ctx && client_cert != nullptr && client_cert[0] != '\0') {
+  if (client_cert != nullptr && client_cert[0] != '\0') {
     if (!SSL_CTX_use_certificate_chain_file(nclient_ctx, (const char 
*)client_cert)) {
       SSLError("failed to load client certificate from %s", 
this->clientCertPath);
       SSLReleaseContext(nclient_ctx);
       return nullptr;
     }
   }
+  // If there is not private key specified, perhaps it is in the file with the 
cert
+  if (client_key == nullptr || client_key[0] == '\0') {
+    client_key = client_cert;
+  }
+  // Try loading the private key
+  if (client_key != nullptr && client_key[0] != '\0') {
+    // If it failed, then we are just going to use the previously set private 
key from records.config
+    SSL_CTX_use_PrivateKey_file(nclient_ctx, client_key, SSL_FILETYPE_PEM);
+  }
   return nclient_ctx;
 }
 
-void
-SSLConfigParams::deleteKey(cchar *key) const
-{
-  SSL_CTX_free((SSL_CTX *)ctx_map.get(key));
-}
-
 SSL_CTX *
 SSLConfigParams::getClientSSL_CTX() const
 {
diff --git a/iocore/net/SSLSNIConfig.cc b/iocore/net/SSLSNIConfig.cc
index 14551bb..069049e 100644
--- a/iocore/net/SSLSNIConfig.cc
+++ b/iocore/net/SSLSNIConfig.cc
@@ -86,11 +86,11 @@ SNIConfigParams::loadSNIConfig()
     aiVec->push_back(ai3);
     // set the next hop properties
     SSLConfig::scoped_config params;
-    auto clientCTX  = params->getCTX(servername);
+    auto clientCTX  = params->getClientSSL_CTX();
     cchar *certFile = item.client_cert.data();
-    if (!clientCTX && certFile) {
-      clientCTX = params->getNewCTX(certFile);
-      params->InsertCTX(certFile, clientCTX);
+    cchar *keyFile  = item.client_key.data();
+    if (certFile) {
+      clientCTX = params->getNewCTX(certFile, keyFile);
     }
     NextHopProperty *nps        = new NextHopProperty();
     nps->name                   = ats_strdup(servername);
diff --git a/iocore/net/YamlSNIConfig.cc b/iocore/net/YamlSNIConfig.cc
index ce462eb..5366e4b 100644
--- a/iocore/net/YamlSNIConfig.cc
+++ b/iocore/net/YamlSNIConfig.cc
@@ -59,9 +59,16 @@ TsEnumDescriptor LEVEL_DESCRIPTOR      = {{{"NONE", 0}, 
{"MODERATE", 1}, {"STRIC
 TsEnumDescriptor POLICY_DESCRIPTOR     = {{{"DISABLED", 0}, {"PERMISSIVE", 1}, 
{"ENFORCED", 2}}};
 TsEnumDescriptor PROPERTIES_DESCRIPTOR = {{{"NONE", 0}, {"SIGNATURE", 0x1}, 
{"NAME", 0x2}, {"ALL", 0x3}}};
 
-std::set<std::string> valid_sni_config_keys = {
-  TS_fqdn,        TS_disable_H2, TS_verify_client, TS_tunnel_route, 
TS_verify_server_policy, TS_verify_server_properties,
-  TS_client_cert, TS_ip_allow};
+std::set<std::string> valid_sni_config_keys = {TS_fqdn,
+                                               TS_disable_H2,
+                                               TS_verify_client,
+                                               TS_tunnel_route,
+                                               TS_verify_origin_server,
+                                               TS_verify_server_policy,
+                                               TS_verify_server_properties,
+                                               TS_client_cert,
+                                               TS_client_key,
+                                               TS_ip_allow};
 
 namespace YAML
 {
@@ -138,6 +145,9 @@ template <> struct convert<YamlSNIConfig::Item> {
     if (node[TS_client_cert]) {
       item.client_cert = node[TS_client_cert].as<std::string>();
     }
+    if (node[TS_client_key]) {
+      item.client_key = node[TS_client_key].as<std::string>();
+    }
 
     if (node[TS_ip_allow]) {
       item.ip_allow = node[TS_ip_allow].as<std::string>();
diff --git a/iocore/net/YamlSNIConfig.h b/iocore/net/YamlSNIConfig.h
index d89fe6f..0cb6d64 100644
--- a/iocore/net/YamlSNIConfig.h
+++ b/iocore/net/YamlSNIConfig.h
@@ -35,6 +35,7 @@ TSDECL(verify_server_policy);
 TSDECL(verify_server_properties);
 TSDECL(verify_origin_server);
 TSDECL(client_cert);
+TSDECL(client_key);
 TSDECL(ip_allow);
 #undef TSDECL
 
@@ -47,7 +48,6 @@ struct YamlSNIConfig {
     verify_server_policy,     // this applies to server side vc only
     verify_server_properties, // this applies to server side vc only
     client_cert
-
   };
   enum class Level { NONE = 0, MODERATE, STRICT };
   enum class Policy : uint8_t { DISABLED = 0, PERMISSIVE, ENFORCED };
@@ -63,6 +63,7 @@ struct YamlSNIConfig {
     Policy verify_server_policy       = Policy::DISABLED;
     Property verify_server_properties = Property::NONE;
     std::string client_cert;
+    std::string client_key;
     std::string ip_allow;
   };
 
diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc
index 590fa46..13b1125 100644
--- a/proxy/http/HttpConfig.cc
+++ b/proxy/http/HttpConfig.cc
@@ -1001,8 +1001,6 @@ HttpConfig::startup()
   HttpEstablishStaticConfigByte(c.oride.insert_response_via_string, 
"proxy.config.http.insert_response_via_str");
   HttpEstablishStaticConfigLongLong(c.oride.proxy_response_hsts_max_age, 
"proxy.config.ssl.hsts_max_age");
   
HttpEstablishStaticConfigByte(c.oride.proxy_response_hsts_include_subdomains, 
"proxy.config.ssl.hsts_include_subdomains");
-  HttpEstablishStaticConfigStringAlloc(c.oride.client_cert_filename, 
"proxy.config.ssl.client.cert.filename");
-  HttpEstablishStaticConfigStringAlloc(c.oride.client_cert_filepath, 
"proxy.config.ssl.client.cert.path");
 
   HttpEstablishStaticConfigStringAlloc(c.proxy_request_via_string, 
"proxy.config.http.request_via_str");
   c.proxy_request_via_string_len = -1;
@@ -1487,8 +1485,6 @@ HttpConfig::reconfigure()
   params->redirection_host_no_port          = 
INT_TO_BOOL(m_master.redirection_host_no_port);
   params->oride.number_of_redirections      = 
m_master.oride.number_of_redirections;
   params->post_copy_size                    = m_master.post_copy_size;
-  params->oride.client_cert_filename        = 
ats_strdup(m_master.oride.client_cert_filename);
-  params->oride.client_cert_filepath        = 
ats_strdup(m_master.oride.client_cert_filepath);
   params->redirect_actions_string           = 
ats_strdup(m_master.redirect_actions_string);
   params->redirect_actions_map = 
parse_redirect_actions(params->redirect_actions_string, 
params->redirect_actions_self_action);
 
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index d339068..cf16c09 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -5015,23 +5015,6 @@ HttpSM::do_http_server_open(bool raw)
       opt.set_ssl_servername(t_state.server_info.name);
     }
 
-    SSLConfig::scoped_config params;
-    // check if the overridden client cert filename is already attached to an 
existing ssl context
-    if (t_state.txn_conf->client_cert_filepath && 
t_state.txn_conf->client_cert_filename) {
-      ats_scoped_str clientCert(
-        Layout::relative_to(t_state.txn_conf->client_cert_filepath, 
t_state.txn_conf->client_cert_filename));
-      if (clientCert != nullptr) {
-        auto tCTX = params->getCTX(clientCert);
-
-        if (tCTX == nullptr) {
-          // make new client ctx and add it to the ctx list
-          Debug("ssl", "adding new cert for client cert %s", (char 
*)clientCert);
-          auto tctx = params->getNewCTX(clientCert);
-          params->InsertCTX(clientCert, tctx);
-        }
-        opt.set_client_certname(clientCert);
-      }
-    }
     connect_action_handle = sslNetProcessor.connect_re(this,                   
              // state machine
                                                        
&t_state.current.server->dst_addr.sa, // addr + port
                                                        &opt);
diff --git a/tests/gold_tests/autest-site/microserver.test.ext 
b/tests/gold_tests/autest-site/microserver.test.ext
index 72f3178..6fe93df 100644
--- a/tests/gold_tests/autest-site/microserver.test.ext
+++ b/tests/gold_tests/autest-site/microserver.test.ext
@@ -132,13 +132,20 @@ def makeHeader(self, requestString, **kwargs):
     return headerStr
 
 
-def uServerUpAndRunning(host, port, isSsl, isIPv6):
+def uServerUpAndRunning(host, port, isSsl, isIPv6, clientcert='', 
clientkey=''):
     if isIPv6:
         plain_sock = socket.socket(socket.AF_INET6)
     else:
         plain_sock = socket.socket(socket.AF_INET)
 
-    sock = ssl.wrap_socket(plain_sock) if isSsl else plain_sock
+    if isSsl: 
+      if clientcert != '' or clientkey != '':
+        sock = ssl.wrap_socket(plain_sock, keyfile=clientkey, 
certfile=clientcert)
+      else:
+        sock = ssl.wrap_socket(plain_sock)
+    else:
+      sock = plain_sock
+
     try:
         sock.connect((host, port))
     except ConnectionRefusedError:
@@ -166,7 +173,7 @@ def uServerUpAndRunning(host, port, isSsl, isIPv6):
 AddWhenFunction(uServerUpAndRunning)
 
 
-def MakeOriginServer(obj, name, port=False, ip='INADDR_LOOPBACK', delay=False, 
ssl=False, lookup_key='{PATH}', mode='test', options={}):
+def MakeOriginServer(obj, name, port=False, ip='INADDR_LOOPBACK', delay=False, 
ssl=False, lookup_key='{PATH}', mode='test', options={}, clientcert='', 
clientkey=''):
     # to get the IP keywords in tools/lib
     sys.path.append(obj.Variables.AtsTestToolsDir)
     import lib.IPConstants as IPConstants
@@ -212,7 +219,7 @@ def MakeOriginServer(obj, name, port=False, 
ip='INADDR_LOOPBACK', delay=False, s
         "options": "skipHooks"
     })
 
-    p.Ready = When.uServerUpAndRunning(ipaddr, port, ssl, 
IPConstants.isIPv6(ip))
+    p.Ready = When.uServerUpAndRunning(ipaddr, port, ssl, 
IPConstants.isIPv6(ip), clientcert=clientcert, clientkey=clientkey)
     p.ReturnCode = Any(None, 0)
 
     return p
diff --git a/tests/gold_tests/tls/ssl/signed2-bar.pem 
b/tests/gold_tests/tls/ssl/signed2-bar.pem
new file mode 100644
index 0000000..8810238
--- /dev/null
+++ b/tests/gold_tests/tls/ssl/signed2-bar.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbjCCAlYCCQC/n10Tbs/+tzANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCSUwxEjAQBgNVBAcMCUNoYW1wYWlnbjEOMAwGA1UECgwFWWFo
+b28xGjAYBgNVBAMMEXNpZ25lcjIueWFob28uY29tMSIwIAYJKoZIhvcNAQkBFhNz
+aGlucmljaEBhcGFjaGUub3JnMB4XDTE4MTAxOTE3MzUyNVoXDTI4MTAxNjE3MzUy
+NVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRQwEgYDVQQHDAtTcHJpbmdm
+aWVsZDEQMA4GA1UECgwHRXhhbXBsZTEQMA4GA1UEAwwHYmFyLmNvbTEeMBwGCSqG
+SIb3DQEJARYPYm9iQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEA7swOnuDGaffJv17oUQGTAmqvXzOc0QQ7GOX6cd81JCcCbWWuAC5O
+gHbrKL34d7eqmCSeO0yLZzRvWZwL2EITnHGTZI/MWz8rbo+aUM7twgEfyLAQVrRv
+DtEi0RzVTpoLt23V7iXGvtyykV96hSW0XqnfTiPbxsa8SoPTT1HhqcwLlE6ZZn7P
+Du9IPJdGQSe5f9FZrAOZVA2cVTY3GnFWB3PgKbo7i8+Xa1USni8U67XOg5LD+7q7
+k+WVa1my9+YaL4sFIpboM/WQyEkJdE+nCLrPAslI7PP4iRJZ/QJ8QGfDLs+fqUNx
+v+AbGmypRB39PhmIp18YkzE9VQq/W6LWfwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
+AQA0SU1rpeJkryF7Vg/6cpUBMIrcSUGlQdut9M9jUygzer6FoEsfl/gm08KcCL17
+gXzeGX00BZ+iO9mhFcIYs9tMfVfZU8HpEpos1kRL/jIzrsTcqK9nklBenRaClpXv
+8yXKjZ5n1AOgCwH5iwZ48s65Pdk8h14jxDLYXpfHsyHPl4xqYwam0+cPYPf1YROz
+TzzKccMR3kIvGvNO+xqhx3fNrP76DeszABI9ADR6GotpFfQEg0Jjnsi+leQKh6HK
+ASZwq0NpgELBr/vQFONg5oUVcICG5TGZhswLWZD42n42N8OtegRDaL1vJ3S5yTOC
+k30i+j2hfxKHWMDJ14UB+zl1
+-----END CERTIFICATE-----
diff --git a/tests/gold_tests/tls/ssl/signed2-foo.pem 
b/tests/gold_tests/tls/ssl/signed2-foo.pem
new file mode 100644
index 0000000..7728f7a
--- /dev/null
+++ b/tests/gold_tests/tls/ssl/signed2-foo.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbDCCAlQCCQC/n10Tbs/+tjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCSUwxEjAQBgNVBAcMCUNoYW1wYWlnbjEOMAwGA1UECgwFWWFo
+b28xGjAYBgNVBAMMEXNpZ25lcjIueWFob28uY29tMSIwIAYJKoZIhvcNAQkBFhNz
+aGlucmljaEBhcGFjaGUub3JnMB4XDTE4MTAxOTE3MzQ1N1oXDTI4MTAxNjE3MzQ1
+N1owcjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFp
+Z24xEDAOBgNVBAoMB0V4YW1wbGUxEDAOBgNVBAMMB2Zvby5jb20xHjAcBgkqhkiG
+9w0BCQEWD2JvYkBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMmF46yvSjgLRBV6Wjy+JiX8iNa+SPhjpiiOc78T1PkdJ9bGRGKRFPxf
+vKqz0KWuM1xig801A/m+CXWoAh6LFSttlmSVxneQcX8xd3O5hX/+5Pdh9auw5N19
+ty7pp0e0Gv9BzTD0ZJsGmnjZkAvHONnaFlmrnVeYq9zPnn+Cb/1i+UYSvO+w/OR6
+N0fpTUYp4uoZpk6qRXs3YnjMqYnKI/PCuZH/zLuT72MMdBf4DbBrmBqIAwZ0gzxp
+NX5ew00C96ym9fJftSHDEOzDR6vQYu/iyxgKu7mEX61RyN44IfFKcKgQLjlvbMNk
+cBMsuOvsAgnnZNxKjWRNpOKsA4CIdEsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
+aCMjyADDi6VB6by8B7ho59z1AtkjcEmPptrAIr/0pZLVaBK8lYNm1jWSJvSrR851
+6KEPE/pu7fExpQiShplY3RiujWqGYJK9oQPM5/YM8BEM5RF00CYDbRnb8NMYio6+
+zAsCK8nrodTglHIlsPc2NfL56z/XfVmkZYiyTQH1qbo8jGCGIs6iyydGnyItt+sz
+hWWsYJLco69PWcLofQYDC9WFEGbTxEGRtDSO5gEC81WCbR4BhslXKhpqqGOOXxMH
+AykUdSs4DQfWAjwbezRqaktMXWNhGPjWgIsE38p9sDzr18EyX2DGr4POQYjvcNCH
+xWuVAbRPyFp8h98+wbfwqQ==
+-----END CERTIFICATE-----
diff --git a/tests/gold_tests/tls/ssl/signer2.key 
b/tests/gold_tests/tls/ssl/signer2.key
new file mode 100644
index 0000000..dea7a01
--- /dev/null
+++ b/tests/gold_tests/tls/ssl/signer2.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC/0ZxzgzZSY4rx
++GBEGYKCvUbb8sDKn5dV/HC3WbwJzlwrYZuwimAGv+In0oDpFuCsRGMe8SgpfenF
+aUS7rfnCKYzDYJJLRqzlPnyXkJCEFLeM5PocZYMA9mWw6D7dmQUbVnbkBqbs28bp
+Veq3EqSwL6nYW/vAAbu9yryoqPEcS63qFoVFZ1TZJUgCVg/9C21U1oB3JMg9sOGi
+C2EotMLRp/IVgqjYMF8jZBPdoJUARgrsYUNuq9U4Yx/BKozBJSP/an175i1+TKTb
+s+ugGYyd31opdqRY7slNMvlJFsO8LsplO/75a8tHr+phVXs3dj674h8rx6Kr4tpr
+05H9vQFVAgMBAAECggEBAJNwRHctVeXCCZyvsx7lFMH1Rq/tSW71eFdpcCIeYUCQ
+U5wsrITn96N4fhbp4JhJM2x2LFIuPxaVZ8iLf39a3Gz3jvDmG8ysiFy0yQOe5NYB
+Loynu+9zv1xQCB4QhbHC2oAG19+xlUDeNWhI197b/6ZFHKHnIfyV2H6rhJOHN7zs
+v7uSplxdtUVkof++J1b0Y1xqwusyD2Rft0irDXAiFEXH6oK4VVxCirewvIRk9h7t
+xSO+IJbqg691ayS3DgDcqy34tQAAph5UGwyFYKHO7Z1wBVXQM5YnjEr9EvHPFECf
+sMwZBJMxtKvUYMM02gl7pdETo5hwEZ/WWoutRp4f+oECgYEA+VA1v3VJwYwrvKUL
+dkw3NBR99RoI/e5F8N4KtJK+m0rWB+aboAHv5VC5DSrdzvug+4pZHpx9YC/0ZufZ
+iYjqF/es/J/uiCSfJTMS8n80UsF5oa2GQyIEuD733awBZQ1ruc4+v1WYqpSAcfOj
+bU5f93jTo/UDLLmGuMjLdWPvZvECgYEAxPakhWDcPkNmm17qt9TZ/ClqUxYEScY/
+0QWHLwOXtW00r9GFkl9vfUw9/Gqw1NusocRXa8+ihtSHlxqUDO06Ls7flqB6uuSZ
+CBYnUypE0jT1OMuD3K9FNGc1o9Y8QcSF+Nul2FzbwfQoi7Yv25EO9r/aQ/uF+Oj1
+VL27vPX6KKUCgYEA5KQ51o8zCAyL4+Kc4228RsfwSAMLcg2+GMsZmEboBTUZmn9U
+A+ci4fQo8bl5WCSOm4Fif99WYAs6odFJQIfO4BIllDz8HeEwDoaLftdH3glPigXA
+lvqwx2QAH0xqrwki3XEXPJO8gdvU/CxLmagB/MvTlI7TzYWL1xVW+h6fZJECgYEA
+jcBsO0mweGcNq3guOMtJbr9ntBA+WdICD66I0f8l6f6EUpzaIrPoiyaZ3dXzGd5X
+abzipcazU5IVW1xXfM4md5WPONqaOXNX54f6GVJsYVSXv55IckT563L0GcuPZk3H
+lYiO3R5HUlkj7RjbbIwDVvZQYWjdzHvsRGagfKgSt7kCgYAnfGCYdehHwUGhd4oI
+wOYApT7g3Zfday2oHhOXWhxe2r9Zg/lIIv32PROhT9nIhiyiWrxEMkf5imUPNcRj
+C43cyirFPseuovSiS4V12MEbCBMpl8hmoxHzjmudGKKTdEWoTcx7H6jpQGgII6KU
+8+svtuHZeHaziA8eW6dq/XjAcQ==
+-----END PRIVATE KEY-----
diff --git a/tests/gold_tests/tls/ssl/signer2.pem 
b/tests/gold_tests/tls/ssl/signer2.pem
new file mode 100644
index 0000000..36901dd
--- /dev/null
+++ b/tests/gold_tests/tls/ssl/signer2.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIJAK1jQyJPinZQMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJJTDESMBAGA1UEBwwJQ2hhbXBhaWduMQ4wDAYDVQQK
+DAVZYWhvbzEaMBgGA1UEAwwRc2lnbmVyMi55YWhvby5jb20xIjAgBgkqhkiG9w0B
+CQEWE3NoaW5yaWNoQGFwYWNoZS5vcmcwHhcNMTgxMDE5MTczMzUyWhcNMjgxMDE2
+MTczMzUyWjB+MQswCQYDVQQGEwJVUzELMAkGA1UECAwCSUwxEjAQBgNVBAcMCUNo
+YW1wYWlnbjEOMAwGA1UECgwFWWFob28xGjAYBgNVBAMMEXNpZ25lcjIueWFob28u
+Y29tMSIwIAYJKoZIhvcNAQkBFhNzaGlucmljaEBhcGFjaGUub3JnMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv9Gcc4M2UmOK8fhgRBmCgr1G2/LAyp+X
+Vfxwt1m8Cc5cK2GbsIpgBr/iJ9KA6RbgrERjHvEoKX3pxWlEu635wimMw2CSS0as
+5T58l5CQhBS3jOT6HGWDAPZlsOg+3ZkFG1Z25Aam7NvG6VXqtxKksC+p2Fv7wAG7
+vcq8qKjxHEut6haFRWdU2SVIAlYP/QttVNaAdyTIPbDhogthKLTC0afyFYKo2DBf
+I2QT3aCVAEYK7GFDbqvVOGMfwSqMwSUj/2p9e+Ytfkyk27ProBmMnd9aKXakWO7J
+TTL5SRbDvC7KZTv++WvLR6/qYVV7N3Y+u+IfK8eiq+Laa9OR/b0BVQIDAQABo1Aw
+TjAdBgNVHQ4EFgQUQbZJDhAynmvgB4Ugim8qkfTqsSIwHwYDVR0jBBgwFoAUQbZJ
+DhAynmvgB4Ugim8qkfTqsSIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AQEAhMh2BrVhhV3gcWv9sxK2TP5I//4iqnR3zxpdKMQ3z/wj2JQyagjHdLyHhyBc
+OyXZsO0WjPt5EPZxI+GpERVz6TiAW/IiiWuF2AtmNE7Kz9FouQCBHSXKGRNt6GWa
+PE5xrOfc/UhTpeDjfHPF4vmIJ7aBiHGt6xv91dLhvrCQZcf0jESS3ZCRvlouIgWW
+yKRPPIfxjJm0nwVzjmEhr1R4TVPSQRfQ8is/kYx2oRXjKuwftYlKlaj8wu0NoASs
+ZOv43f+lPei9QPKqN4Hawym6NMfJlKNBaIEqzw/8F+Td74QbCEsnf8AaZD2ccIph
+ea34ZvlNcntNiM9+4qqyS+V1IQ==
+-----END CERTIFICATE-----
diff --git a/tests/gold_tests/tls/tls_client_cert.test.py 
b/tests/gold_tests/tls/tls_client_cert.test.py
new file mode 100644
index 0000000..4ebec4a
--- /dev/null
+++ b/tests/gold_tests/tls/tls_client_cert.test.py
@@ -0,0 +1,254 @@
+'''
+Test offering client cert to origin
+'''
+#  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
+import re
+
+Test.Summary = '''
+Test different combinations of TLS handshake hooks to ensure they are applied 
consistently.
+'''
+
+Test.SkipUnless(Condition.HasProgram("grep", "grep needs to be installed on 
system for this test to work"))
+
+ts = Test.MakeATSProcess("ts", command="traffic_manager", select_ports=False)
+cafile = "{0}/signer.pem".format(Test.RunDirectory)
+cafile2 = "{0}/signer2.pem".format(Test.RunDirectory)
+server = Test.MakeOriginServer("server", ssl=True, options = { "--clientCA": 
cafile, "--clientverify": "true"}, 
clientcert="{0}/signed-foo.pem".format(Test.RunDirectory), 
clientkey="{0}/signed-foo.key".format(Test.RunDirectory))
+server2 = Test.MakeOriginServer("server2", ssl=True, options = { "--clientCA": 
cafile2, "--clientverify": "true"}, 
clientcert="{0}/signed2-bar.pem".format(Test.RunDirectory), 
clientkey="{0}/signed-bar.key".format(Test.RunDirectory))
+server.Setup.Copy("ssl/signer.pem")
+server.Setup.Copy("ssl/signer2.pem")
+server.Setup.Copy("ssl/signed-foo.pem")
+server.Setup.Copy("ssl/signed-foo.key")
+server.Setup.Copy("ssl/signed2-foo.pem")
+server.Setup.Copy("ssl/signed2-bar.pem")
+server.Setup.Copy("ssl/signed-bar.key")
+server2.Setup.Copy("ssl/signer.pem")
+server2.Setup.Copy("ssl/signer2.pem")
+server2.Setup.Copy("ssl/signed-foo.pem")
+server2.Setup.Copy("ssl/signed-foo.key")
+server2.Setup.Copy("ssl/signed2-foo.pem")
+server2.Setup.Copy("ssl/signed2-bar.pem")
+server2.Setup.Copy("ssl/signed-bar.key")
+
+request_header = {"headers": "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n", 
"timestamp": "1469733493.993", "body": ""}
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", 
"timestamp": "1469733493.993", "body": ""}
+server.addResponse("sessionlog.json", request_header, response_header)
+request_header = {"headers": "GET / HTTP/1.1\r\nHost: bar.com\r\n\r\n", 
"timestamp": "1469733493.993", "body": ""}
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", 
"timestamp": "1469733493.993", "body": ""}
+server.addResponse("sessionlog.json", request_header, response_header)
+
+ts.addSSLfile("ssl/server.pem")
+ts.addSSLfile("ssl/server.key")
+ts.addSSLfile("ssl/signed-foo.pem")
+ts.addSSLfile("ssl/signed-foo.key")
+ts.addSSLfile("ssl/signed2-foo.pem")
+ts.addSSLfile("ssl/signed-bar.pem")
+ts.addSSLfile("ssl/signed2-bar.pem")
+ts.addSSLfile("ssl/signed-bar.key")
+
+ts.Variables.ssl_port = 4443
+ts.Disk.records_config.update({
+    'proxy.config.diags.debug.enabled': 1,
+    'proxy.config.diags.debug.tags': 'ssl|http',
+    '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.http.server_ports': '{0}'.format(ts.Variables.port),
+    'proxy.config.ssl.client.verify.server':  0,
+    '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.cert.path': '{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.ssl.client.cert.filename': 'signed-foo.pem',
+    'proxy.config.ssl.client.private_key.path': 
'{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.ssl.client.private_key.filename': 'signed-foo.key',
+    'proxy.config.url_remap.pristine_host_hdr' : 1,
+})
+
+ts.Disk.ssl_multicert_config.AddLine(
+    'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+)
+
+ts.Disk.remap_config.AddLine(
+    'map /case1 https://127.0.0.1:{0}/'.format(server.Variables.Port)
+)
+ts.Disk.remap_config.AddLine(
+    'map /case2 https://127.0.0.1:{0}/'.format(server2.Variables.Port)
+)
+
+ts.Disk.ssl_server_name_yaml.AddLine(
+    '- fqdn: bar.com')
+ts.Disk.ssl_server_name_yaml.AddLine(
+    '  client_cert: {0}/signed2-bar.pem'.format(ts.Variables.SSLDir))
+ts.Disk.ssl_server_name_yaml.AddLine(
+    '  client_key: {0}/signed-bar.key'.format(ts.Variables.SSLDir))
+
+
+# Should succeed
+tr = Test.AddTestRun("Connect with first client cert to first server")
+tr.Processes.Default.StartBefore(Test.Processes.ts, 
ready=When.PortOpen(ts.Variables.port))
+tr.Processes.Default.StartBefore(server)
+tr.Processes.Default.StartBefore(server2)
+tr.StillRunningAfter = ts
+tr.StillRunningAfter = server
+tr.StillRunningAfter = server2
+tr.Processes.Default.Command = "curl -H host:example.com  
http://127.0.0.1:{0}/case1".format(ts.Variables.port)
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.TimeOut = 5
+tr.Processes.Default.Streams.stdout = Testers.ExcludesExpression("Could Not 
Connect", "Check response")
+tr.TimeOut = 5
+
+#Should fail
+trfail = Test.AddTestRun("Connect with first client cert to second server")
+trfail.StillRunningAfter = ts
+trfail.StillRunningAfter = server
+trfail.StillRunningAfter = server2
+trfail.Processes.Default.Command = 'curl -H host:example.com  
http://127.0.0.1:{0}/case2'.format(ts.Variables.port)
+trfail.Processes.Default.ReturnCode = 0
+trfail.Processes.Default.TimeOut = 5
+trfail.Processes.Default.Streams.stdout = Testers.ContainsExpression("Could 
Not Connect", "Check response")
+trfail.TimeOut = 5
+
+# Should succeed
+trbar = Test.AddTestRun("Connect with signed2 bar to second server")
+trbar.StillRunningAfter = ts
+trbar.StillRunningAfter = server
+trbar.StillRunningAfter = server2
+trbar.Processes.Default.Command = "curl -H host:bar.com  
http://127.0.0.1:{0}/case2".format(ts.Variables.port)
+trbar.Processes.Default.ReturnCode = 0
+trbar.Processes.Default.TimeOut = 5
+trbar.Processes.Default.Streams.stdout = Testers.ExcludesExpression("Could Not 
Connect", "Check response")
+trbar.TimeOut = 5
+
+#Should fail
+trbarfail = Test.AddTestRun("Connect with signed2 bar cert to first server")
+trbarfail.StillRunningAfter = ts
+trbarfail.StillRunningAfter = server
+trbarfail.StillRunningAfter = server2
+trbarfail.Processes.Default.Command = 'curl -H host:bar.com  
http://127.0.0.1:{0}/case1'.format(ts.Variables.port)
+trbarfail.Processes.Default.ReturnCode = 0
+trbarfail.Processes.Default.TimeOut = 5
+trbarfail.Processes.Default.Streams.stdout = Testers.ContainsExpression("Could 
Not Connect", "Check response")
+trbarfail.TimeOut = 5
+
+tr2 = Test.AddTestRun("Update client cert file and reload")
+# Update the SNI config
+snipath = ts.Disk.ssl_server_name_yaml.AbsPath
+tr2.Disk.File(snipath, id = "ssl_server_name_yaml", typename="ats:config"),
+tr2.Disk.ssl_server_name_yaml.AddLine(
+    '- fqdn: bar.com')
+tr2.Disk.ssl_server_name_yaml.AddLine(
+    '  client_cert: {0}/signed-bar.pem'.format(ts.Variables.SSLDir))
+tr2.Disk.ssl_server_name_yaml.AddLine(
+    '  client_key: {0}/signed-bar.key'.format(ts.Variables.SSLDir))
+tr2.StillRunningAfter = ts
+tr2.StillRunningAfter = server
+tr2.StillRunningAfter = server2
+tr2.Processes.Default.Command = 'traffic_ctl config set 
proxy.config.ssl.client.cert.filename signed2-foo.pem; traffic_ctl config 
reload'
+# Need to copy over the environment so traffic_ctl knows where to find the 
unix domain socket
+tr2.Processes.Default.Env = ts.Env
+tr2.Processes.Default.ReturnCode = 0
+tr2.Processes.Default.TimeOut = 5
+tr2.TimeOut = 5
+
+#Should succeed
+tr3bar = Test.AddTestRun("Make request with other bar cert to first server")
+# Wait for the reload to complete
+tr3bar.DelayStart = 2
+tr3bar.StillRunningAfter = ts
+tr3bar.StillRunningAfter = server
+tr3bar.StillRunningAfter = server2
+tr3bar.Processes.Default.Command = 'curl  -H host:example.com 
http://127.0.0.1:{0}/case1'.format(ts.Variables.port)
+tr3bar.Processes.Default.ReturnCode = 0
+tr3bar.Processes.Default.TimeOut = 5
+tr3bar.Processes.Default.Streams.stdout = Testers.ExcludesExpression("Could 
Not Connect", "Check response")
+tr3bar.TimeOut = 5
+
+#Should fail
+tr3barfail = Test.AddTestRun("Make request with other bar cert to second 
server")
+tr3barfail.StillRunningAfter = ts
+tr3barfail.StillRunningAfter = server
+tr3barfail.StillRunningAfter = server2
+tr3barfail.Processes.Default.Command = 'curl  -H host:example.com 
http://127.0.0.1:{0}/case2'.format(ts.Variables.port)
+tr3barfail.Processes.Default.ReturnCode = 0
+tr3barfail.Processes.Default.TimeOut = 5
+tr3barfail.Processes.Default.Streams.stdout = 
Testers.ContainsExpression("Could Not Connect", "Check response")
+tr3barfail.TimeOut = 5
+
+# Skipping the last two cases until we get the certificate settings reloadable 
from records.config
+
+#Should succeed
+#tr3 = Test.AddTestRun("Make request with other cert to second server")
+# Wait for the reload to complete
+#tr3.StillRunningAfter = ts
+#tr3.StillRunningAfter = server
+#tr3.StillRunningAfter = server2
+#tr3.Processes.Default.Command = 'curl  -H host:example.com 
http://127.0.0.1:{0}/case2'.format(ts.Variables.port)
+#tr3.Processes.Default.ReturnCode = 0
+#tr3.Processes.Default.TimeOut = 5
+#tr3.Processes.Default.Streams.stdout = Testers.ExcludesExpression("Could Not 
Connect", "Check response")
+#tr3.TimeOut = 5
+#
+#Should fail
+#tr3fail = Test.AddTestRun("Make request with other cert to first server")
+#tr3fail.StillRunningAfter = ts
+#tr3fail.StillRunningAfter = server
+#tr3fail.StillRunningAfter = server2
+#tr3fail.Processes.Default.Command = 'curl  -H host:example.com 
http://127.0.0.1:{0}/case1'.format(ts.Variables.port)
+#tr3fail.Processes.Default.ReturnCode = 0
+#tr3fail.Processes.Default.TimeOut = 5
+#tr3fail.Processes.Default.Streams.stdout = Testers.ContainsExpression("Could 
Not Connect", "Check response")
+#tr3fail.TimeOut = 5
+
+# Test the case of updating certificate contents without changing file name.
+trupdate = Test.AddTestRun("Update client cert file in place")
+trupdate.StillRunningAfter = ts
+trupdate.StillRunningAfter = server
+trupdate.StillRunningAfter = server2
+trupdate.Setup.CopyAs("ssl/signed2-bar.pem", ".", "signed-bar.pem")
+trupdate.Setup.CopyAs("ssl/signed-foo.pem", ".", 
"{0}/signed2-foo.pem".format(ts.Variables.SSLDir))
+trupdate.Processes.Default.Command = 'traffic_ctl config reload'
+# Need to copy over the environment so traffic_ctl knows where to find the 
unix domain socket
+trupdate.Processes.Default.Env = ts.Env
+trupdate.Processes.Default.ReturnCode = 0
+trupdate.Processes.Default.TimeOut = 5
+trupdate.TimeOut = 5
+
+#Should succeed
+tr3bar = Test.AddTestRun("Make request with renamed bar cert to first server")
+# Wait for the reload to complete
+tr3bar.DelayStart = 2
+tr3bar.StillRunningAfter = ts
+tr3bar.StillRunningAfter = server
+tr3bar.StillRunningAfter = server2
+tr3bar.Processes.Default.Command = 'curl  -H host:example.com 
http://127.0.0.1:{0}/case1'.format(ts.Variables.port)
+tr3bar.Processes.Default.ReturnCode = 0
+tr3bar.Processes.Default.TimeOut = 5
+tr3bar.Processes.Default.Streams.stdout = Testers.ExcludesExpression("Could 
Not Connect", "Check response")
+tr3bar.TimeOut = 5
+
+#Should fail
+tr3barfail = Test.AddTestRun("Make request with renamed bar cert to second 
server")
+tr3barfail.StillRunningAfter = ts
+tr3barfail.StillRunningAfter = server
+tr3barfail.StillRunningAfter = server2
+tr3barfail.Processes.Default.Command = 'curl  -H host:example.com 
http://127.0.0.1:{0}/case2'.format(ts.Variables.port)
+tr3barfail.Processes.Default.ReturnCode = 0
+tr3barfail.Processes.Default.TimeOut = 5
+tr3barfail.Processes.Default.Streams.stdout = 
Testers.ContainsExpression("Could Not Connect", "Check response")
+
+# Allow for error messages in diags
+ts.Disk.diags_log.Content = Testers.ContainsExpression("ERROR", "Some 
connections should fail")
diff --git a/tests/tools/microServer/uWServer.py 
b/tests/tools/microServer/uWServer.py
index 5e57536..f2dfb38 100644
--- a/tests/tools/microServer/uWServer.py
+++ b/tests/tools/microServer/uWServer.py
@@ -136,6 +136,7 @@ class SSLServer(ThreadingMixIn, HTTPServer):
         pwd = os.path.dirname(os.path.realpath(__file__))
         keys = os.path.join(pwd, options.key)
         certs = os.path.join(pwd, options.cert)
+        clientCA = os.path.join(pwd, options.clientCA)
         self.options = options
         self.hook_set = HookSet()
 
@@ -145,9 +146,11 @@ class SSLServer(ThreadingMixIn, HTTPServer):
         if options.load:
             self.hook_set.load(options.load)
 
+        print ("clientverify={0}".format(options.clientverify))
+
         if options.clientverify:
             self.socket = ssl.wrap_socket(socket.socket(self.address_family, 
self.socket_type),
-                                          keyfile=keys, certfile=certs, 
server_side=True, cert_reqs=ssl.CERT_REQUIRED, 
ca_certs='/etc/ssl/certs/ca-certificates.crt')
+                                          keyfile=keys, certfile=certs, 
server_side=True, cert_reqs=ssl.CERT_REQUIRED, ca_certs=clientCA)
         else:
             self.socket = ssl.wrap_socket(socket.socket(self.address_family, 
self.socket_type),
                                           keyfile=keys, certfile=certs, 
server_side=True)
@@ -170,6 +173,7 @@ class MyHandler(BaseHTTPRequestHandler):
         global lookup_key_
         kpath = ""
         path = ""
+        print("Request={0} lookup_key={1}".format(requestline, lookup_key_))
         url_part = requestline.split(" ")
         if url_part:
             if url_part[1].startswith("http"):
@@ -190,7 +194,6 @@ class MyHandler(BaseHTTPRequestHandler):
             argsList.append(stringk)
         KeyList = []
         for argsL in argsList:
-            print("args", argsL, len(argsL))
             if len(argsL) > 0:
                 val = self.headers.get(argsL)
                 if val:
@@ -292,6 +295,7 @@ class MyHandler(BaseHTTPRequestHandler):
         self.command = None  # set in case of error on the first line
         self.request_version = version = self.default_request_version
         self.close_connection = True
+        print("Raw request {0}".format(self.raw_requestline))
         requestline = str(self.raw_requestline, 'UTF-8')
         requestline = requestline.rstrip('\r\n')
         self.requestline = requestline
@@ -600,7 +604,7 @@ def _bool(arg):
 
 def _argparse_bool(arg):
     try:
-        _bool(arg)
+        return _bool(arg)
     except ValueError as ve:
         raise argparse.ArgumentTypeError(ve)
 
@@ -654,6 +658,10 @@ def main():
                         type=str,
                         default="ssl/server.crt",
                         help="certificate")
+    parser.add_argument("--clientCA",
+                        type=str,
+                        default="",
+                        help="CA for client certificates")
     parser.add_argument("--clientverify", "-cverify",
                         type=_argparse_bool,
                         default=False,

Reply via email to