diff --git a/include/iocore/net/NetVConnection.h b/include/iocore/net/NetVConnection.h index a7d8bd8886d..7a89a116255 100644 --- a/include/iocore/net/NetVConnection.h +++ b/include/iocore/net/NetVConnection.h @@ -501,6 +501,7 @@ class NetVConnection : public VConnection, public PluginUserArgs_set_service(NetVConnection::Service::TLS_Basic, instance); } +class TLSEventSupport; +template <> +inline TLSEventSupport * +NetVConnection::get_service() const +{ + return static_cast(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 00000000000..2e71b9c0158 --- /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 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 1b35a683cf5..fbba3810d5f 100644 --- a/include/iocore/net/TLSSNISupport.h +++ b/include/iocore/net/TLSSNISupport.h @@ -82,8 +82,6 @@ class TLSSNISupport } 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 83aba649174..cf957ac97f7 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(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(vconn); - SSLNetVConnection *ssl_vc = dynamic_cast(vc); - // We really only deal with a SSLNetVConnection at the moment - if (ssl_vc != nullptr) { + NetVConnection *vc = reinterpret_cast(vconn); + + if (auto tes = vc->get_service(); 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 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 7d925af5155..45371e3c8d3 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 fd1ae299382..019f870eaa6 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 #include +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 @@ class QUICNetVConnection : public UnixNetVConnection, // QUICNetVConnection int in_closed_queue = 0; + // TLSEventSupport + void reenable(int event) override; + Continuation *getContinuationForTLSEvents() override; + EThread *getThreadForTLSEvents() override; + Ptr getMutexForTLSEvents() override; + bool shouldDestroy(); void destroy(EThread *t); void remove_connection_ids(); @@ -158,7 +167,6 @@ class QUICNetVConnection : public UnixNetVConnection, 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 @@ class QUICNetVConnection : public UnixNetVConnection, 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 0f54f75fa06..edce1e1206c 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 @@ class SSLNetVConnection : public UnixNetVConnection, // 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 @@ class SSLNetVConnection : public UnixNetVConnection, 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 @@ class SSLNetVConnection : public UnixNetVConnection, 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 getMutexForTLSEvents() override; + protected: + // TLSBasicSupport SSL * _get_ssl_object() const override { @@ -395,6 +328,7 @@ class SSLNetVConnection : public UnixNetVConnection, } ssl_curve_id _get_tls_curve() const override; + // TLSSessionResumptionSupport const IpEndpoint & _getLocalEndpoint() override { @@ -402,13 +336,24 @@ class SSLNetVConnection : public UnixNetVConnection, } // 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 @@ class SSLNetVConnection : public UnixNetVConnection, 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 d20330360e8..d6c002221c1 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 #include @@ -49,6 +52,7 @@ QUICNetVConnection::QUICNetVConnection() { this->_set_service(static_cast(this)); this->_set_service(static_cast(this)); + this->_set_service(static_cast(this)); this->_set_service(static_cast(this)); this->_set_service(static_cast(this)); this->_set_service(static_cast(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(this); } +void +QUICNetVConnection::reenable(int /* event ATS_UNUSED */) +{ +} + +Continuation * +QUICNetVConnection::getContinuationForTLSEvents() +{ + return this; +} + +EThread * +QUICNetVConnection::getThreadForTLSEvents() +{ + return this->thread; +} + +Ptr +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 51b6d4a897d..aef0ecf9f3a 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 dcf222aea77..0ca851ebc8b 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(this)); this->_set_service(static_cast(this)); + this->_set_service(static_cast(this)); this->_set_service(static_cast(this)); this->_set_service(static_cast(this)); this->_set_service(static_cast(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 +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 639cbfa4ad7..95680bccb36 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(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(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 00000000000..718332b9a17 --- /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 +#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(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 090ad9d00d9..4de80326d66 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);