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

maskit 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 c9d557bda9 Add TLSEventSupport (#11744)
c9d557bda9 is described below

commit c9d557bda9444f89a1bd1d9f850e99f496a92efc
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Fri Sep 20 10:19:26 2024 -0600

    Add TLSEventSupport (#11744)
    
    * Add TLSEventSupport
    
    * Remove _fire_ssl_servername_event
    
    * Refactoring for Clang-Analyzer
    
    * const
---
 include/iocore/net/NetVConnection.h   |  15 +
 include/iocore/net/TLSEventSupport.h  |  89 ++++++
 include/iocore/net/TLSSNISupport.h    |   2 -
 src/api/InkAPI.cc                     |  24 +-
 src/iocore/net/CMakeLists.txt         |   1 +
 src/iocore/net/P_QUICNetVConnection.h |  23 +-
 src/iocore/net/P_SSLNetVConnection.h  | 123 ++------
 src/iocore/net/QUICNetVConnection.cc  |  35 ++-
 src/iocore/net/SSLClientUtils.cc      |   5 +-
 src/iocore/net/SSLNetVConnection.cc   | 420 +++-----------------------
 src/iocore/net/SSLUtils.cc            |  64 ++--
 src/iocore/net/TLSEventSupport.cc     | 553 ++++++++++++++++++++++++++++++++++
 src/iocore/net/TLSSNISupport.cc       |   2 -
 13 files changed, 820 insertions(+), 536 deletions(-)

diff --git a/include/iocore/net/NetVConnection.h 
b/include/iocore/net/NetVConnection.h
index a7d8bd8886..7a89a11625 100644
--- a/include/iocore/net/NetVConnection.h
+++ b/include/iocore/net/NetVConnection.h
@@ -501,6 +501,7 @@ protected:
     TLS_ALPN,
     TLS_Basic,
     TLS_CertSwitch,
+    TLS_Event,
     TLS_EarlyData,
     TLS_SNI,
     TLS_SessionResumption,
@@ -594,6 +595,20 @@ NetVConnection::_set_service(TLSBasicSupport *instance)
   this->_set_service(NetVConnection::Service::TLS_Basic, instance);
 }
 
+class TLSEventSupport;
+template <>
+inline TLSEventSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSEventSupport 
*>(this->_get_service(NetVConnection::Service::TLS_Event));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSEventSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_Event, instance);
+}
+
 class TLSEarlyDataSupport;
 template <>
 inline TLSEarlyDataSupport *
diff --git a/include/iocore/net/TLSEventSupport.h 
b/include/iocore/net/TLSEventSupport.h
new file mode 100644
index 0000000000..2e71b9c015
--- /dev/null
+++ b/include/iocore/net/TLSEventSupport.h
@@ -0,0 +1,89 @@
+/** @file
+
+  TLSEventSupport implements common methods and members to
+  support TLS related events
+
+  @section license License
+
+  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.
+ */
+
+#pragma once
+
+#include "iocore/eventsystem/Lock.h"
+
+class Continuation;
+
+class TLSEventSupport
+{
+public:
+  enum class SSLHandshakeHookState {
+    HANDSHAKE_HOOKS_PRE,
+    HANDSHAKE_HOOKS_PRE_INVOKE,
+    HANDSHAKE_HOOKS_CLIENT_HELLO,
+    HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE,
+    HANDSHAKE_HOOKS_SNI,
+    HANDSHAKE_HOOKS_CERT,
+    HANDSHAKE_HOOKS_CERT_INVOKE,
+    HANDSHAKE_HOOKS_CLIENT_CERT,
+    HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE,
+    HANDSHAKE_HOOKS_OUTBOUND_PRE,
+    HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE,
+    HANDSHAKE_HOOKS_VERIFY_SERVER,
+    HANDSHAKE_HOOKS_DONE
+  };
+
+  static char const *get_ssl_handshake_hook_state_name(SSLHandshakeHookState 
state);
+
+  virtual ~TLSEventSupport() = default;
+
+  static void             initialize();
+  static TLSEventSupport *getInstance(SSL *ssl);
+  static void             bind(SSL *ssl, TLSEventSupport *es);
+  static void             unbind(SSL *ssl);
+
+  bool                    callHooks(TSEvent eventId);
+  bool                    calledHooks(TSEvent eventId) const;
+  virtual Continuation   *getContinuationForTLSEvents() = 0;
+  virtual EThread        *getThreadForTLSEvents()       = 0;
+  virtual Ptr<ProxyMutex> getMutexForTLSEvents()        = 0;
+  virtual void            reenable(int event)           = 0;
+
+protected:
+  void clear();
+
+  SSLHandshakeHookState get_handshake_hook_state();
+  void                  set_handshake_hook_state(SSLHandshakeHookState state);
+  bool                  is_invoked_state() const;
+  int                   invoke_tls_event();
+  void                  resume_tls_event();
+
+  virtual bool _is_tunneling_requested() const = 0;
+  virtual void _switch_to_tunneling_mode()     = 0;
+
+private:
+  static int _ex_data_index;
+  SSL       *_ssl;
+
+  bool _first_handshake_hooks_pre          = true;
+  bool _first_handshake_hooks_outbound_pre = true;
+
+  /// The current hook.
+  /// @note For @C SSL_HOOKS_INVOKE, this is the hook to invoke.
+  class APIHook        *curHook               = nullptr;
+  SSLHandshakeHookState sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE;
+};
diff --git a/include/iocore/net/TLSSNISupport.h 
b/include/iocore/net/TLSSNISupport.h
index 1b35a683cf..fbba3810d5 100644
--- a/include/iocore/net/TLSSNISupport.h
+++ b/include/iocore/net/TLSSNISupport.h
@@ -82,8 +82,6 @@ public:
   } hints_from_sni;
 
 protected:
-  virtual void _fire_ssl_servername_event() = 0;
-
   virtual in_port_t _get_local_port() = 0;
 
   void _clear();
diff --git a/src/api/InkAPI.cc b/src/api/InkAPI.cc
index 83aba64917..cf957ac97f 100644
--- a/src/api/InkAPI.cc
+++ b/src/api/InkAPI.cc
@@ -7870,25 +7870,25 @@ TSHttpEventNameLookup(TSEvent event)
   return HttpDebugNames::get_event_name(static_cast<int>(event));
 }
 
-/// Re-enable SSL VC.
+/// Re-enable NetVC that has TLSEventSupport.
 class TSSslCallback : public Continuation
 {
 public:
-  TSSslCallback(SSLNetVConnection *vc, TSEvent event) : 
Continuation(vc->nh->mutex), m_vc(vc), m_event(event)
+  TSSslCallback(TLSEventSupport *tes, TSEvent event) : 
Continuation(tes->getMutexForTLSEvents().get()), m_tes(tes), m_event(event)
   {
     SET_HANDLER(&TSSslCallback::event_handler);
   }
   int
   event_handler(int /* event ATS_UNUSED */, void *)
   {
-    m_vc->reenable(m_vc->nh, m_event);
+    m_tes->reenable(m_event);
     delete this;
     return 0;
   }
 
 private:
-  SSLNetVConnection *m_vc;
-  TSEvent            m_event;
+  TLSEventSupport *m_tes;
+  TSEvent          m_event;
 };
 
 /// SSL Hooks
