Implement SNI support for the TlsStream class
authorGunnar Beutner <gunnar@beutner.name>
Thu, 5 Mar 2015 13:15:42 +0000 (14:15 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Thu, 5 Mar 2015 13:15:42 +0000 (14:15 +0100)
fixes #8610

lib/base/tlsstream.cpp
lib/base/tlsstream.hpp
lib/cli/pkiutility.cpp
lib/remote/apilistener.cpp
lib/remote/apilistener.hpp

index f9bbb6de253505bc50a294913a215f001e33aaa9..6f6ab788b54bf90d648d8530040214fb79b36345 100644 (file)
@@ -39,7 +39,7 @@ bool I2_EXPORT TlsStream::m_SSLIndexInitialized = false;
  * @param role The role of the client.
  * @param sslContext The SSL context for the client.
  */
-TlsStream::TlsStream(const Socket::Ptr& socket, ConnectionRole role, const boost::shared_ptr<SSL_CTX>& sslContext)
+TlsStream::TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const boost::shared_ptr<SSL_CTX>& sslContext)
        : SocketEvents(socket, this), m_Eof(false), m_HandshakeOK(false), m_VerifyOK(true), m_ErrorCode(0),
          m_ErrorOccurred(false),  m_Socket(socket), m_Role(role), m_SendQ(new FIFO()), m_RecvQ(new FIFO()),
          m_CurrentAction(TlsActionNone), m_Retry(false)
@@ -73,8 +73,14 @@ TlsStream::TlsStream(const Socket::Ptr& socket, ConnectionRole role, const boost
 
        if (m_Role == RoleServer)
                SSL_set_accept_state(m_SSL.get());
-       else
+       else {
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+               if (!hostname.IsEmpty())
+                       SSL_set_tlsext_host_name(m_SSL.get(), hostname.CStr());
+#endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
+
                SSL_set_connect_state(m_SSL.get());
+       }
 }
 
 TlsStream::~TlsStream(void)
index c0c6907d3203bde74d7d0f3e8e4894e34570f86c..cc627b1b5d93f882a2a81179cb2e77fe44016787 100644 (file)
@@ -48,7 +48,7 @@ class I2_BASE_API TlsStream : public Stream, private SocketEvents
 public:
        DECLARE_PTR_TYPEDEFS(TlsStream);
 
-       TlsStream(const Socket::Ptr& socket, ConnectionRole role, const boost::shared_ptr<SSL_CTX>& sslContext);
+       TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const boost::shared_ptr<SSL_CTX>& sslContext);
        ~TlsStream(void);
 
        boost::shared_ptr<X509> GetClientCertificate(void) const;
index ab8f7b04e4a51a90cdc6b525076f4f8c9ff6fdd2..9a1c11ef099e5f5dbe0366b0511a05d17f7361cd 100644 (file)
@@ -153,7 +153,7 @@ int PkiUtility::SaveCert(const String& host, const String& port, const String& k
                return 1;
        }
 
-       TlsStream::Ptr stream = new TlsStream(client, RoleClient, sslContext);
+       TlsStream::Ptr stream = new TlsStream(client, String(), RoleClient, sslContext);
 
        try {
                stream->Handshake();
@@ -219,7 +219,7 @@ int PkiUtility::RequestCertificate(const String& host, const String& port, const
                return 1;
        }
 
-       TlsStream::Ptr stream = new TlsStream(client, RoleClient, sslContext);
+       TlsStream::Ptr stream = new TlsStream(client, String(), RoleClient, sslContext);
 
        try {
                stream->Handshake();
index cda6ccd754eac092333ab466b35ab0b6aafc3641..7fe35b5c9725c01f1c5ef39061f7ba5d0c4e47c8 100644 (file)
@@ -210,7 +210,7 @@ void ApiListener::ListenerThreadProc(const Socket::Ptr& server)
        for (;;) {
                try {
                        Socket::Ptr client = server->Accept();
-                       Utility::QueueAsyncCallback(boost::bind(&ApiListener::NewClientHandler, this, client, RoleServer), LowLatencyScheduler);
+                       Utility::QueueAsyncCallback(boost::bind(&ApiListener::NewClientHandler, this, client, String(), RoleServer), LowLatencyScheduler);
                } catch (const std::exception&) {
                        Log(LogCritical, "ApiListener", "Cannot accept new connection.");
                }
@@ -246,7 +246,7 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)
        try {
                endpoint->SetConnecting(true);
                client->Connect(host, port);
-               NewClientHandler(client, RoleClient);
+               NewClientHandler(client, endpoint->GetName(), RoleClient);
                endpoint->SetConnecting(false);
        } catch (const std::exception& ex) {
                endpoint->SetConnecting(false);
@@ -265,7 +265,7 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)
  *
  * @param client The new client.
  */
-void ApiListener::NewClientHandler(const Socket::Ptr& client, ConnectionRole role)
+void ApiListener::NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role)
 {
        CONTEXT("Handling new API client connection");
 
@@ -274,7 +274,7 @@ void ApiListener::NewClientHandler(const Socket::Ptr& client, ConnectionRole rol
        {
                ObjectLock olock(this);
                try {
-                       tlsStream = new TlsStream(client, role, m_SSLContext);
+                       tlsStream = new TlsStream(client, hostname, role, m_SSLContext);
                } catch (const std::exception&) {
                        Log(LogCritical, "ApiListener", "Cannot create TLS stream from client connection.");
                        return;
index 642db025ed02d6ea2f277f1b30df5e985d829d6d..7f3cc505729a520e1eccc75e5e6e7f6e4203f0dd 100644 (file)
@@ -86,7 +86,7 @@ private:
        bool AddListener(const String& node, const String& service);
        void AddConnection(const Endpoint::Ptr& endpoint);
 
-       void NewClientHandler(const Socket::Ptr& client, ConnectionRole role);
+       void NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role);
        void ListenerThreadProc(const Socket::Ptr& server);
 
        WorkQueue m_RelayQueue;