(websocket+tls) fix hang in tls handshake which could lead to ANR, discovered through unittesting.
This commit is contained in:
		@@ -1,6 +1,10 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
All changes to this project will be documented in this file.
 | 
					All changes to this project will be documented in this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [8.3.2] - 2020-03-20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(websocket+tls) fix hang in tls handshake which could lead to ANR, discovered through unittesting.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [8.3.1] - 2020-03-20
 | 
					## [8.3.1] - 2020-03-20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(cobra) CobraMetricsPublisher can be configure with an ix::CobraConfig + more unittest use SSL in server + client
 | 
					(cobra) CobraMetricsPublisher can be configure with an ix::CobraConfig + more unittest use SSL in server + client
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,6 +164,26 @@ namespace ix
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OSStatus SocketAppleSSL::tlsHandShake(std::string& errMsg,
 | 
				
			||||||
 | 
					                                          const CancellationRequest& isCancellationRequested)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        OSStatus status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        do
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            status = SSLHandshake(_sslContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Interrupt the handshake
 | 
				
			||||||
 | 
					            if (isCancellationRequested())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                errMsg = "Cancellation requested";
 | 
				
			||||||
 | 
					                return errSSLInternal;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return status;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // No wait support
 | 
					    // No wait support
 | 
				
			||||||
    bool SocketAppleSSL::connect(const std::string& host,
 | 
					    bool SocketAppleSSL::connect(const std::string& host,
 | 
				
			||||||
                                 int port,
 | 
					                                 int port,
 | 
				
			||||||
@@ -190,26 +210,17 @@ namespace ix
 | 
				
			|||||||
                Boolean option(1);
 | 
					                Boolean option(1);
 | 
				
			||||||
                SSLSetSessionOption(_sslContext, kSSLSessionOptionBreakOnServerAuth, option);
 | 
					                SSLSetSessionOption(_sslContext, kSSLSessionOptionBreakOnServerAuth, option);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                do
 | 
					                status = tlsHandShake(errMsg, isCancellationRequested);
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    status = SSLHandshake(_sslContext);
 | 
					 | 
				
			||||||
                } while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (status == errSSLServerAuthCompleted)
 | 
					                if (status == errSSLServerAuthCompleted)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // proceed with the handshake
 | 
					                    // proceed with the handshake
 | 
				
			||||||
                    do
 | 
					                    status = tlsHandShake(errMsg, isCancellationRequested);
 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        status = SSLHandshake(_sslContext);
 | 
					 | 
				
			||||||
                    } while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                do
 | 
					                status = tlsHandShake(errMsg, isCancellationRequested);
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    status = SSLHandshake(_sslContext);
 | 
					 | 
				
			||||||
                } while (status == errSSLWouldBlock || status == errSSLServerAuthCompleted);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,10 @@ namespace ix
 | 
				
			|||||||
        static OSStatus writeToSocket(SSLConnectionRef connection, const void* data, size_t* len);
 | 
					        static OSStatus writeToSocket(SSLConnectionRef connection, const void* data, size_t* len);
 | 
				
			||||||
        static OSStatus readFromSocket(SSLConnectionRef connection, void* data, size_t* len);
 | 
					        static OSStatus readFromSocket(SSLConnectionRef connection, void* data, size_t* len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        OSStatus tlsHandShake(
 | 
				
			||||||
 | 
					            std::string& errMsg,
 | 
				
			||||||
 | 
					            const CancellationRequest& isCancellationRequested);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SSLContextRef _sslContext;
 | 
					        SSLContextRef _sslContext;
 | 
				
			||||||
        mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
 | 
					        mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -195,8 +195,17 @@ namespace ix
 | 
				
			|||||||
        int res;
 | 
					        int res;
 | 
				
			||||||
        do
 | 
					        do
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::lock_guard<std::mutex> lock(_mutex);
 | 
					            {
 | 
				
			||||||
            res = mbedtls_ssl_handshake(&_ssl);
 | 
					                std::lock_guard<std::mutex> lock(_mutex);
 | 
				
			||||||
 | 
					                res = mbedtls_ssl_handshake(&_ssl);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (isCancellationRequested())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                errMsg = "Cancellation requested";
 | 
				
			||||||
 | 
					                close();
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        } while (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE);
 | 
					        } while (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (res != 0)
 | 
					        if (res != 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -224,7 +224,10 @@ namespace ix
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool SocketOpenSSL::openSSLClientHandshake(const std::string& host, std::string& errMsg)
 | 
					    bool SocketOpenSSL::openSSLClientHandshake(
 | 
				
			||||||
 | 
					        const std::string& host,
 | 
				
			||||||
 | 
					        std::string& errMsg,
 | 
				
			||||||
 | 
					        const CancellationRequest& isCancellationRequested)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        while (true)
 | 
					        while (true)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -233,6 +236,12 @@ namespace ix
 | 
				
			|||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (isCancellationRequested())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                errMsg = "Cancellation requested";
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ERR_clear_error();
 | 
					            ERR_clear_error();
 | 
				
			||||||
            int connect_result = SSL_connect(_ssl_connection);
 | 
					            int connect_result = SSL_connect(_ssl_connection);
 | 
				
			||||||
            if (connect_result == 1)
 | 
					            if (connect_result == 1)
 | 
				
			||||||
@@ -577,7 +586,7 @@ namespace ix
 | 
				
			|||||||
            X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection);
 | 
					            X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection);
 | 
				
			||||||
            X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0);
 | 
					            X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            handshakeSuccessful = openSSLClientHandshake(host, errMsg);
 | 
					            handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!handshakeSuccessful)
 | 
					        if (!handshakeSuccessful)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,9 @@ namespace ix
 | 
				
			|||||||
        void openSSLInitialize();
 | 
					        void openSSLInitialize();
 | 
				
			||||||
        std::string getSSLError(int ret);
 | 
					        std::string getSSLError(int ret);
 | 
				
			||||||
        SSL_CTX* openSSLCreateContext(std::string& errMsg);
 | 
					        SSL_CTX* openSSLCreateContext(std::string& errMsg);
 | 
				
			||||||
        bool openSSLClientHandshake(const std::string& hostname, std::string& errMsg);
 | 
					        bool openSSLClientHandshake(const std::string& hostname,
 | 
				
			||||||
 | 
					                                    std::string& errMsg,
 | 
				
			||||||
 | 
					                                    const CancellationRequest& isCancellationRequested);
 | 
				
			||||||
        bool openSSLCheckServerCert(SSL* ssl, const std::string& hostname, std::string& errMsg);
 | 
					        bool openSSLCheckServerCert(SSL* ssl, const std::string& hostname, std::string& errMsg);
 | 
				
			||||||
        bool checkHost(const std::string& host, const char* pattern);
 | 
					        bool checkHost(const std::string& host, const char* pattern);
 | 
				
			||||||
        bool handleTLSOptions(std::string& errMsg);
 | 
					        bool handleTLSOptions(std::string& errMsg);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IX_WEBSOCKET_VERSION "8.3.1"
 | 
					#define IX_WEBSOCKET_VERSION "8.3.2"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,7 +147,7 @@ namespace
 | 
				
			|||||||
TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
 | 
					TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int port = getFreePort();
 | 
					    int port = getFreePort();
 | 
				
			||||||
    bool preferTLS = false;
 | 
					    bool preferTLS = true;
 | 
				
			||||||
    snake::AppConfig appConfig = makeSnakeServerConfig(port, preferTLS);
 | 
					    snake::AppConfig appConfig = makeSnakeServerConfig(port, preferTLS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Start a redis server
 | 
					    // Start a redis server
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user