@@ -8372,19 +8372,19 @@ TSVConnReenable(TSVConn vconn)
 void
 TSVConnReenableEx(TSVConn vconn, TSEvent event)
 {
-  NetVConnection    *vc     = reinterpret_cast<NetVConnection *>(vconn);
-  SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(vc);
-  // We really only deal with a SSLNetVConnection at the moment
-  if (ssl_vc != nullptr) {
+  NetVConnection *vc = reinterpret_cast<NetVConnection *>(vconn);
+
+  if (auto tes = vc->get_service<TLSEventSupport>(); tes) {
     EThread *eth = this_ethread();
 
     // We use the mutex of VC's NetHandler so we can put the VC into 
ready_list by reenable()
-    MUTEX_TRY_LOCK(trylock, ssl_vc->nh->mutex, eth);
+    Ptr<ProxyMutex> m = tes->getMutexForTLSEvents();
+    MUTEX_TRY_LOCK(trylock, m, eth);
     if (trylock.is_locked()) {
-      ssl_vc->reenable(ssl_vc->nh, event);
+      tes->reenable(event);
     } else {
       // We schedule the reenable to the home thread of ssl_vc.
-      ssl_vc->thread->schedule_imm(new TSSslCallback(ssl_vc, event));
+      tes->getThreadForTLSEvents()->schedule_imm(new TSSslCallback(tes, 
event));
     }
   }
 }
diff --git a/src/iocore/net/CMakeLists.txt b/src/iocore/net/CMakeLists.txt
index 7d925af515..45371e3c8d 100644
--- a/src/iocore/net/CMakeLists.txt
+++ b/src/iocore/net/CMakeLists.txt
@@ -55,6 +55,7 @@ add_library(
   SSLUtils.cc
   OCSPStapling.cc
   TLSBasicSupport.cc
+  TLSEventSupport.cc
   TLSCertSwitchSupport.cc
   TLSEarlyDataSupport.cc
   TLSKeyLogger.cc
diff --git a/src/iocore/net/P_QUICNetVConnection.h 
b/src/iocore/net/P_QUICNetVConnection.h
index fd1ae29938..019f870eaa 100644
--- a/src/iocore/net/P_QUICNetVConnection.h
+++ b/src/iocore/net/P_QUICNetVConnection.h
@@ -43,6 +43,7 @@
 #include "P_UDPNet.h"
 #include "iocore/net/TLSALPNSupport.h"
 #include "iocore/net/TLSBasicSupport.h"
+#include "iocore/net/TLSEventSupport.h"
 #include "iocore/net/TLSSessionResumptionSupport.h"
 #include "iocore/net/TLSSNISupport.h"
 #include "iocore/net/TLSCertSwitchSupport.h"
@@ -59,6 +60,7 @@
 #include <netinet/in.h>
 #include <quiche.h>
 
+class EThread;
 class QUICPacketHandler;
 class QUICResetTokenTable;
 class QUICConnectionTable;
@@ -70,6 +72,7 @@ class QUICNetVConnection : public UnixNetVConnection,
                            public TLSSNISupport,
                            public TLSSessionResumptionSupport,
                            public TLSCertSwitchSupport,
+                           public TLSEventSupport,
                            public TLSBasicSupport,
                            public QUICSupport
 {
@@ -142,6 +145,12 @@ public:
   // QUICNetVConnection
   int in_closed_queue = 0;
 
+  // TLSEventSupport
+  void            reenable(int event) override;
+  Continuation   *getContinuationForTLSEvents() override;
+  EThread        *getThreadForTLSEvents() override;
+  Ptr<ProxyMutex> getMutexForTLSEvents() override;
+
   bool shouldDestroy();
   void destroy(EThread *t);
   void remove_connection_ids();
@@ -158,7 +167,6 @@ protected:
   ssl_curve_id _get_tls_curve() const override;
 
   // TLSSNISupport
-  void      _fire_ssl_servername_event() override;
   in_port_t _get_local_port() override;
 
   // TLSSessionResumptionSupport
@@ -169,6 +177,19 @@ protected:
   shared_SSL_CTX _lookupContextByName(const std::string &servername, 
SSLCertContextType ctxType) override;
   shared_SSL_CTX _lookupContextByIP() override;
 
+  // TLSEventSupport
+  bool
+  _is_tunneling_requested() const override
+  {
+    // FIXME Not Supported
+    return false;
+  }
+  void
+  _switch_to_tunneling_mode() override
+  {
+    // FIXME Not supported
+  }
+
 private:
   SSL                      *_ssl;
   QUICConfig::scoped_config _quic_config;
diff --git a/src/iocore/net/P_SSLNetVConnection.h 
b/src/iocore/net/P_SSLNetVConnection.h
index 0f54f75fa0..edce1e1206 100644
--- a/src/iocore/net/P_SSLNetVConnection.h
+++ b/src/iocore/net/P_SSLNetVConnection.h
@@ -43,6 +43,7 @@
 #include "iocore/net/TLSEarlyDataSupport.h"
 #include "iocore/net/TLSTunnelSupport.h"
 #include "iocore/net/TLSBasicSupport.h"
+#include "iocore/net/TLSEventSupport.h"
 #include "iocore/net/TLSCertSwitchSupport.h"
 #include "P_SSLUtils.h"
 #include "P_SSLConfig.h"
@@ -105,6 +106,7 @@ class SSLNetVConnection : public UnixNetVConnection,
                           public TLSEarlyDataSupport,
                           public TLSTunnelSupport,
                           public TLSCertSwitchSupport,
+                          public TLSEventSupport,
                           public TLSBasicSupport
 {
   typedef UnixNetVConnection super; ///< Parent type.
@@ -195,9 +197,6 @@ public:
   // Copy up here so we overload but don't override
   using super::reenable;
 
-  /// Reenable the VC after a pre-accept or SNI hook is called.
-  virtual void reenable(NetHandler *nh, int event = TS_EVENT_CONTINUE);
-
   int64_t read_raw_data();
 
   void
@@ -227,80 +226,6 @@ public:
     this->handShakeBioStored = 0;
   }
 
-  // Returns true if all the hooks reenabled
-  bool callHooks(TSEvent eventId);
-
-  // Returns true if we have already called at
-  // least some of the hooks
-  bool
-  calledHooks(TSEvent eventId) const
-  {
-    bool retval = false;
-    switch (this->sslHandshakeHookState) {
-    case HANDSHAKE_HOOKS_PRE:
-    case HANDSHAKE_HOOKS_PRE_INVOKE:
-      if (eventId == TS_EVENT_VCONN_START) {
-        if (curHook) {
-          retval = true;
-        }
-      }
-      break;
-    case HANDSHAKE_HOOKS_CLIENT_HELLO:
-    case HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
-      if (eventId == TS_EVENT_VCONN_START) {
-        retval = true;
-      } else if (eventId == TS_EVENT_SSL_CLIENT_HELLO) {
-        if (curHook) {
-          retval = true;
-        }
-      }
-      break;
-    case HANDSHAKE_HOOKS_SNI:
-      if (eventId == TS_EVENT_VCONN_START || eventId == 
TS_EVENT_SSL_CLIENT_HELLO) {
-        retval = true;
-      } else if (eventId == TS_EVENT_SSL_SERVERNAME) {
-        if (curHook) {
-          retval = true;
-        }
-      }
-      break;
-    case HANDSHAKE_HOOKS_CERT:
-    case HANDSHAKE_HOOKS_CERT_INVOKE:
-      if (eventId == TS_EVENT_VCONN_START || eventId == 
TS_EVENT_SSL_CLIENT_HELLO || eventId == TS_EVENT_SSL_SERVERNAME) {
-        retval = true;
-      } else if (eventId == TS_EVENT_SSL_CERT) {
-        if (curHook) {
-          retval = true;
-        }
-      }
-      break;
-    case HANDSHAKE_HOOKS_CLIENT_CERT:
-    case HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
-      if (eventId == TS_EVENT_SSL_VERIFY_CLIENT || eventId == 
TS_EVENT_VCONN_START) {
-        retval = true;
-      }
-      break;
-
-    case HANDSHAKE_HOOKS_OUTBOUND_PRE:
-    case HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
-      if (eventId == TS_EVENT_VCONN_OUTBOUND_START) {
-        if (curHook) {
-          retval = true;
-        }
-      }
-      break;
-
-    case HANDSHAKE_HOOKS_VERIFY_SERVER:
-      retval = (eventId == TS_EVENT_SSL_VERIFY_SERVER);
-      break;
-
-    case HANDSHAKE_HOOKS_DONE:
-      retval = true;
-      break;
-    }
-    return retval;
-  }
-
   int         populate_protocol(std::string_view *results, int n) const 
override;
   const char *protocol_contains(std::string_view tag) const override;
 
@@ -387,7 +312,15 @@ public:
     return _ca_cert_dir.get();
   }
 
+  // TLSEventSupport
+  /// Reenable the VC after a pre-accept or SNI hook is called.
+  void            reenable(int event = TS_EVENT_CONTINUE) override;
+  Continuation   *getContinuationForTLSEvents() override;
+  EThread        *getThreadForTLSEvents() override;
+  Ptr<ProxyMutex> getMutexForTLSEvents() override;
+
 protected:
+  // TLSBasicSupport
   SSL *
   _get_ssl_object() const override
   {
@@ -395,6 +328,7 @@ protected:
   }
   ssl_curve_id _get_tls_curve() const override;
 
+  // TLSSessionResumptionSupport
   const IpEndpoint &
   _getLocalEndpoint() override
   {
@@ -402,13 +336,24 @@ protected:
   }
 
   // TLSSNISupport
-  void      _fire_ssl_servername_event() override;
   in_port_t _get_local_port() override;
 
   bool           _isTryingRenegotiation() const override;
   shared_SSL_CTX _lookupContextByName(const std::string &servername, 
SSLCertContextType ctxType) override;
   shared_SSL_CTX _lookupContextByIP() override;
 
+  // TLSEventSupport
+  bool
+  _is_tunneling_requested() const override
+  {
+    return SSL_HOOK_OP_TUNNEL == hookOpRequested;
+  }
+  void
+  _switch_to_tunneling_mode() override
+  {
+    this->attributes = HttpProxyPort::TRANSPORT_BLIND_TUNNEL;
+  }
+
 private:
   std::string_view map_tls_protocol_to_tag(const char *proto_string) const;
   bool             update_rbio(bool move_to_socket);
@@ -429,28 +374,6 @@ private:
 
   int sent_cert = 0;
 
-  /// The current hook.
-  /// @note For @C SSL_HOOKS_INVOKE, this is the hook to invoke.
-  class APIHook *curHook = nullptr;
-
-  enum SSLHandshakeHookState {
-    HANDSHAKE_HOOKS_PRE,
-    HANDSHAKE_HOOKS_PRE_INVOKE,
-    HANDSHAKE_HOOKS_CLIENT_HELLO,
-    HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE,
-    HANDSHAKE_HOOKS_SNI,
-    HANDSHAKE_HOOKS_CERT,
-    HANDSHAKE_HOOKS_CERT_INVOKE,
-    HANDSHAKE_HOOKS_CLIENT_CERT,
-    HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE,
-    HANDSHAKE_HOOKS_OUTBOUND_PRE,
-    HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE,
-    HANDSHAKE_HOOKS_VERIFY_SERVER,
-    HANDSHAKE_HOOKS_DONE
-  } sslHandshakeHookState = HANDSHAKE_HOOKS_PRE;
-
-  static char const *get_ssl_handshake_hook_state_name(SSLHandshakeHookState 
state);
-
   int64_t redoWriteSize = 0;
 
   X509_STORE_CTX *verify_cert = nullptr;
diff --git a/src/iocore/net/QUICNetVConnection.cc 
b/src/iocore/net/QUICNetVConnection.cc
index d20330360e..d6c002221c 100644
--- a/src/iocore/net/QUICNetVConnection.cc
+++ b/src/iocore/net/QUICNetVConnection.cc
@@ -24,9 +24,12 @@
 #include "P_SSLUtils.h"
 #include "P_QUICNetVConnection.h"
 #include "P_QUICPacketHandler.h"
+#include "api/APIHook.h"
+#include "iocore/eventsystem/EThread.h"
 #include "iocore/net/QUICMultiCertConfigLoader.h"
 #include "iocore/net/quic/QUICStream.h"
 #include "iocore/net/quic/QUICGlobals.h"
+#include "iocore/net/SSLAPIHooks.h"
 
 #include <netinet/in.h>
 #include <quiche.h>
@@ -49,6 +52,7 @@ QUICNetVConnection::QUICNetVConnection()
 {
   this->_set_service(static_cast<ALPNSupport *>(this));
   this->_set_service(static_cast<TLSBasicSupport *>(this));
+  this->_set_service(static_cast<TLSEventSupport *>(this));
   this->_set_service(static_cast<TLSCertSwitchSupport *>(this));
   this->_set_service(static_cast<TLSSNISupport *>(this));
   this->_set_service(static_cast<TLSSessionResumptionSupport *>(this));
@@ -142,6 +146,7 @@ QUICNetVConnection::free_thread(EThread * /* t ATS_UNUSED 
*/)
   super::clear();
   ALPNSupport::clear();
   TLSBasicSupport::clear();
+  TLSEventSupport::clear();
   TLSCertSwitchSupport::_clear();
 
   this->_packet_handler->close_connection(this);
@@ -540,6 +545,7 @@ void
 QUICNetVConnection::_bindSSLObject()
 {
   TLSBasicSupport::bind(this->_ssl, this);
+  TLSEventSupport::bind(this->_ssl, this);
   ALPNSupport::bind(this->_ssl, this);
   TLSSessionResumptionSupport::bind(this->_ssl, this);
   TLSSNISupport::bind(this->_ssl, this);
@@ -551,6 +557,7 @@ void
 QUICNetVConnection::_unbindSSLObject()
 {
   TLSBasicSupport::unbind(this->_ssl);
+  TLSEventSupport::unbind(this->_ssl);
   ALPNSupport::unbind(this->_ssl);
   TLSSessionResumptionSupport::unbind(this->_ssl);
   TLSSNISupport::unbind(this->_ssl);
@@ -761,6 +768,29 @@ QUICNetVConnection::get_quic_connection()
   return static_cast<QUICConnection *>(this);
 }
 
+void
+QUICNetVConnection::reenable(int /* event ATS_UNUSED */)
+{
+}
+
+Continuation *
+QUICNetVConnection::getContinuationForTLSEvents()
+{
+  return this;
+}
+
+EThread *
+QUICNetVConnection::getThreadForTLSEvents()
+{
+  return this->thread;
+}
+
+Ptr<ProxyMutex>
+QUICNetVConnection::getMutexForTLSEvents()
+{
+  return this->nh->mutex;
+}
+
 SSL *
 QUICNetVConnection::_get_ssl_object() const
 {
@@ -777,11 +807,6 @@ QUICNetVConnection::_get_tls_curve() const
   }
 }
 
-void
-QUICNetVConnection::_fire_ssl_servername_event()
-{
-}
-
 in_port_t
 QUICNetVConnection::_get_local_port()
 {
diff --git a/src/iocore/net/SSLClientUtils.cc b/src/iocore/net/SSLClientUtils.cc
index 51b6d4a897..aef0ecf9f3 100644
--- a/src/iocore/net/SSLClientUtils.cc
+++ b/src/iocore/net/SSLClientUtils.cc
@@ -132,7 +132,10 @@ verify_callback(int signature_ok, X509_STORE_CTX *ctx)
   }
   // If the previous configured checks passed, give the hook a try
   netvc->set_verify_cert(ctx);
-  netvc->callHooks(TS_EVENT_SSL_VERIFY_SERVER);
+  TLSEventSupport *es = TLSEventSupport::getInstance(ssl);
+  if (es) {
+    es->callHooks(TS_EVENT_SSL_VERIFY_SERVER);
+  }
   netvc->set_verify_cert(nullptr);
 
   if (netvc->getSSLHandshakeStatus() == 
SSLHandshakeStatus::SSL_HANDSHAKE_ERROR) {
diff --git a/src/iocore/net/SSLNetVConnection.cc 
b/src/iocore/net/SSLNetVConnection.cc
index dcf222aea7..0ca851ebc8 100644
--- a/src/iocore/net/SSLNetVConnection.cc
+++ b/src/iocore/net/SSLNetVConnection.cc
@@ -39,7 +39,6 @@
 #include "P_SSLClientUtils.h"
 #include "P_SSLNetVConnection.h"
 #include "BIO_fastopen.h"
-#include "iocore/net/SSLAPIHooks.h"
 #include "SSLStats.h"
 #include "iocore/net/TLSALPNSupport.h"
 
@@ -92,117 +91,12 @@ DbgCtl dbg_ctl_ssl_alpn{"ssl_alpn"};
 DbgCtl dbg_ctl_ssl_origin_session_cache{"ssl.origin_session_cache"};
 DbgCtl dbg_ctl_proxyprotocol{"proxyprotocol"};
 
-/// Callback to get two locks.
-/// The lock for this continuation, and for the target continuation.
-class ContWrapper : public Continuation
-{
-public:
-  /** Constructor.
-      This takes the secondary @a mutex and the @a target continuation
-      to invoke, along with the arguments for that invocation.
-  */
-  ContWrapper(ProxyMutex   *mutex,                     ///< Mutex for this 
continuation (primary lock).
-              Continuation *target,                    ///< "Real" 
continuation we want to call.
-              int           eventId = EVENT_IMMEDIATE, ///< Event ID for 
invocation of @a target.
-              void         *edata   = nullptr          ///< Data for 
invocation of @a target.
-              )
-    : Continuation(mutex), _target(target), _eventId(eventId), _edata(edata)
-  {
-    SET_HANDLER(&ContWrapper::event_handler);
-  }
-
-  /// Required event handler method.
-  int
-  event_handler(int, void *)
-  {
-    EThread *eth = this_ethread();
-
-    MUTEX_TRY_LOCK(lock, _target->mutex, eth);
-    if (lock.is_locked()) { // got the target lock, we can proceed.
-      _target->handleEvent(_eventId, _edata);
-      delete this;
-    } else { // can't get both locks, try again.
-      eventProcessor.schedule_imm(this, ET_NET);
-    }
-    return 0;
-  }
-
-  /** Convenience static method.
-
-      This lets a client make one call and not have to (accurately)
-      copy the invocation logic embedded here. We duplicate it near
-      by textually so it is easier to keep in sync.
-
-      This takes the same arguments as the constructor but, if the
-      lock can be obtained immediately, does not construct an
-      instance but simply calls the @a target.
-  */
-  static void
-  wrap(ProxyMutex   *mutex,                     ///< Mutex for this 
continuation (primary lock).
-       Continuation *target,                    ///< "Real" continuation we 
want to call.
-       int           eventId = EVENT_IMMEDIATE, ///< Event ID for invocation 
of @a target.
-       void         *edata   = nullptr          ///< Data for invocation of @a 
target.
-  )
-  {
-    EThread *eth = this_ethread();
-    if (!target->mutex) {
-      // If there's no mutex, plugin doesn't care about locking so why should 
we?
-      target->handleEvent(eventId, edata);
-    } else {
-      MUTEX_TRY_LOCK(lock, target->mutex, eth);
-      if (lock.is_locked()) {
-        target->handleEvent(eventId, edata);
-      } else {
-        eventProcessor.schedule_imm(new ContWrapper(mutex, target, eventId, 
edata), ET_NET);
-      }
-    }
-  }
-
-private:
-  Continuation *_target;  ///< Continuation to invoke.
-  int           _eventId; ///< with this event
-  void         *_edata;   ///< and this data
-};
 } // namespace
 
 //
 // Private
 //
 
-char const *
-SSLNetVConnection::get_ssl_handshake_hook_state_name(SSLHandshakeHookState 
state)
-{
-  switch (state) {
-  case HANDSHAKE_HOOKS_PRE:
-    return "TS_SSL_HOOK_PRE_ACCEPT";
-  case HANDSHAKE_HOOKS_PRE_INVOKE:
-    return "TS_SSL_HOOK_PRE_ACCEPT_INVOKE";
-  case HANDSHAKE_HOOKS_CLIENT_HELLO:
-    return "TS_SSL_HOOK_CLIENT_HELLO";
-  case HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
-    return "TS_SSL_HOOK_CLIENT_HELLO_INVOKE";
-  case HANDSHAKE_HOOKS_SNI:
-    return "TS_SSL_HOOK_SERVERNAME";
-  case HANDSHAKE_HOOKS_CERT:
-    return "TS_SSL_HOOK_CERT";
-  case HANDSHAKE_HOOKS_CERT_INVOKE:
-    return "TS_SSL_HOOK_CERT_INVOKE";
-  case HANDSHAKE_HOOKS_CLIENT_CERT:
-    return "TS_SSL_HOOK_CLIENT_CERT";
-  case HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
-    return "TS_SSL_HOOK_CLIENT_CERT_INVOKE";
-  case HANDSHAKE_HOOKS_OUTBOUND_PRE:
-    return "TS_SSL_HOOK_PRE_CONNECT";
-  case HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
-    return "TS_SSL_HOOK_PRE_CONNECT_INVOKE";
-  case HANDSHAKE_HOOKS_VERIFY_SERVER:
-    return "TS_SSL_HOOK_VERIFY_SERVER";
-  case HANDSHAKE_HOOKS_DONE:
-    return "TS_SSL_HOOKS_DONE";
-  }
-  return "unknown handshake hook name";
-}
-
 void
 SSLNetVConnection::_make_ssl_connection(SSL_CTX *ctx)
 {
@@ -236,6 +130,7 @@ SSLNetVConnection::_bindSSLObject()
 {
   SSLNetVCAttach(this->ssl, this);
   TLSBasicSupport::bind(this->ssl, this);
+  TLSEventSupport::bind(this->ssl, this);
   ALPNSupport::bind(this->ssl, this);
   TLSSessionResumptionSupport::bind(this->ssl, this);
   TLSSNISupport::bind(this->ssl, this);
@@ -249,6 +144,7 @@ SSLNetVConnection::_unbindSSLObject()
 {
   SSLNetVCDetach(this->ssl);
   TLSBasicSupport::unbind(this->ssl);
+  TLSEventSupport::unbind(this->ssl);
   ALPNSupport::unbind(this->ssl);
   TLSSessionResumptionSupport::unbind(this->ssl);
   TLSSNISupport::unbind(this->ssl);
@@ -929,6 +825,7 @@ SSLNetVConnection::SSLNetVConnection()
 {
   this->_set_service(static_cast<ALPNSupport *>(this));
   this->_set_service(static_cast<TLSBasicSupport *>(this));
+  this->_set_service(static_cast<TLSEventSupport *>(this));
   this->_set_service(static_cast<TLSCertSwitchSupport *>(this));
   this->_set_service(static_cast<TLSEarlyDataSupport *>(this));
   this->_set_service(static_cast<TLSSNISupport *>(this));
@@ -1010,6 +907,7 @@ SSLNetVConnection::clear()
 
   ALPNSupport::clear();
   TLSBasicSupport::clear();
+  TLSEventSupport::clear();
   TLSSessionResumptionSupport::clear();
   TLSSNISupport::_clear();
   TLSTunnelSupport::_clear();
@@ -1020,7 +918,6 @@ SSLNetVConnection::clear()
   sslTotalBytesSent           = 0;
   sslClientRenegotiationAbort = false;
 
-  curHook         = nullptr;
   hookOpRequested = SSL_HOOK_OP_DEFAULT;
   free_handshake_buffers();
 
@@ -1281,27 +1178,13 @@ int
 SSLNetVConnection::sslServerHandShakeEvent(int &err)
 {
   // Continue on if we are in the invoked state.  The hook has not yet 
reenabled
-  if (sslHandshakeHookState == HANDSHAKE_HOOKS_CERT_INVOKE || 
sslHandshakeHookState == HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE ||
-      sslHandshakeHookState == HANDSHAKE_HOOKS_PRE_INVOKE || 
sslHandshakeHookState == HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE) {
+  if (this->is_invoked_state()) {
     return SSL_WAIT_FOR_HOOK;
   }
 
   // Go do the preaccept hooks
-  if (sslHandshakeHookState == HANDSHAKE_HOOKS_PRE) {
-    Metrics::Counter::increment(ssl_rsb.total_attempts_handshake_count_in);
-    if (!curHook) {
-      Dbg(dbg_ctl_ssl, "Initialize preaccept curHook from NULL");
-      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_START_HOOK));
-    } else {
-      curHook = curHook->next();
-    }
-    // If no more hooks, move onto CLIENT HELLO
-
-    if (nullptr == curHook) {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_HELLO;
-    } else {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_PRE_INVOKE;
-      ContWrapper::wrap(nh->mutex.get(), curHook->m_cont, 
TS_EVENT_VCONN_START, this);
+  if (this->get_handshake_hook_state() == 
TLSEventSupport::SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE) {
+    if (this->invoke_tls_event() == 1) {
       return SSL_WAIT_FOR_HOOK;
     }
   }
@@ -1325,7 +1208,8 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
     return EVENT_DONE;
   }
 
-  Dbg(dbg_ctl_ssl, "Go on with the handshake state=%s", 
get_ssl_handshake_hook_state_name(sslHandshakeHookState));
+  Dbg(dbg_ctl_ssl, "Go on with the handshake state=%s",
+      
TLSEventSupport::get_ssl_handshake_hook_state_name(this->get_handshake_hook_state()));
 
   // All the pre-accept hooks have completed, proceed with the actual accept.
   if (this->handShakeReader) {
@@ -1552,7 +1436,7 @@ SSLNetVConnection::sslClientHandShakeEvent(int &err)
   ink_assert(TLSBasicSupport::getInstance(ssl) == this);
 
   // Initialize properly for a client connection
-  if (sslHandshakeHookState == HANDSHAKE_HOOKS_PRE) {
+  if (this->get_handshake_hook_state() == 
TLSEventSupport::SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE) {
     if (this->pp_info.version != ProxyProtocolVersion::UNDEFINED) {
       // Outbound PROXY Protocol
       VIO    &vio     = this->write.vio;
@@ -1582,28 +1466,18 @@ SSLNetVConnection::sslClientHandShakeEvent(int &err)
       }
     }
 
-    sslHandshakeHookState = HANDSHAKE_HOOKS_OUTBOUND_PRE;
+    
this->set_handshake_hook_state(TLSEventSupport::SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE);
   }
 
   // Do outbound hook processing here
   // Continue on if we are in the invoked state.  The hook has not yet 
reenabled
-  if (sslHandshakeHookState == HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE) {
+  if (this->is_invoked_state()) {
     return SSL_WAIT_FOR_HOOK;
   }
 
   // Go do the preaccept hooks
-  if (sslHandshakeHookState == HANDSHAKE_HOOKS_OUTBOUND_PRE) {
-    Metrics::Counter::increment(ssl_rsb.total_attempts_handshake_count_out);
-    if (!curHook) {
-      Dbg(dbg_ctl_ssl, "Initialize outbound connect curHook from NULL");
-      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_OUTBOUND_START_HOOK));
-    } else {
-      curHook = curHook->next();
-    }
-    // If no more hooks, carry on
-    if (nullptr != curHook) {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE;
-      ContWrapper::wrap(nh->mutex.get(), curHook->m_cont, 
TS_EVENT_VCONN_OUTBOUND_START, this);
+  if (this->get_handshake_hook_state() == 
TLSEventSupport::SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE) {
+    if (this->invoke_tls_event() == 1) {
       return SSL_WAIT_FOR_HOOK;
     }
   }
@@ -1707,34 +1581,17 @@ SSLNetVConnection::sslClientHandShakeEvent(int &err)
 }
 
 void
-SSLNetVConnection::reenable(NetHandler *nh, int event)
+SSLNetVConnection::reenable(int event)
 {
-  Dbg(dbg_ctl_ssl, "Handshake reenable from state=%s", 
get_ssl_handshake_hook_state_name(sslHandshakeHookState));
+  Dbg(dbg_ctl_ssl, "Handshake reenable from state=%s",
+      
TLSEventSupport::get_ssl_handshake_hook_state_name(this->get_handshake_hook_state()));
 
   // Mark as error to stop the Handshake
   if (event == TS_EVENT_ERROR) {
     sslHandshakeStatus = SSLHandshakeStatus::SSL_HANDSHAKE_ERROR;
   }
 
-  switch (sslHandshakeHookState) {
-  case HANDSHAKE_HOOKS_PRE_INVOKE:
-    sslHandshakeHookState = HANDSHAKE_HOOKS_PRE;
-    break;
-  case HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
-    sslHandshakeHookState = HANDSHAKE_HOOKS_OUTBOUND_PRE;
-    break;
-  case HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
-    sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_HELLO;
-    break;
-  case HANDSHAKE_HOOKS_CERT_INVOKE:
-    sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
-    break;
-  case HANDSHAKE_HOOKS_VERIFY_SERVER:
-  case HANDSHAKE_HOOKS_CLIENT_CERT:
-    break;
-  default:
-    break;
-  }
+  this->resume_tls_event();
 
   // Reenabling from the handshake callback
   //
@@ -1743,232 +1600,31 @@ SSLNetVConnection::reenable(NetHandler *nh, int event)
   // can be replaced by the plugin, it didn't seem reasonable to assume that 
the
   // callback would be executed again.  So we walk through the rest of the 
hooks
   // here in the reenable.
-  if (curHook != nullptr) {
-    curHook = curHook->next();
-    Dbg(dbg_ctl_ssl, "iterate from reenable curHook=%p", curHook);
-  }
-  if (curHook != nullptr) {
-    // Invoke the hook and return, wait for next reenable
-    if (sslHandshakeHookState == HANDSHAKE_HOOKS_CLIENT_HELLO) {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE;
-      curHook->invoke(TS_EVENT_SSL_CLIENT_HELLO, this);
-    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_CLIENT_CERT) {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE;
-      curHook->invoke(TS_EVENT_SSL_VERIFY_CLIENT, this);
-    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_CERT) {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_CERT_INVOKE;
-      curHook->invoke(TS_EVENT_SSL_CERT, this);
-    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_SNI) {
-      curHook->invoke(TS_EVENT_SSL_SERVERNAME, this);
-    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_PRE) {
-      Dbg(dbg_ctl_ssl, "Reenable preaccept");
-      sslHandshakeHookState = HANDSHAKE_HOOKS_PRE_INVOKE;
-      ContWrapper::wrap(nh->mutex.get(), curHook->m_cont, 
TS_EVENT_VCONN_START, this);
-    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_OUTBOUND_PRE) {
-      Dbg(dbg_ctl_ssl, "Reenable outbound connect");
-      sslHandshakeHookState = HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE;
-      ContWrapper::wrap(nh->mutex.get(), curHook->m_cont, 
TS_EVENT_VCONN_OUTBOUND_START, this);
-    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_DONE) {
-      if (this->get_context() == NET_VCONNECTION_OUT) {
-        ContWrapper::wrap(nh->mutex.get(), curHook->m_cont, 
TS_EVENT_VCONN_OUTBOUND_CLOSE, this);
-      } else {
-        ContWrapper::wrap(nh->mutex.get(), curHook->m_cont, 
TS_EVENT_VCONN_CLOSE, this);
-      }
-    } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_VERIFY_SERVER) {
-      Dbg(dbg_ctl_ssl, "ServerVerify");
-      ContWrapper::wrap(nh->mutex.get(), curHook->m_cont, 
TS_EVENT_SSL_VERIFY_SERVER, this);
-    }
-    return;
-  } else {
-    // Move onto the "next" state
-    switch (this->sslHandshakeHookState) {
-    case HANDSHAKE_HOOKS_PRE:
-    case HANDSHAKE_HOOKS_PRE_INVOKE:
-      sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_HELLO;
-      break;
-    case HANDSHAKE_HOOKS_CLIENT_HELLO:
-    case HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
-      sslHandshakeHookState = HANDSHAKE_HOOKS_SNI;
-      break;
-    case HANDSHAKE_HOOKS_SNI:
-      sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
-      break;
-    case HANDSHAKE_HOOKS_CERT:
-    case HANDSHAKE_HOOKS_CERT_INVOKE:
-      sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_CERT;
-      break;
-    case HANDSHAKE_HOOKS_OUTBOUND_PRE:
-    case HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
-      this->write.triggered = true;
-      this->write.enabled   = true;
-      this->writeReschedule(nh);
-      sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-      break;
-    case HANDSHAKE_HOOKS_CLIENT_CERT:
-    case HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
-      sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-      break;
-    case HANDSHAKE_HOOKS_VERIFY_SERVER:
-      sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-      break;
-    default:
-      break;
-    }
-    Dbg(dbg_ctl_ssl, "iterate from reenable curHook=%p %s", curHook, 
get_ssl_handshake_hook_state_name(sslHandshakeHookState));
+  if (this->invoke_tls_event() == 2) {
+    this->write.triggered = true;
+    this->write.enabled   = true;
+    this->writeReschedule(nh);
   }
 
   this->readReschedule(nh);
 }
 
-bool
-SSLNetVConnection::callHooks(TSEvent eventId)
+Continuation *
+SSLNetVConnection::getContinuationForTLSEvents()
 {
-  // Only dealing with the SNI/CERT hook so far.
-  ink_assert(eventId == TS_EVENT_SSL_CLIENT_HELLO || eventId == 
TS_EVENT_SSL_CERT || eventId == TS_EVENT_SSL_SERVERNAME ||
-             eventId == TS_EVENT_SSL_VERIFY_SERVER || eventId == 
TS_EVENT_SSL_VERIFY_CLIENT || eventId == TS_EVENT_VCONN_CLOSE ||
-             eventId == TS_EVENT_VCONN_OUTBOUND_CLOSE);
-  Dbg(dbg_ctl_ssl, "sslHandshakeHookState=%s eventID=%d", 
get_ssl_handshake_hook_state_name(this->sslHandshakeHookState), eventId);
-
-  // Move state if it is appropriate
-  if (eventId == TS_EVENT_VCONN_CLOSE) {
-    // Regardless of state, if the connection is closing, then transition to
-    // the DONE state. This will trigger us to call the appropriate cleanup
-    // routines.
-    this->sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-  } else {
-    switch (this->sslHandshakeHookState) {
-    case HANDSHAKE_HOOKS_PRE:
-    case HANDSHAKE_HOOKS_OUTBOUND_PRE:
-      if (eventId == TS_EVENT_SSL_CLIENT_HELLO) {
-        this->sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_HELLO;
-      } else if (eventId == TS_EVENT_SSL_SERVERNAME) {
-        this->sslHandshakeHookState = HANDSHAKE_HOOKS_SNI;
-      } else if (eventId == TS_EVENT_SSL_VERIFY_SERVER) {
-        this->sslHandshakeHookState = HANDSHAKE_HOOKS_VERIFY_SERVER;
-      } else if (eventId == TS_EVENT_SSL_CERT) {
-        this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
-      }
-      break;
-    case HANDSHAKE_HOOKS_CLIENT_HELLO:
-      if (eventId == TS_EVENT_SSL_SERVERNAME) {
-        this->sslHandshakeHookState = HANDSHAKE_HOOKS_SNI;
-      } else if (eventId == TS_EVENT_SSL_CERT) {
-        this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
-      }
-      break;
-    case HANDSHAKE_HOOKS_SNI:
-      if (eventId == TS_EVENT_SSL_CERT) {
-        this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
-      }
-      break;
-    default:
-      break;
-    }
-  }
-
-  // Look for hooks associated with the event
-  switch (this->sslHandshakeHookState) {
-  case HANDSHAKE_HOOKS_CLIENT_HELLO:
-  case HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
-    if (!curHook) {
-      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_CLIENT_HELLO_HOOK));
-    } else {
-      curHook = curHook->next();
-    }
-    if (curHook == nullptr) {
-      this->sslHandshakeHookState = HANDSHAKE_HOOKS_SNI;
-    } else {
-      this->sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE;
-    }
-    break;
-  case HANDSHAKE_HOOKS_VERIFY_SERVER:
-    // The server verify event addresses ATS to origin handshake
-    // All the other events are for client to ATS
-    if (!curHook) {
-      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_VERIFY_SERVER_HOOK));
-    } else {
-      curHook = curHook->next();
-    }
-    break;
-  case HANDSHAKE_HOOKS_SNI:
-    if (!curHook) {
-      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_SERVERNAME_HOOK));
-    } else {
-      curHook = curHook->next();
-    }
-    if (!curHook) {
-      this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
-    }
-    break;
-  case HANDSHAKE_HOOKS_CERT:
-  case HANDSHAKE_HOOKS_CERT_INVOKE:
-    if (!curHook) {
-      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_CERT_HOOK));
-    } else {
-      curHook = curHook->next();
-    }
-    if (curHook == nullptr) {
-      this->sslHandshakeHookState = HANDSHAKE_HOOKS_CLIENT_CERT;
-    } else {
-      this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT_INVOKE;
-    }
-    break;
-  case HANDSHAKE_HOOKS_CLIENT_CERT:
-  case HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
-    if (!curHook) {
-      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_VERIFY_CLIENT_HOOK));
-    } else {
-      curHook = curHook->next();
-    }
-  // fallthrough
-  case HANDSHAKE_HOOKS_DONE:
-  case HANDSHAKE_HOOKS_OUTBOUND_PRE:
-    if (eventId == TS_EVENT_VCONN_CLOSE) {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-      if (curHook == nullptr) {
-        curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_CLOSE_HOOK));
-      } else {
-        curHook = curHook->next();
-      }
-    } else if (eventId == TS_EVENT_VCONN_OUTBOUND_CLOSE) {
-      sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-      if (curHook == nullptr) {
-        curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_OUTBOUND_CLOSE_HOOK));
-      } else {
-        curHook = curHook->next();
-      }
-    }
-    break;
-  default:
-    curHook                     = nullptr;
-    this->sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-    return true;
-  }
-
-  Dbg(dbg_ctl_ssl, "iterated to curHook=%p", curHook);
-
-  bool reenabled = true;
-
-  if (SSL_HOOK_OP_TUNNEL == hookOpRequested) {
-    this->attributes = HttpProxyPort::TRANSPORT_BLIND_TUNNEL;
-    // Don't mark the handshake as complete yet,
-    // Will be checking for that flag not being set after
-    // we get out of this callback, and then will shuffle
-    // over the buffered handshake packets to the O.S.
-    // sslHandShakeComplete = 1;
-    return reenabled;
-  }
+  return this;
+}
 
