You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by sh...@apache.org on 2017/01/06 16:53:04 UTC

[trafficserver] branch master updated: TS-5022: Allow multiple client cert for ATS

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

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

The following commit(s) were added to refs/heads/master by this push:
       new  63b924e   TS-5022: Allow multiple client cert for ATS
63b924e is described below

commit 63b924e8bb56ffe6730a52ee151ac1566bfe6e4f
Author: Persia Aziz <pe...@yahoo-inc.com>
AuthorDate: Mon Nov 14 11:51:27 2016 -0600

    TS-5022: Allow multiple client cert for ATS
---
 iocore/net/I_NetVConnection.h                    | 18 ++++-
 iocore/net/P_SSLConfig.h                         | 13 ++++
 iocore/net/P_SSLNetProcessor.h                   |  9 +--
 iocore/net/P_UnixNetVConnection.h                |  3 +-
 iocore/net/SSLConfig.cc                          | 95 +++++++++++++++++++++++-
 iocore/net/SSLNetProcessor.cc                    | 14 +---
 iocore/net/SSLNetVConnection.cc                  | 17 ++++-
 lib/ts/Map.h                                     |  2 +-
 lib/ts/apidefs.h.in                              |  2 +
 plugins/experimental/ts_lua/ts_lua_http_config.c |  4 +
 proxy/InkAPI.cc                                  | 24 ++++++
 proxy/InkAPITest.cc                              |  2 +
 proxy/http/HttpConfig.cc                         |  4 +
 proxy/http/HttpConfig.h                          |  6 +-
 proxy/http/HttpSM.cc                             | 19 ++++-
 15 files changed, 203 insertions(+), 29 deletions(-)

diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h
index ba6d149..c772557 100644
--- a/iocore/net/I_NetVConnection.h
+++ b/iocore/net/I_NetVConnection.h
@@ -178,6 +178,10 @@ struct NetVCOptions {
    */
   ats_scoped_str sni_servername;
 
+  /**
+   * Client certificate to use in response to OS's certificate request
+   */
+  ats_scoped_str clientCertificate;
   /// Reset all values to defaults.
   void reset();
 
@@ -202,17 +206,29 @@ struct NetVCOptions {
     }
     return *this;
   }
+  self &
+  set_client_certname(const char *name)
+  {
+    clientCertificate = ats_strdup(name);
+    // clientCertificate = name;
+    return *this;
+  }
 
   self &
   operator=(self const &that)
   {
     if (&that != this) {
-      sni_servername = nullptr; // release any current name.
+      sni_servername    = nullptr; // release any current name.
+      clientCertificate = nullptr;
       memcpy(this, &that, sizeof(self));
       if (that.sni_servername) {
         sni_servername.release(); // otherwise we'll free the source string.
         this->sni_servername = ats_strdup(that.sni_servername);
       }
+      if (that.clientCertificate) {
+        clientCertificate.release();
+        this->clientCertificate = ats_strdup(that.clientCertificate);
+      }
     }
     return *this;
   }
diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h
index 621f570..2977464 100644
--- a/iocore/net/P_SSLConfig.h
+++ b/iocore/net/P_SSLConfig.h
@@ -113,6 +113,19 @@ struct SSLConfigParams : public ConfigInfo {
   static init_ssl_ctx_func init_ssl_ctx_cb;
   static load_ssl_file_func load_ssl_file_cb;
 
+  SSL_CTX *client_ctx;
+
+  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();
+  bool InsertCTX(cchar *client_cert, SSL_CTX *cctx) const;
+  SSL_CTX *getClientSSL_CTX(void) const;
+  SSL_CTX *getNewCTX(char *client_cert) const;
+
   void initialize();
   void cleanup();
   void reset();
diff --git a/iocore/net/P_SSLNetProcessor.h b/iocore/net/P_SSLNetProcessor.h
index cdc11bc..12ed7b3 100644
--- a/iocore/net/P_SSLNetProcessor.h
+++ b/iocore/net/P_SSLNetProcessor.h
@@ -42,6 +42,7 @@
 #include "P_Net.h"
 #include "P_SSLConfig.h"
 #include <openssl/ssl.h>
+#include "ts/Map.h"
 
 class UnixNetVConnection;
 struct NetAccept;
@@ -57,17 +58,9 @@ public:
 
   void cleanup(void);
 
-  SSL_CTX *
-  getClientSSL_CTX(void) const
-  {
-    return client_ctx;
-  }
-
   SSLNetProcessor();
   virtual ~SSLNetProcessor();
 
-  SSL_CTX *client_ctx;
-
   //
   // Private
   //
diff --git a/iocore/net/P_UnixNetVConnection.h b/iocore/net/P_UnixNetVConnection.h
index f2d4065..0fa1411 100644
--- a/iocore/net/P_UnixNetVConnection.h
+++ b/iocore/net/P_UnixNetVConnection.h
@@ -66,7 +66,8 @@ NetVCOptions::reset()
 
   etype = ET_NET;
 
-  sni_servername = nullptr;
+  sni_servername    = nullptr;
+  clientCertificate = nullptr;
 }
 
 TS_INLINE void
diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc
index bada78d..66b2977 100644
--- a/iocore/net/SSLConfig.cc
+++ b/iocore/net/SSLConfig.cc
@@ -73,12 +73,14 @@ static ConfigUpdateHandler<SSLCertificateConfig> *sslCertUpdate;
 
 SSLConfigParams::SSLConfigParams()
 {
+  ink_mutex_init(&ctxMapLock, "Context List Lock");
   reset();
 }
 
 SSLConfigParams::~SSLConfigParams()
 {
   cleanup();
+  ink_mutex_destroy(&ctxMapLock);
 }
 
 void
@@ -88,7 +90,7 @@ SSLConfigParams::reset()
     clientKeyPath = clientCACertFilename = clientCACertPath = cipherSuite = client_cipherSuite = dhparamsFile = serverKeyPathOnly =
       ticket_key_filename                                                                                     = nullptr;
   default_global_keyblock                                                                                     = nullptr;
-
+  client_ctx                                                                                                  = nullptr;
   clientCertLevel = client_verify_depth = verify_depth = clientVerify = 0;
   ssl_ctx_options                                                     = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
   ssl_client_ctx_protocols                                            = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
@@ -120,6 +122,8 @@ SSLConfigParams::cleanup()
   ssl_wire_trace_ip       = (IpAddr *)ats_free_null(ssl_wire_trace_ip);
   ticket_key_filename     = (char *)ats_free_null(ticket_key_filename);
   ticket_block_free(default_global_keyblock);
+  freeCTXmap();
+  SSLReleaseContext(client_ctx);
   reset();
 }
 
@@ -341,6 +345,95 @@ SSLConfigParams::initialize()
     ssl_wire_trace_percentage  = 0;
     ssl_wire_trace_server_name = nullptr;
   }
+  // Enable client regardless of config file settings as remap file
+  // can cause HTTP layer to connect using SSL. But only if SSL
+  // initialization hasn't failed already.
+  client_ctx = SSLInitClientContext(this);
+  if (!client_ctx) {
+    SSLError("Can't initialize the SSL client, HTTPS in remap rules will not function");
+  }
+
+  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()
+{
+  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", 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(char *client_cert) const
+{
+  SSL_CTX *nclient_ctx = nullptr;
+  nclient_ctx          = SSLInitClientContext(this);
+  if (!nclient_ctx) {
+    SSLError("Can't initialize the SSL client, HTTPS in remap rules will not function");
+  }
+  if (nclient_ctx && client_cert != nullptr) {
+    if (!SSL_CTX_use_certificate_chain_file(nclient_ctx, (const char *)client_cert)) {
+      SSLError("failed to load client certificate from %s", this->clientCertPath);
+      goto fail;
+    }
+  }
+  return nclient_ctx;
+fail:
+  SSLReleaseContext(nclient_ctx);
+  ::exit(1);
+}
+
+void
+SSLConfigParams::deleteKey(cchar *key) const
+{
+  SSL_CTX_free((SSL_CTX *)ctx_map.get(key));
+}
+
+SSL_CTX *
+SSLConfigParams::getClientSSL_CTX(void) const
+{
+  return client_ctx;
 }
 
 void
diff --git a/iocore/net/SSLNetProcessor.cc b/iocore/net/SSLNetProcessor.cc
index 7e3edd7..1aa942d 100644
--- a/iocore/net/SSLNetProcessor.cc
+++ b/iocore/net/SSLNetProcessor.cc
@@ -51,8 +51,6 @@ struct OCSPContinuation : public Continuation {
 void
 SSLNetProcessor::cleanup(void)
 {
-  SSLReleaseContext(client_ctx);
-  client_ctx = nullptr;
 }
 
 int
@@ -66,15 +64,7 @@ SSLNetProcessor::start(int, size_t stacksize)
     return -1;
 
   // Acquire a SSLConfigParams instance *after* we start SSL up.
-  SSLConfig::scoped_config params;
-
-  // Enable client regardless of config file settings as remap file
-  // can cause HTTP layer to connect using SSL. But only if SSL
-  // initialization hasn't failed already.
-  client_ctx = SSLInitClientContext(params);
-  if (!client_ctx) {
-    SSLError("Can't initialize the SSL client, HTTPS in remap rules will not function");
-  }
+  // SSLConfig::scoped_config params;
 
   // Initialize SSL statistics. This depends on an initial set of certificates being loaded above.
   SSLInitializeStatistics();
@@ -113,7 +103,7 @@ SSLNetProcessor::allocate_vc(EThread *t)
   return vc;
 }
 
-SSLNetProcessor::SSLNetProcessor() : client_ctx(nullptr)
+SSLNetProcessor::SSLNetProcessor()
 {
 }
 
diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index 7f50231..5ad895b 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -924,7 +924,7 @@ SSLNetVConnection::sslStartHandShake(int event, int &err)
     // net_activity will not be triggered until after the handshake
     set_inactivity_timeout(HRTIME_SECONDS(SSLConfigParams::ssl_handshake_timeout_in));
   }
