diff --git a/src/HTTP/UrlClient.cpp b/src/HTTP/UrlClient.cpp index 167ceab0f..4320d3c29 100644 --- a/src/HTTP/UrlClient.cpp +++ b/src/HTTP/UrlClient.cpp @@ -315,7 +315,7 @@ public: m_Link = &a_Link; if (m_IsTls) { - m_Link->StartTLSClient(m_ParentRequest.GetOwnCert(), m_ParentRequest.GetOwnPrivKey(), m_ParentRequest.m_UrlHost); + m_Link->StartTLSClient(m_ParentRequest.GetOwnCert(), m_ParentRequest.GetOwnPrivKey()); } else { diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h index f4ec4f0ee..c8647c83c 100644 --- a/src/OSSupport/Network.h +++ b/src/OSSupport/Network.h @@ -129,8 +129,7 @@ public: Returns empty string on success, non-empty error description on failure. */ virtual AString StartTLSClient( cX509CertPtr a_OwnCert, - cCryptoKeyPtr a_OwnPrivKey, - const std::string_view hostname + cCryptoKeyPtr a_OwnPrivKey ) = 0; /** Starts a TLS handshake as a server connection. diff --git a/src/OSSupport/TCPLinkImpl.cpp b/src/OSSupport/TCPLinkImpl.cpp index 26eb6ef24..4009d4ec3 100644 --- a/src/OSSupport/TCPLinkImpl.cpp +++ b/src/OSSupport/TCPLinkImpl.cpp @@ -33,10 +33,11 @@ //////////////////////////////////////////////////////////////////////////////// // cTCPLinkImpl: -cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks): +cTCPLinkImpl::cTCPLinkImpl(const std::string & a_Host, cTCPLink::cCallbacksPtr a_LinkCallbacks): Super(std::move(a_LinkCallbacks)), m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)), m_LocalPort(0), + m_RemoteHost(a_Host), m_RemotePort(0), m_ShouldShutdown(false) { @@ -46,7 +47,13 @@ cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks): -cTCPLinkImpl::cTCPLinkImpl(evutil_socket_t a_Socket, cTCPLink::cCallbacksPtr a_LinkCallbacks, cServerHandleImplPtr a_Server, const sockaddr * a_Address, socklen_t a_AddrLen): +cTCPLinkImpl::cTCPLinkImpl( + evutil_socket_t a_Socket, + cTCPLink::cCallbacksPtr a_LinkCallbacks, + cServerHandleImplPtr a_Server, + const sockaddr * a_Address, + socklen_t a_AddrLen +): Super(std::move(a_LinkCallbacks)), m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), a_Socket, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)), m_Server(std::move(a_Server)), @@ -81,7 +88,7 @@ cTCPLinkImplPtr cTCPLinkImpl::Connect(const AString & a_Host, UInt16 a_Port, cTC ASSERT(a_ConnectCallbacks != nullptr); // Create a new link: - cTCPLinkImplPtr res{new cTCPLinkImpl(std::move(a_LinkCallbacks))}; // Cannot use std::make_shared here, constructor is not accessible + cTCPLinkImplPtr res{new cTCPLinkImpl(a_Host, std::move(a_LinkCallbacks))}; // Cannot use std::make_shared here, constructor is not accessible res->m_ConnectCallbacks = std::move(a_ConnectCallbacks); cNetworkSingleton::Get().AddLink(res); res->m_Callbacks->OnLinkCreated(res); @@ -253,8 +260,7 @@ void cTCPLinkImpl::Close(void) AString cTCPLinkImpl::StartTLSClient( cX509CertPtr a_OwnCert, - cCryptoKeyPtr a_OwnPrivKey, - const std::string_view hostname + cCryptoKeyPtr a_OwnPrivKey ) { // Check preconditions: @@ -280,7 +286,11 @@ AString cTCPLinkImpl::StartTLSClient( m_TlsContext->Initialize(true); } - m_TlsContext->SetExpectedPeerName(hostname); + // Enable SNI / peer name verification: + if (!m_RemoteHost.empty()) + { + m_TlsContext->SetExpectedPeerName(m_RemoteHost); + } m_TlsContext->SetSelf(cLinkTlsContextWPtr(m_TlsContext)); diff --git a/src/OSSupport/TCPLinkImpl.h b/src/OSSupport/TCPLinkImpl.h index 2805d7d96..311aa132a 100644 --- a/src/OSSupport/TCPLinkImpl.h +++ b/src/OSSupport/TCPLinkImpl.h @@ -56,9 +56,16 @@ public: /** Creates a new link based on the given socket. Used for connections accepted in a server using cNetwork::Listen(). + a_Host is the hostname used for TLS SNI (can be empty in cases TLS is not used). a_Address and a_AddrLen describe the remote peer that has connected. The link is created disabled, you need to call Enable() to start the regular communication. */ - cTCPLinkImpl(evutil_socket_t a_Socket, cCallbacksPtr a_LinkCallbacks, cServerHandleImplPtr a_Server, const sockaddr * a_Address, socklen_t a_AddrLen); + cTCPLinkImpl( + evutil_socket_t a_Socket, + cCallbacksPtr a_LinkCallbacks, + cServerHandleImplPtr a_Server, + const sockaddr * a_Address, + socklen_t a_AddrLen + ); /** Destroys the LibEvent handle representing the link. */ virtual ~cTCPLinkImpl() override; @@ -84,8 +91,7 @@ public: virtual void Close(void) override; virtual AString StartTLSClient( cX509CertPtr a_OwnCert, - cCryptoKeyPtr a_OwnPrivKey, - const std::string_view hostname + cCryptoKeyPtr a_OwnPrivKey ) override; virtual AString StartTLSServer( cX509CertPtr a_OwnCert, @@ -167,6 +173,10 @@ protected: /** The port of the local endpoint. Valid only after the socket has been connected. */ UInt16 m_LocalPort; + /** The original host parameter which was used for creating the link, either hostname or IP address. + Used for TLS SNI. */ + AString m_RemoteHost; + /** The IP address of the remote endpoint. Valid only after the socket has been connected. */ AString m_RemoteIP; @@ -191,7 +201,7 @@ protected: Used for outgoing connections created using cNetwork::Connect(). To be used only by the Connect() factory function. The link is created disabled, you need to call Enable() to start the regular communication. */ - cTCPLinkImpl(const cCallbacksPtr a_LinkCallbacks); + cTCPLinkImpl(const std::string & a_Host, const cCallbacksPtr a_LinkCallbacks); /** Callback that LibEvent calls when there's data available from the remote peer. */ static void ReadCallback(bufferevent * a_BufferEvent, void * a_Self); diff --git a/src/mbedTLS++/SslContext.h b/src/mbedTLS++/SslContext.h index 48f5a94f2..c54703791 100644 --- a/src/mbedTLS++/SslContext.h +++ b/src/mbedTLS++/SslContext.h @@ -67,7 +67,9 @@ public: /** Returns true if the object has been initialized properly. */ bool IsValid(void) const { return m_IsValid; } - /** Sets the SSL peer name expected for this context. Must be called after Initialize(). + /** Sets the SSL peer name expected for this context. + This is used both for TLS SNI and for certificate validation. + Must be called after Initialize(). \param a_ExpectedPeerName CommonName that we expect the SSL peer to have in its cert, if it is different, the verification will fail. An empty string will disable the CN check. */ void SetExpectedPeerName(const std::string_view a_ExpectedPeerName);