-  if (curHook != nullptr) {
-    WEAK_SCOPED_MUTEX_LOCK(lock, curHook->m_cont->mutex, this_ethread());
-    curHook->invoke(eventId, this);
-    reenabled =
-      (this->sslHandshakeHookState != HANDSHAKE_HOOKS_CERT_INVOKE && 
this->sslHandshakeHookState != HANDSHAKE_HOOKS_PRE_INVOKE &&
-       this->sslHandshakeHookState != HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE);
-    Dbg(dbg_ctl_ssl, "Called hook on state=%s reenabled=%d", 
get_ssl_handshake_hook_state_name(sslHandshakeHookState), reenabled);
-  }
+EThread *
+SSLNetVConnection::getThreadForTLSEvents()
+{
+  return this->thread;
+}
 
-  return reenabled;
+Ptr<ProxyMutex>
+SSLNetVConnection::getMutexForTLSEvents()
+{
+  return this->nh->mutex;
 }
 
 int
@@ -2116,12 +1772,6 @@ SSLNetVConnection::protocol_contains(std::string_view 
prefix) const
   return retval;
 }
 
-void
-SSLNetVConnection::_fire_ssl_servername_event()
-{
-  this->callHooks(TS_EVENT_SSL_SERVERNAME);
-}
-
 in_port_t
 SSLNetVConnection::_get_local_port()
 {
diff --git a/src/iocore/net/SSLUtils.cc b/src/iocore/net/SSLUtils.cc
index 639cbfa4ad..95680bccb3 100644
--- a/src/iocore/net/SSLUtils.cc
+++ b/src/iocore/net/SSLUtils.cc
@@ -290,7 +290,10 @@ ssl_verify_client_callback(int preverify_ok, 
X509_STORE_CTX *ctx)
   }
 
   netvc->set_verify_cert(ctx);