-
+  SSLConfig::scoped_config params;
   switch (event) {
   case SSL_EVENT_SERVER:
     if (this->ssl == nullptr) {
@@ -980,7 +980,20 @@ SSLNetVConnection::sslStartHandShake(int event, int &err)
 
   case SSL_EVENT_CLIENT:
     if (this->ssl == nullptr) {
-      this->ssl = make_ssl_connection(ssl_NetProcessor.client_ctx, this);
+      SSL_CTX *clientCTX = nullptr;
+      if (this->options.clientCertificate) {
+        const char *certfile = (const char *)this->options.clientCertificate;
+        if (certfile != nullptr) {
+          clientCTX = params->getCTX(certfile);
+          if (clientCTX != nullptr)
+            Debug("ssl", "context for %s is found at %p", this->options.clientCertificate.get(), (void *)clientCTX);
+          else
+            Debug("ssl", "failed to find context for %s", this->options.clientCertificate.get());
+        }
+      } else {
+        clientCTX = params->client_ctx;
+      }
+      this->ssl = make_ssl_connection(clientCTX, this);
 
       if (this->ssl == nullptr) {
         SSLErrorVC(this, "failed to create SSL client session");
diff --git a/lib/ts/Map.h b/lib/ts/Map.h
index 4147fc5..e142591 100644
--- a/lib/ts/Map.h
+++ b/lib/ts/Map.h
@@ -353,7 +353,7 @@ template <class K, class C, class A>
 inline void
 Map<K, C, A>::get_keys(Vec<K> &keys)
 {
-  for (int i = 0; i < n; i++)
+  for (size_t i = 0; i < n; i++)
     if (v[i].key)
       keys.add(v[i].key);
 }
diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
index 141c279..3b6f58b 100644
--- a/lib/ts/apidefs.h.in
+++ b/lib/ts/apidefs.h.in
@@ -742,6 +742,8 @@ typedef enum {
   TS_CONFIG_HTTP_TRANSACTION_ACTIVE_TIMEOUT_IN,
   TS_CONFIG_SRV_ENABLED,
   TS_CONFIG_HTTP_FORWARD_CONNECT_METHOD,
+  TS_CONFIG_SSL_CERT_FILENAME,
+  TS_CONFIG_SSL_CERT_FILEPATH,
   TS_CONFIG_LAST_ENTRY
 } TSOverridableConfigKey;
 
diff --git a/plugins/experimental/ts_lua/ts_lua_http_config.c b/plugins/experimental/ts_lua/ts_lua_http_config.c
index 5de9081..de0ca0e 100644
--- a/plugins/experimental/ts_lua/ts_lua_http_config.c
+++ b/plugins/experimental/ts_lua/ts_lua_http_config.c
@@ -121,6 +121,8 @@ typedef enum {
   TS_LUA_CONFIG_LAST_ENTRY                                    = TS_CONFIG_LAST_ENTRY,
   TS_LUA_CONFIG_SRV_ENABLED                                   = TS_CONFIG_SRV_ENABLED,
   TS_LUA_CONFIG_HTTP_FORWARD_CONNECT_METHOD                   = TS_CONFIG_HTTP_FORWARD_CONNECT_METHOD,
+  TS_LUA_CONFIG_SSL_CERT_FILENAME                             = TS_CONFIG_SSL_CERT_FILENAME,
+  TS_LUA_CONFIG_SSL_CERT_FILEPATH                             = TS_CONFIG_SSL_CERT_FILEPATH,
 } TSLuaOverridableConfigKey;
 
 typedef enum {
@@ -232,6 +234,8 @@ ts_lua_var_item ts_lua_http_config_vars[] = {
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_TRANSACTION_ACTIVE_TIMEOUT_IN),
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_SRV_ENABLED),
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_FORWARD_CONNECT_METHOD),
+  TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_SSL_CERT_FILENAME),
+  TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_SSL_CERT_FILEPATH),
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_LAST_ENTRY),
 };
 
diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc
index be8d845..6cc2770 100644
--- a/proxy/InkAPI.cc
+++ b/proxy/InkAPI.cc
@@ -8140,6 +8140,14 @@ _conf_to_memberp(TSOverridableConfigKey conf, OverridableHttpConfigParams *overr
     typ = OVERRIDABLE_TYPE_INT;
     ret = &overridableHttpConfig->forward_connect_method;
     break;
+  case TS_CONFIG_SSL_CERT_FILENAME:
+    typ = OVERRIDABLE_TYPE_STRING;
+    ret = &overridableHttpConfig->client_cert_filename;
+    break;
+  case TS_CONFIG_SSL_CERT_FILEPATH:
+    typ = OVERRIDABLE_TYPE_STRING;
+    ret = &overridableHttpConfig->client_cert_filepath;
+    break;
   // This helps avoiding compiler warnings, yet detect unhandled enum members.
   case TS_CONFIG_NULL:
   case TS_CONFIG_LAST_ENTRY:
@@ -8299,6 +8307,15 @@ TSHttpTxnConfigStringSet(TSHttpTxn txnp, TSOverridableConfigKey conf, const char
       s->t_state.txn_conf->body_factory_template_base_len = 0;
     }
     break;
+  case TS_CONFIG_SSL_CERT_FILENAME:
+    if (value && length > 0) {
+      s->t_state.txn_conf->client_cert_filename = const_cast<char *>(value);
+    }
+    break;
+  case TS_CONFIG_SSL_CERT_FILEPATH:
+    if (value && length > 0) {
+      s->t_state.txn_conf->client_cert_filepath = const_cast<char *>(value);
+    }
   default:
     return TS_ERROR;
     break;
@@ -8378,6 +8395,9 @@ TSHttpTxnConfigFind(const char *name, int length, TSOverridableConfigKey *conf,
   case 33:
     if (!strncmp(name, "proxy.config.http.cache.fuzz.time", length)) {
       cnf = TS_CONFIG_HTTP_CACHE_FUZZ_TIME;
+    } else if (!strncmp(name, "proxy.config.ssl.client.cert.path", length)) {
+      cnf = TS_CONFIG_SSL_CERT_FILEPATH;
+      typ = TS_RECORDDATATYPE_STRING;
     }
     break;
 
@@ -8440,8 +8460,12 @@ TSHttpTxnConfigFind(const char *name, int length, TSOverridableConfigKey *conf,
         cnf = TS_CONFIG_HTTP_CACHE_FUZZ_MIN_TIME;
       } else if (!strncmp(name, "proxy.config.http.default_buffer_size", length)) {
         cnf = TS_CONFIG_HTTP_DEFAULT_BUFFER_SIZE;
+      } else if (!strncmp(name, "proxy.config.ssl.client.cert.filename", length)) {
+        cnf = TS_CONFIG_SSL_CERT_FILENAME;
+        typ = TS_RECORDDATATYPE_STRING;
       }
       break;
+
     case 'r':
       if (!strncmp(name, "proxy.config.http.response_server_str", length)) {
         cnf = TS_CONFIG_HTTP_RESPONSE_SERVER_STR;
diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index f4defcb..b00bd95 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -7618,6 +7618,8 @@ const char *SDK_Overridable_Configs[TS_CONFIG_LAST_ENTRY] = {
   "proxy.config.http.transaction_active_timeout_in",
   "proxy.config.srv_enabled",
   "proxy.config.http.forward_connect_method",
+  "proxy.config.ssl.client.cert.filename",
+  "proxy.config.ssl.client.cert.path",
 };
 
 REGRESSION_TEST(SDK_API_OVERRIDABLE_CONFIGS)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc
index 7709fcf..763f6ba 100644
--- a/proxy/http/HttpConfig.cc
+++ b/proxy/http/HttpConfig.cc
@@ -915,6 +915,8 @@ 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;
@@ -1402,6 +1404,8 @@ 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);
 
   // Local Manager
   params->synthetic_port = m_master.synthetic_port;
diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h
index 2b068c3..cc75710 100644
--- a/proxy/http/HttpConfig.h
+++ b/proxy/http/HttpConfig.h
@@ -469,7 +469,9 @@ struct OverridableHttpConfigParams {
       global_user_agent_header_size(0),
       cache_heuristic_lm_factor(0.10),
       freshness_fuzz_prob(0.005),
-      background_fill_threshold(0.5)
+      background_fill_threshold(0.5),
+      client_cert_filename(NULL),
+      client_cert_filepath(NULL)
   {
   }
 
@@ -681,6 +683,8 @@ struct OverridableHttpConfigParams {
   MgmtFloat cache_heuristic_lm_factor;
   MgmtFloat freshness_fuzz_prob;
   MgmtFloat background_fill_threshold;
+  char *client_cert_filename;
+  char *client_cert_filepath;
 };
 
 /////////////////////////////////////////////////////////////
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index 3a59065..0f72b42 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -39,13 +39,15 @@
 #include "RemapProcessor.h"
 #include "Transform.h"
 #include "P_SSLConfig.h"
-
+#include <openssl/ossl_typ.h>
+#include <openssl/ssl.h>
 #include "HttpPages.h"
 
 #include "IPAllow.h"
 //#include "I_Auth.h"
 //#include "HttpAuthParams.h"
 #include "congest/Congestion.h"
+#include "ts/I_Layout.h"
 
 #define DEFAULT_RESPONSE_BUFFER_SIZE_INDEX 6 // 8K
 #define DEFAULT_REQUEST_BUFFER_SIZE_INDEX 6  // 8K
@@ -4018,7 +4020,7 @@ HttpSM::do_remap_request(bool run_inline)
 {
   DebugSM("http_seq", "[HttpSM::do_remap_request] Remapping request");
   DebugSM("url_rewrite", "Starting a possible remapping for request [%" PRId64 "]", sm_id);
-
+  SSLConfig::scoped_config params;
   bool ret = false;
   if (t_state.cop_test_page == false) {
     ret = remapProcessor.setup_for_remap(&t_state);
@@ -4059,6 +4061,16 @@ HttpSM::do_remap_request(bool run_inline)
     pending_action = remap_action_handle;
   }
 
+  // check if the overridden client cert filename is already attached to an existing ssl context
+  ats_scoped_str clientCert(Layout::relative_to(t_state.txn_conf->client_cert_filepath, t_state.txn_conf->client_cert_filename));
+  auto tCTX = params->getCTX(clientCert);
+
+  if (tCTX == nullptr) {
+    // make new client ctx and add it to the ctx list
+    auto tctx = params->getNewCTX(clientCert);
+    params->InsertCTX(clientCert, tctx);
+  }
+
   return;
 }
 
@@ -5034,6 +5046,9 @@ HttpSM::do_http_server_open(bool raw)
       opt.set_sni_servername(host, len);
     }
 
+    ats_scoped_str clientCert(
+      ats_strdup((Layout::relative_to(t_state.txn_conf->client_cert_filepath, t_state.txn_conf->client_cert_filename))));
+    opt.set_client_certname(clientCert);
     connect_action_handle = sslNetProcessor.connect_re(this,                                 // state machine
                                                        &t_state.current.server->dst_addr.sa, // addr + port
                                                        &opt);

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].