-  netvc->callHooks(TS_EVENT_SSL_VERIFY_CLIENT);
+  TLSEventSupport *es = TLSEventSupport::getInstance(ssl);
+  if (es) {
+    es->callHooks(TS_EVENT_SSL_VERIFY_CLIENT);
+  }
   netvc->set_verify_cert(nullptr);
 
   if (netvc->getSSLHandShakeComplete()) { // hook moved the handshake state to 
terminal
@@ -330,17 +333,15 @@ ssl_client_hello_callback(const SSL_CLIENT_HELLO 
*client_hello)
     return CLIENT_HELLO_ERROR;
   }
 
-  SSLNetVConnection *netvc = dynamic_cast<SSLNetVConnection *>(snis);
-  if (netvc) {
-    if (netvc->ssl != s) {
-      Dbg(dbg_ctl_ssl_error, "ssl_client_hello_callback call back on stale 
netvc");
-      return CLIENT_HELLO_ERROR;
-    }
-
-    bool reenabled = netvc->callHooks(TS_EVENT_SSL_CLIENT_HELLO);
+  TLSEventSupport *es = TLSEventSupport::getInstance(s);
+  if (es) {
+    bool reenabled = es->callHooks(TS_EVENT_SSL_CLIENT_HELLO);
     if (!reenabled) {
       return CLIENT_HELLO_RETRY;
     }
+  } else {
+    Dbg(dbg_ctl_ssl_error, "ssl_client_hello_callback call back on stale 
netvc");
+    return CLIENT_HELLO_ERROR;
   }
 
   return CLIENT_HELLO_SUCCESS;
@@ -354,6 +355,7 @@ static int
 ssl_cert_callback(SSL *ssl, [[maybe_unused]] void *arg)
 {
   TLSCertSwitchSupport *tcss     = TLSCertSwitchSupport::getInstance(ssl);
+  TLSEventSupport      *tes      = TLSEventSupport::getInstance(ssl);
   SSLNetVConnection    *sslnetvc = dynamic_cast<SSLNetVConnection *>(tcss);
   bool                  reenabled;
   int                   retval = 1;
@@ -379,28 +381,30 @@ ssl_cert_callback(SSL *ssl, [[maybe_unused]] void *arg)
   }
 #endif
 
-  if (sslnetvc) {
-    // Do the common certificate lookup only once.  If we pause
-    // and restart processing, do not execute the common logic again
-    if (!sslnetvc->calledHooks(TS_EVENT_SSL_CERT)) {
-      retval = sslnetvc->selectCertificate(ssl, ctxType);
-      if (retval != 1) {
-        return retval;
+  if (tcss) {
+    if (tes) {
+      // Do the common certificate lookup only once.  If we pause
+      // and restart processing, do not execute the common logic again
+      if (!tes->calledHooks(TS_EVENT_SSL_CERT)) {
+        retval = tcss->selectCertificate(ssl, ctxType);
+        if (retval != 1) {
+          return retval;
+        }
       }
-    }
 
-    // Call the plugin cert code
-    reenabled = sslnetvc->callHooks(TS_EVENT_SSL_CERT);
-    // If it did not re-enable, return the code to
-    // stop the accept processing
-    if (!reenabled) {
-      retval = -1; // Pause
-    }
-  } else {
-    if (tcss && tcss->selectCertificate(ssl, ctxType) == 1) {
-      retval = 1;
+      // Call the plugin cert code
+      reenabled = tes->callHooks(TS_EVENT_SSL_CERT);
+      // If it did not re-enable, return the code to
+      // stop the accept processing
+      if (!reenabled) {
+        retval = -1; // Pause
+      }
     } else {
-      retval = 0;
+      if (tcss->selectCertificate(ssl, ctxType) == 1) {
+        retval = 1;
+      } else {
+        retval = 0;
+      }
     }
   }
 
@@ -433,6 +437,9 @@ ssl_servername_callback(SSL *ssl, int *al, void *arg)
 {
   TLSSNISupport *snis = TLSSNISupport::getInstance(ssl);
   if (snis) {
+    if (TLSEventSupport *es = TLSEventSupport::getInstance(ssl); es) {
+      es->callHooks(TS_EVENT_SSL_SERVERNAME);
+    }
     snis->on_servername(ssl, al, arg);
 #if !TS_USE_HELLO_CB
     // Only call the SNI actions here if not already performed in the HELLO_CB
@@ -900,6 +907,7 @@ SSLInitializeLibrary()
   ssl_vc_index = SSL_get_ex_new_index(0, (void *)"NetVC index", nullptr, 
nullptr, nullptr);
 
   TLSBasicSupport::initialize();
+  TLSEventSupport::initialize();
   ALPNSupport::initialize();
   TLSSessionResumptionSupport::initialize();
   TLSSNISupport::initialize();
diff --git a/src/iocore/net/TLSEventSupport.cc 
b/src/iocore/net/TLSEventSupport.cc
new file mode 100644
index 0000000000..718332b9a1
--- /dev/null
+++ b/src/iocore/net/TLSEventSupport.cc
@@ -0,0 +1,553 @@
+/** @file
+
+  TLSSEventSupport.cc provides implementations for
+  TLSEventSupport methods
+
+  @section license License
+
+  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.
+ */
+
+#include <openssl/ssl.h>
+#include "iocore/net/TLSEventSupport.h"
+#include "iocore/net/SSLAPIHooks.h"
+#include "tscore/Diags.h"
+#include "SSLStats.h"
+
+int TLSEventSupport::_ex_data_index = -1;
+
+namespace
+{
+DbgCtl dbg_ctl_ssl{"ssl"};
+
+/// Callback to get two locks.
+/// The lock for this continuation, and for the target continuation.
+class ContWrapper : public Continuation
+{
+public:
+  /** Constructor.
+      This takes the secondary @a mutex and the @a target continuation
+      to invoke, along with the arguments for that invocation.
+  */
+  ContWrapper(ProxyMutex   *mutex,                     ///< Mutex for this 
continuation (primary lock).
+              Continuation *target,                    ///< "Real" 
continuation we want to call.
+              int           eventId = EVENT_IMMEDIATE, ///< Event ID for 
invocation of @a target.
+              void         *edata   = nullptr          ///< Data for 
invocation of @a target.
+              )
+    : Continuation(mutex), _target(target), _eventId(eventId), _edata(edata)
+  {
+    SET_HANDLER(&ContWrapper::event_handler);
+  }
+
+  /// Required event handler method.
+  int
+  event_handler(int, void *)
+  {
+    EThread *eth = this_ethread();
+
+    MUTEX_TRY_LOCK(lock, _target->mutex, eth);
+    if (lock.is_locked()) { // got the target lock, we can proceed.
+      _target->handleEvent(_eventId, _edata);
+      delete this;
+    } else { // can't get both locks, try again.
+      eventProcessor.schedule_imm(this, ET_NET);
+    }
+    return 0;
+  }
+
+  /** Convenience static method.
+
+      This lets a client make one call and not have to (accurately)
+      copy the invocation logic embedded here. We duplicate it near
+      by textually so it is easier to keep in sync.
+
+      This takes the same arguments as the constructor but, if the
+      lock can be obtained immediately, does not construct an
+      instance but simply calls the @a target.
+  */
+  static void
+  wrap(ProxyMutex   *mutex,                     ///< Mutex for this 
continuation (primary lock).
+       Continuation *target,                    ///< "Real" continuation we 
want to call.
+       int           eventId = EVENT_IMMEDIATE, ///< Event ID for invocation 
of @a target.
+       void         *edata   = nullptr          ///< Data for invocation of @a 
target.
+  )
+  {
+    EThread *eth = this_ethread();
+    if (!target->mutex) {
+      // If there's no mutex, plugin doesn't care about locking so why should 
we?
+      target->handleEvent(eventId, edata);
+    } else {
+      MUTEX_TRY_LOCK(lock, target->mutex, eth);
+      if (lock.is_locked()) {
+        target->handleEvent(eventId, edata);
+      } else {
+        eventProcessor.schedule_imm(new ContWrapper(mutex, target, eventId, 
edata), ET_NET);
+      }
+    }
+  }
+
+private:
+  Continuation *_target;  ///< Continuation to invoke.
+  int           _eventId; ///< with this event
+  void         *_edata;   ///< and this data
+};
+
+} // end anonymous namespace
+
+void
+TLSEventSupport::initialize()
+{
+  ink_assert(_ex_data_index == -1);
+  if (_ex_data_index == -1) {
+    _ex_data_index = SSL_get_ex_new_index(0, (void *)"TLSEventSupport index", 
nullptr, nullptr, nullptr);
+  }
+}
+
+TLSEventSupport *
+TLSEventSupport::getInstance(SSL *ssl)
+{
+  return static_cast<TLSEventSupport *>(SSL_get_ex_data(ssl, _ex_data_index));
+}
+
+void
+TLSEventSupport::bind(SSL *ssl, TLSEventSupport *es)
+{
+  SSL_set_ex_data(ssl, _ex_data_index, es);
+  es->_ssl = ssl;
+}
+
+void
+TLSEventSupport::unbind(SSL *ssl)
+{
+  SSL_set_ex_data(ssl, _ex_data_index, nullptr);
+}
+
+void
+TLSEventSupport::clear()
+{
+  curHook = nullptr;
+}
+
+bool
+TLSEventSupport::callHooks(TSEvent eventId)
+{
+  // Only dealing with the SNI/CERT hook so far.
+  ink_assert(eventId == TS_EVENT_SSL_CLIENT_HELLO || eventId == 
TS_EVENT_SSL_CERT || eventId == TS_EVENT_SSL_SERVERNAME ||
+             eventId == TS_EVENT_SSL_VERIFY_SERVER || eventId == 
TS_EVENT_SSL_VERIFY_CLIENT || eventId == TS_EVENT_VCONN_CLOSE ||
+             eventId == TS_EVENT_VCONN_OUTBOUND_CLOSE);
+  Dbg(dbg_ctl_ssl, "sslHandshakeHookState=%s eventID=%d", 
get_ssl_handshake_hook_state_name(this->sslHandshakeHookState), eventId);
+
+  // Move state if it is appropriate
+  if (eventId == TS_EVENT_VCONN_CLOSE) {
+    // Regardless of state, if the connection is closing, then transition to
+    // the DONE state. This will trigger us to call the appropriate cleanup
+    // routines.
+    this->sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE;
+  } else {
+    switch (this->sslHandshakeHookState) {
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE:
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE:
+      if (eventId == TS_EVENT_SSL_CLIENT_HELLO) {
+        this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO;
+      } else if (eventId == TS_EVENT_SSL_SERVERNAME) {
+        this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI;
+      } else if (eventId == TS_EVENT_SSL_VERIFY_SERVER) {
+        this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_VERIFY_SERVER;
+      } else if (eventId == TS_EVENT_SSL_CERT) {
+        this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT;
+      }
+      break;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO:
+      if (eventId == TS_EVENT_SSL_SERVERNAME) {
+        this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI;
+      } else if (eventId == TS_EVENT_SSL_CERT) {
+        this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT;
+      }
+      break;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI:
+      if (eventId == TS_EVENT_SSL_CERT) {
+        this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT;
+      }
+      break;
+    default:
+      break;
+    }
+  }
+
+  // Look for hooks associated with the event
+  switch (this->sslHandshakeHookState) {
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
+    if (!curHook) {
+      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_CLIENT_HELLO_HOOK));
+    } else {
+      curHook = curHook->next();
+    }
+    if (curHook == nullptr) {
+      this->sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI;
+    } else {
+      this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE;
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_VERIFY_SERVER:
+    // The server verify event addresses ATS to origin handshake
+    // All the other events are for client to ATS
+    if (!curHook) {
+      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_VERIFY_SERVER_HOOK));
+    } else {
+      curHook = curHook->next();
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI:
+    if (!curHook) {
+      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_SERVERNAME_HOOK));
+    } else {
+      curHook = curHook->next();
+    }
+    if (!curHook) {
+      this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT;
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE:
+    if (!curHook) {
+      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_CERT_HOOK));
+    } else {
+      curHook = curHook->next();
+    }
+    if (curHook == nullptr) {
+      this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT;
+    } else {
+      this->sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE;
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
+    if (!curHook) {
+      curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_SSL_VERIFY_CLIENT_HOOK));
+    } else {
+      curHook = curHook->next();
+    }
+    [[fallthrough]];
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE:
+    if (eventId == TS_EVENT_VCONN_CLOSE) {
+      sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE;
+      if (curHook == nullptr) {
+        curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_CLOSE_HOOK));
+      } else {
+        curHook = curHook->next();
+      }
+    } else if (eventId == TS_EVENT_VCONN_OUTBOUND_CLOSE) {
+      sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE;
+      if (curHook == nullptr) {
+        curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_OUTBOUND_CLOSE_HOOK));
+      } else {
+        curHook = curHook->next();
+      }
+    }
+    break;
+  default:
+    curHook                     = nullptr;
+    this->sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE;
+    return true;
+  }
+
+  Dbg(dbg_ctl_ssl, "iterated to curHook=%p", curHook);
+
+  bool reenabled = true;
+
+  if (this->_is_tunneling_requested()) {
+    this->_switch_to_tunneling_mode();
+    // Don't mark the handshake as complete yet,
+    // Will be checking for that flag not being set after
+    // we get out of this callback, and then will shuffle
+    // over the buffered handshake packets to the O.S.
+    // sslHandShakeComplete = 1;
+    return reenabled;
+  }
+
+  if (curHook != nullptr) {
+    WEAK_SCOPED_MUTEX_LOCK(lock, curHook->m_cont->mutex, this_ethread());
+    curHook->invoke(eventId, this->getContinuationForTLSEvents());
+    reenabled = (this->sslHandshakeHookState != 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE &&
+                 this->sslHandshakeHookState != 
SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE &&
+                 this->sslHandshakeHookState != 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE);
+    Dbg(dbg_ctl_ssl, "Called hook on state=%s reenabled=%d", 
get_ssl_handshake_hook_state_name(sslHandshakeHookState), reenabled);
+  }
+
+  return reenabled;
+}
+
+// Returns true if we have already called at
+// least some of the hooks
+bool
+TLSEventSupport::calledHooks(TSEvent eventId) const
+{
+  bool retval = false;
+  switch (this->sslHandshakeHookState) {
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE:
+    if (eventId == TS_EVENT_VCONN_START) {
+      if (curHook) {
+        retval = true;
+      }
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
+    if (eventId == TS_EVENT_VCONN_START) {
+      retval = true;
+    } else if (eventId == TS_EVENT_SSL_CLIENT_HELLO) {
+      if (curHook) {
+        retval = true;
+      }
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI:
+    if (eventId == TS_EVENT_VCONN_START || eventId == 
TS_EVENT_SSL_CLIENT_HELLO) {
+      retval = true;
+    } else if (eventId == TS_EVENT_SSL_SERVERNAME) {
+      if (curHook) {
+        retval = true;
+      }
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE:
+    if (eventId == TS_EVENT_VCONN_START || eventId == 
TS_EVENT_SSL_CLIENT_HELLO || eventId == TS_EVENT_SSL_SERVERNAME) {
+      retval = true;
+    } else if (eventId == TS_EVENT_SSL_CERT) {
+      if (curHook) {
+        retval = true;
+      }
+    }
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
+    if (eventId == TS_EVENT_SSL_VERIFY_CLIENT || eventId == 
TS_EVENT_VCONN_START) {
+      retval = true;
+    }
+    break;
+
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
+    if (eventId == TS_EVENT_VCONN_OUTBOUND_START) {
+      if (curHook) {
+        retval = true;
+      }
+    }
+    break;
+
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_VERIFY_SERVER:
+    retval = (eventId == TS_EVENT_SSL_VERIFY_SERVER);
+    break;
+
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE:
+    retval = true;
+    break;
+  }
+  return retval;
+}
+
+char const *
+TLSEventSupport::get_ssl_handshake_hook_state_name(SSLHandshakeHookState state)
+{
+  switch (state) {
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE:
+    return "TS_SSL_HOOK_PRE_ACCEPT";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE:
+    return "TS_SSL_HOOK_PRE_ACCEPT_INVOKE";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO:
+    return "TS_SSL_HOOK_CLIENT_HELLO";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
+    return "TS_SSL_HOOK_CLIENT_HELLO_INVOKE";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI:
+    return "TS_SSL_HOOK_SERVERNAME";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT:
+    return "TS_SSL_HOOK_CERT";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE:
+    return "TS_SSL_HOOK_CERT_INVOKE";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT:
+    return "TS_SSL_HOOK_CLIENT_CERT";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
+    return "TS_SSL_HOOK_CLIENT_CERT_INVOKE";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE:
+    return "TS_SSL_HOOK_PRE_CONNECT";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
+    return "TS_SSL_HOOK_PRE_CONNECT_INVOKE";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_VERIFY_SERVER:
+    return "TS_SSL_HOOK_VERIFY_SERVER";
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE:
+    return "TS_SSL_HOOKS_DONE";
+  }
+  return "unknown handshake hook name";
+}
+
+TLSEventSupport::SSLHandshakeHookState
+TLSEventSupport::get_handshake_hook_state()
+{
+  return this->sslHandshakeHookState;
+}
+
+void
+TLSEventSupport::set_handshake_hook_state(TLSEventSupport::SSLHandshakeHookState
 state)
+{
+  this->sslHandshakeHookState = state;
+}
+
+bool
+TLSEventSupport::is_invoked_state() const
+{
+  return sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE ||
+         sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE ||
+         sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE ||
+         sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE ||
+         sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE;
+}
+
+int
+TLSEventSupport::invoke_tls_event()
+{
+  if (curHook != nullptr) {
+    curHook = curHook->next();
+    Dbg(dbg_ctl_ssl, "iterate from reenable curHook=%p", curHook);
+  }
+  if (curHook != nullptr) {
+    // Invoke the hook and return, wait for next reenable
+    if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO) {
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE;
+      curHook->invoke(TS_EVENT_SSL_CLIENT_HELLO, 
this->getContinuationForTLSEvents());
+    } else if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT) {
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE;
+      curHook->invoke(TS_EVENT_SSL_VERIFY_CLIENT, 
this->getContinuationForTLSEvents());
+    } else if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT) {
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE;
+      curHook->invoke(TS_EVENT_SSL_CERT, this->getContinuationForTLSEvents());
+    } else if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI) {
+      curHook->invoke(TS_EVENT_SSL_SERVERNAME, 
this->getContinuationForTLSEvents());
+    } else if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE) {
+      Dbg(dbg_ctl_ssl, "Reenable preaccept");
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE;
+      ContWrapper::wrap(this->getMutexForTLSEvents().get(), curHook->m_cont, 
TS_EVENT_VCONN_START,
+                        this->getContinuationForTLSEvents());
+    } else if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE) {
+      Dbg(dbg_ctl_ssl, "Reenable outbound connect");
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE;
+      ContWrapper::wrap(this->getMutexForTLSEvents().get(), curHook->m_cont, 
TS_EVENT_VCONN_OUTBOUND_START,
+                        this->getContinuationForTLSEvents());
+    } else if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE) {
+      if (SSL_is_server(this->_ssl)) {
+        ContWrapper::wrap(this->getMutexForTLSEvents().get(), curHook->m_cont, 
TS_EVENT_VCONN_CLOSE,
+                          this->getContinuationForTLSEvents());
+      } else {
+        ContWrapper::wrap(this->getMutexForTLSEvents().get(), curHook->m_cont, 
TS_EVENT_VCONN_OUTBOUND_CLOSE,
+                          this->getContinuationForTLSEvents());
+      }
+    } else if (sslHandshakeHookState == 
SSLHandshakeHookState::HANDSHAKE_HOOKS_VERIFY_SERVER) {
+      Dbg(dbg_ctl_ssl, "ServerVerify");
+      ContWrapper::wrap(this->getMutexForTLSEvents().get(), curHook->m_cont, 
TS_EVENT_SSL_VERIFY_SERVER,
+                        this->getContinuationForTLSEvents());
+    }
+    return 1;
+  } else {
+    // Move onto the "next" state
+    switch (this->sslHandshakeHookState) {
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE:
+      if (this->_first_handshake_hooks_pre) {
+        this->_first_handshake_hooks_pre = false;
+        Metrics::Counter::increment(ssl_rsb.total_attempts_handshake_count_in);
+        Dbg(dbg_ctl_ssl, "Initialize preaccept curHook from NULL");
+        curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_START_HOOK));
+        if (curHook) {
+          sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE;
+          ContWrapper::wrap(this->getMutexForTLSEvents().get(), 
curHook->m_cont, TS_EVENT_VCONN_START,
+                            this->getContinuationForTLSEvents());
+          return 1;
+        }
+      }
+      [[fallthrough]];
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE:
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO;
+      break;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO:
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
+      sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI;
+      break;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_SNI:
+      sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT;
+      break;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT:
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE:
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT;
+      break;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE:
+      if (this->_first_handshake_hooks_outbound_pre) {
+        this->_first_handshake_hooks_outbound_pre = false;
+        
Metrics::Counter::increment(ssl_rsb.total_attempts_handshake_count_out);
+        Dbg(dbg_ctl_ssl, "Initialize outbound connect curHook from NULL");
+        curHook = 
SSLAPIHooks::instance()->get(TSSslHookInternalID(TS_VCONN_OUTBOUND_START_HOOK));
+        if (curHook) {
+          sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE;
+          ContWrapper::wrap(this->getMutexForTLSEvents().get(), 
curHook->m_cont, TS_EVENT_VCONN_OUTBOUND_START,
+                            this->getContinuationForTLSEvents());
+          return 1;
+        }
+      }
+      [[fallthrough]];
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
+      sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE;
+      return 2;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT:
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:
+      sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE;
+      break;
+    case SSLHandshakeHookState::HANDSHAKE_HOOKS_VERIFY_SERVER:
+      sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_DONE;
+      break;
+    default:
+      break;
+    }
+    Dbg(dbg_ctl_ssl, "iterate from reenable curHook=%p %s", curHook,
+        
TLSEventSupport::get_ssl_handshake_hook_state_name(sslHandshakeHookState));
+  }
+  return 0;
+}
+
+void
+TLSEventSupport::resume_tls_event()
+{
+  switch (this->sslHandshakeHookState) {
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE_INVOKE:
+    sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_PRE;
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE_INVOKE:
+    sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_OUTBOUND_PRE;
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO_INVOKE:
+    sslHandshakeHookState = 
SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_HELLO;
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE:
+    sslHandshakeHookState = SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT;
+    break;
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_VERIFY_SERVER:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT:
+    break;
+  default:
+    break;
+  }
+}
diff --git a/src/iocore/net/TLSSNISupport.cc b/src/iocore/net/TLSSNISupport.cc
index 090ad9d00d..4de80326d6 100644
--- a/src/iocore/net/TLSSNISupport.cc
+++ b/src/iocore/net/TLSSNISupport.cc
@@ -127,8 +127,6 @@ TLSSNISupport::on_client_hello(ClientHello &client_hello)
 void
 TLSSNISupport::on_servername(SSL *ssl, int * /* al ATS_UNUSED */, void * /* 
arg ATS_UNUSED */)
 {
-  this->_fire_ssl_servername_event();
-
   const char *name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
   if (name) {
     this->_set_sni_server_name(name);

Reply via email to