You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2018/04/26 16:43:12 UTC

ignite git commit: IGNITE-8394: ODBC: Fixed async establishing of SSL connection

Repository: ignite
Updated Branches:
  refs/heads/master ebe55e3ff -> 1840f756d


IGNITE-8394: ODBC: Fixed async establishing of SSL connection

This closes #3925


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/1840f756
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/1840f756
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/1840f756

Branch: refs/heads/master
Commit: 1840f756dcd4a8cf1974b0b15dc716d65d285d41
Parents: ebe55e3
Author: Igor Sapego <is...@gridgain.com>
Authored: Thu Apr 26 19:36:25 2018 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Thu Apr 26 19:42:41 2018 +0300

----------------------------------------------------------------------
 .../cpp/odbc-test/src/queries_ssl_test.cpp      |   1 +
 .../ignite/odbc/ssl/secure_socket_client.h      |  57 +++-
 .../odbc/include/ignite/odbc/ssl/ssl_bindings.h | 146 ++++++---
 .../odbc/include/ignite/odbc/ssl/ssl_gateway.h  |  16 +-
 .../os/win/src/system/tcp_socket_client.cpp     |   1 -
 .../cpp/odbc/src/ssl/secure_socket_client.cpp   | 298 ++++++++++++-------
 .../platforms/cpp/odbc/src/ssl/ssl_gateway.cpp  |  37 ++-
 7 files changed, 378 insertions(+), 178 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/1840f756/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp b/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp
index 47eb5dc..861bef1 100644
--- a/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/queries_ssl_test.cpp
@@ -19,6 +19,7 @@
 
 #include <vector>
 #include <string>
+#include <sstream>
 
 #ifndef _MSC_VER
 #   define BOOST_TEST_DYN_LINK

http://git-wip-us.apache.org/repos/asf/ignite/blob/1840f756/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h
index f6da30d..f8ca0be 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/secure_socket_client.h
@@ -55,7 +55,7 @@ namespace ignite
                  *
                  * @param hostname Host name or address.
                  * @param port TCP port.
-                 * @param timeout Timeout.
+                 * @param timeout Timeout in seconds.
                  * @param diag Diagnostics collector to use for error-reporting.
                  * @return @c true on success and @c false on fail.
                  */
@@ -71,7 +71,7 @@ namespace ignite
                  * Send data using connection.
                  * @param data Data to send.
                  * @param size Number of bytes to send.
-                 * @param timeout Timeout.
+                 * @param timeout Timeout in seconds.
                  * @return Number of bytes that have been sent on success, 
                  *     WaitResult::TIMEOUT on timeout and -errno on failure.
                  */
@@ -82,7 +82,7 @@ namespace ignite
                  *
                  * @param buffer Pointer to data buffer.
                  * @param size Size of the buffer in bytes.
-                 * @param timeout Timeout.
+                 * @param timeout Timeout in seconds.
                  * @return Number of bytes that have been received on success,
                  *     WaitResult::TIMEOUT on timeout and -errno on failure.
                  */
@@ -106,12 +106,13 @@ namespace ignite
                  * This function uses poll to achive timeout functionality
                  * for every separate socket operation.
                  *
-                 * @param timeout Timeout.
+                 * @param ssl SSL instance.
+                 * @param timeout Timeout in seconds.
                  * @param rd Wait for read if @c true, or for write if @c false.
                  * @return -errno on error, WaitResult::TIMEOUT on timeout and
                  *     WaitResult::SUCCESS on success.
                  */
-                int WaitOnSocket(int32_t timeout, bool rd);
+                static int WaitOnSocket(void* ssl, int32_t timeout, bool rd);
 
                 /**
                  * Make new context instance.
@@ -120,11 +121,51 @@ namespace ignite
                  * @param keyPath Private key file path.
                  * @param caPath Certificate authority file path.
                  * @param diag Diagnostics collector to use for error-reporting.
-                 * @return New context instance on success and null-opinter on fail.
+                 * @return New context instance on success and null-pointer on fail.
                  */
                 static void* MakeContext(const std::string& certPath, const std::string& keyPath,
                     const std::string& caPath, diagnostic::Diagnosable& diag);
 
+                /**
+                 * Make new SSL instance.
+                 *
+                 * @param context SSL context.
+                 * @param hostname Host name or address.
+                 * @param port TCP port.
+                 * @param blocking Indicates if the resulted SSL is blocking or not.
+                 * @param diag Diagnostics collector to use for error-reporting.
+                 * @return New SSL instance on success and null-pointer on fail.
+                 */
+                static void* MakeSsl(void* context, const char* hostname, uint16_t port,
+                    bool& blocking, diagnostic::Diagnosable& diag);
+
+                /**
+                 * Complete async connect.
+                 *
+                 * @param ssl SSL instance.
+                 * @param timeout Timeout in seconds.
+                 * @param diag Diagnostics collector to use for error-reporting.
+                 * @return @c true on success.
+                 */
+                static bool CompleteConnectInternal(void* ssl, int timeout, diagnostic::Diagnosable& diag);
+
+                /**
+                 * Get SSL error.
+                 *
+                 * @param ssl SSL instance.
+                 * @param ret Return value of the pervious operation.
+                 * @return Error string.
+                 */
+                static std::string GetSslError(void* ssl, int ret);
+                
+                /**
+                 * Check if a actual error occured.
+                 *
+                 * @param err SSL error code.
+                 * @return @true if a actual error occured
+                 */
+                static bool IsActualError(int err);
+
                 /** Certificate file path. */
                 std::string certPath;
 
@@ -137,8 +178,8 @@ namespace ignite
                 /** SSL context. */
                 void* context;
 
-                /** OpenSSL I/O stream abstraction */
-                void* sslBio;
+                /** OpenSSL instance */
+                void* ssl;
 
                 /** Blocking flag. */
                 bool blocking;

http://git-wip-us.apache.org/repos/asf/ignite/blob/1840f756/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h
index b23533a..9a1740d 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_bindings.h
@@ -20,6 +20,7 @@
 
 #include <openssl/ssl.h>
 #include <openssl/conf.h>
+#include <openssl/err.h>
 
 #include "ignite/odbc/ssl/ssl_gateway.h"
 
@@ -173,84 +174,133 @@ namespace ignite
                     TLSEXT_NAMETYPE_host_name, const_cast<char*>(name));
             }
 
+            inline void SSL_set_connect_state_(SSL* s)
+            {
+                typedef void(FuncType)(SSL*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSL_set_connect_state);
 
+                return fp(s);
+            }
 
-            inline const SSL_METHOD *SSLv23_method()
+            inline int SSL_connect_(SSL* s)
             {
-                typedef const SSL_METHOD*(FuncType)();
+                typedef int(FuncType)(SSL*);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSLv23_method);
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_connect);
 
-                return fp();
+                return fp(s);
             }
 
-            inline void OPENSSL_config(const char *configName)
+            inline int SSL_get_error_(const SSL *s, int ret)
             {
-                typedef void(FuncType)(const char*);
+                typedef int(FuncType)(const SSL*, int);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpOPENSSL_config);
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_get_error);
 
-                fp(configName);
+                return fp(s, ret);
             }
 
-            inline void X509_free(X509 *a)
+            inline int SSL_want_(const SSL *s)
             {
-                typedef void(FuncType)(X509*);
+                typedef int(FuncType)(const SSL*);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpX509_free);
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_want);
 
-                fp(a);
+                return fp(s);
             }
 
-            inline BIO *BIO_new_ssl_connect(SSL_CTX *ctx)
+            inline int SSL_write_(SSL *s, const void *buf, int num)
             {
-                typedef BIO*(FuncType)(SSL_CTX*);
+                typedef int(FuncType)(SSL*, const void*, int);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(
-                    SslGateway::GetInstance().GetFunctions().fpBIO_new_ssl_connect);
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_write);
 
-                return fp(ctx);
+                return fp(s, buf, num);
             }
 
-            inline int BIO_write(BIO *b, const void *data, int len)
+            inline int SSL_read_(SSL *s, void *buf, int num)
             {
-                typedef int(FuncType)(BIO*, const void*, int);
+                typedef int(FuncType)(SSL*, void*, int);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_write);
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_read);
 
-                return fp(b, data, len);
+                return fp(s, buf, num);
             }
 
-            inline int BIO_read(BIO *b, void *data, int len)
+            inline int SSL_pending_(const SSL *ssl)
             {
-                typedef int(FuncType)(BIO*, const void*, int);
+                typedef int(FuncType)(const SSL*);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_read);
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_pending);
 
-                return fp(b, data, len);
+                return fp(ssl);
             }
 
-            inline void BIO_free_all(BIO *a)
+            inline int SSL_get_fd_(const SSL *ssl)
             {
-                typedef void(FuncType)(BIO*);
+                typedef int(FuncType)(const SSL*);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_free_all);
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_get_fd);
+
+                return fp(ssl);
+            }
+
+            inline void SSL_free_(SSL *ssl)
+            {
+                typedef void(FuncType)(SSL*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpSSL_free);
+
+                fp(ssl);
+            }
+
+            inline const SSL_METHOD *SSLv23_client_method_()
+            {
+                typedef const SSL_METHOD*(FuncType)();
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpSSLv23_client_method);
+
+                return fp();
+            }
+
+            inline void OPENSSL_config(const char *configName)
+            {
+                typedef void(FuncType)(const char*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpOPENSSL_config);
+
+                fp(configName);
+            }
+
+            inline void X509_free(X509 *a)
+            {
+                typedef void(FuncType)(X509*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpX509_free);
 
                 fp(a);
             }
 
-            inline int BIO_test_flags(const BIO *b, int flags)
+            inline BIO *BIO_new_ssl_connect(SSL_CTX *ctx)
             {
-                typedef int(FuncType)(const BIO*, int);
+                typedef BIO*(FuncType)(SSL_CTX*);
 
-                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_test_flags);
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpBIO_new_ssl_connect);
 
-                return fp(b, flags);
+                return fp(ctx);
             }
 
-            inline int BIO_should_retry_(const BIO *b)
+            inline void BIO_free_all(BIO *a)
             {
-                return ssl::BIO_test_flags(b, BIO_FLAGS_SHOULD_RETRY);
+                typedef void(FuncType)(BIO*);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpBIO_free_all);
+
+                fp(a);
             }
 
             inline long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg)
@@ -267,16 +317,6 @@ namespace ignite
                 return ssl::BIO_ctrl(bp, BIO_C_GET_FD, 0, reinterpret_cast<void*>(fd));
             }
 
-            inline long BIO_do_handshake_(BIO *bp)
-            {
-                return ssl::BIO_ctrl(bp, BIO_C_DO_STATE_MACHINE, 0, NULL);
-            }
-
-            inline long BIO_do_connect_(BIO *bp)
-            {
-                return ssl::BIO_do_handshake_(bp);
-            }
-
             inline long BIO_get_ssl_(BIO *bp, SSL** ssl)
             {
                 return ssl::BIO_ctrl(bp, BIO_C_GET_SSL, 0, reinterpret_cast<void*>(ssl));
@@ -292,9 +332,23 @@ namespace ignite
                 return ssl::BIO_ctrl(bp, BIO_C_SET_CONNECT, 0, const_cast<char*>(name));
             }
 
-            inline long BIO_pending_(BIO *bp)
+            inline unsigned long ERR_get_error_()
+            {
+                typedef unsigned long(FuncType)();
+
+                FuncType* fp = reinterpret_cast<FuncType*>(SslGateway::GetInstance().GetFunctions().fpERR_get_error);
+
+                return fp();
+            }
+
+            inline void ERR_error_string_n_(unsigned long e, char *buf, size_t len)
             {
-                return ssl::BIO_ctrl(bp, BIO_CTRL_PENDING, 0, NULL);
+                typedef void(FuncType)(unsigned long, char*, size_t);
+
+                FuncType* fp = reinterpret_cast<FuncType*>(
+                    SslGateway::GetInstance().GetFunctions().fpERR_error_string_n);
+
+                fp(e, buf, len);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1840f756/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h
index b131228..4b102ad 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/ssl/ssl_gateway.h
@@ -46,15 +46,23 @@ namespace ignite
                 void *fpSSL_load_error_strings;
                 void *fpSSL_get_peer_certificate;
                 void *fpSSL_ctrl;
-                void *fpSSLv23_method;
+                void *fpSSLv23_client_method;
+                void *fpSSL_set_connect_state;
+                void *fpSSL_connect;
+                void *fpSSL_get_error;
+                void *fpSSL_want;
+                void *fpSSL_write;
+                void *fpSSL_read;
+                void *fpSSL_pending;
+                void *fpSSL_get_fd;
+                void *fpSSL_free;
                 void *fpOPENSSL_config;
                 void *fpX509_free;
                 void *fpBIO_new_ssl_connect;
-                void *fpBIO_write;
-                void *fpBIO_read;
                 void *fpBIO_free_all;
-                void *fpBIO_test_flags;
                 void *fpBIO_ctrl;
+                void *fpERR_get_error;
+                void *fpERR_error_string_n;
             };
 
             /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/1840f756/modules/platforms/cpp/odbc/os/win/src/system/tcp_socket_client.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/os/win/src/system/tcp_socket_client.cpp b/modules/platforms/cpp/odbc/os/win/src/system/tcp_socket_client.cpp
index e891ebf..38e8b97 100644
--- a/modules/platforms/cpp/odbc/os/win/src/system/tcp_socket_client.cpp
+++ b/modules/platforms/cpp/odbc/os/win/src/system/tcp_socket_client.cpp
@@ -97,7 +97,6 @@ namespace ignite
     {
         namespace system
         {
-
             TcpSocketClient::TcpSocketClient() :
                 socketHandle(INVALID_SOCKET),
                 blocking(true)

http://git-wip-us.apache.org/repos/asf/ignite/blob/1840f756/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp b/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp
index 602dec6..84eb1e8 100644
--- a/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp
+++ b/modules/platforms/cpp/odbc/src/ssl/secure_socket_client.cpp
@@ -23,6 +23,7 @@
 #include "ignite/odbc/system/tcp_socket_client.h"
 #include "ignite/odbc/ssl/secure_socket_client.h"
 #include "ignite/odbc/ssl/ssl_bindings.h"
+#include "ignite/common/utils.h"
 
 #ifndef SOCKET_ERROR
 #   define SOCKET_ERROR (-1)
@@ -40,7 +41,7 @@ namespace ignite
                 keyPath(keyPath),
                 caPath(caPath),
                 context(0),
-                sslBio(0),
+                ssl(0),
                 blocking(true)
             {
                 // No-op.
@@ -72,115 +73,60 @@ namespace ignite
                     }
                 }
 
-                BIO* bio = ssl::BIO_new_ssl_connect(reinterpret_cast<SSL_CTX*>(context));
-                if (!bio)
-                {
-                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not create SSL connection.");
-
-                    return false;
-                }
-
-                blocking = false;
-                long res = ssl::BIO_set_nbio_(bio, 1);
-                if (res != OPERATION_SUCCESS)
-                {
-                    blocking = true;
-
-                    diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
-                        "Can not set up non-blocking mode. Timeouts are not available.");
-                }
-
-                std::stringstream stream;
-                stream << hostname << ":" << port;
-
-                std::string address = stream.str();
-
-                res = ssl::BIO_set_conn_hostname_(bio, address.c_str());
-                if (res != OPERATION_SUCCESS)
-                {
-                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not set SSL connection hostname.");
-
-                    ssl::BIO_free_all(bio);
-
-                    return false;
-                }
-
-                SSL* ssl = 0;
-                ssl::BIO_get_ssl_(bio, &ssl);
-                if (!ssl)
-                {
-                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not get SSL instance from BIO.");
-
-                    ssl::BIO_free_all(bio);
-
+                SSL* ssl0 = reinterpret_cast<SSL*>(MakeSsl(context, hostname, port, blocking, diag));
+                if (!ssl0)
                     return false;
-                }
 
-                res = ssl::SSL_set_tlsext_host_name_(ssl, hostname);
+                int res = ssl::SSL_set_tlsext_host_name_(ssl0, hostname);
                 if (res != OPERATION_SUCCESS)
                 {
-                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not set host name for secure connection");
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Can not set host name for secure connection: " + GetSslError(ssl0, res));
 
-                    ssl::BIO_free_all(bio);
+                    ssl::SSL_free_(ssl0);
 
                     return false;
                 }
 
-                do
-                {
-                    res = ssl::BIO_do_connect_(bio);
-                } while (ssl::BIO_should_retry_(bio));
+                ssl::SSL_set_connect_state_(ssl0);
 
-                if (res != OPERATION_SUCCESS)
-                {
-                    diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT,
-                        "Failed to establish secure connection with the host.");
-
-                    ssl::BIO_free_all(bio);
-
-                    return false;
-                }
+                bool connected = CompleteConnectInternal(ssl0, DEFALT_CONNECT_TIMEOUT, diag);
 
-                do
+                if (!connected)
                 {
-                    res = ssl::BIO_do_handshake_(bio);
-                } while (ssl::BIO_should_retry_(bio));
-
-                if (res != OPERATION_SUCCESS)
-                {
-                    diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, "SSL handshake failed.");
-
-                    ssl::BIO_free_all(bio);
+                    ssl::SSL_free_(ssl0);
 
                     return false;
                 }
 
                 // Verify a server certificate was presented during the negotiation
-                X509* cert = ssl::SSL_get_peer_certificate(ssl);
+                X509* cert = ssl::SSL_get_peer_certificate(ssl0);
                 if (cert)
                     ssl::X509_free(cert);
                 else
                 {
-                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Remote host did not provide certificate.");
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Remote host did not provide certificate: " + GetSslError(ssl0, res));
 
-                    ssl::BIO_free_all(bio);
+                    ssl::SSL_free_(ssl0);
 
                     return false;
                 }
 
                 // Verify the result of chain verification
                 // Verification performed according to RFC 4158
-                res = ssl::SSL_get_verify_result(ssl);
+                res = ssl::SSL_get_verify_result(ssl0);
                 if (X509_V_OK != res)
                 {
-                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Certificate chain verification failed.");
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR,
+                        "Certificate chain verification failed: " + GetSslError(ssl0, res));
 
-                    ssl::BIO_free_all(bio);
+                    ssl::SSL_free_(ssl0);
 
                     return false;
                 }
 
-                sslBio = reinterpret_cast<void*>(bio);
+                ssl = reinterpret_cast<void*>(ssl0);
 
                 return true;
             }
@@ -194,22 +140,16 @@ namespace ignite
             {
                 assert(SslGateway::GetInstance().Loaded());
 
-                if (!sslBio)
+                if (!ssl)
                 {
                     LOG_MSG("Trying to send data using closed connection");
 
                     return -1;
                 }
 
-                BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio);
+                SSL* ssl0 = reinterpret_cast<SSL*>(ssl);
 
-                int res = 0;
-
-                do
-                {
-                    res = ssl::BIO_write(sslBio0, data, static_cast<int>(size));
-                }
-                while (ssl::BIO_should_retry_(sslBio0));
+                int res = ssl::SSL_write_(ssl0, data, static_cast<int>(size));
 
                 return res;
             }
@@ -218,30 +158,26 @@ namespace ignite
             {
                 assert(SslGateway::GetInstance().Loaded());
 
-                if (!sslBio)
+                if (!ssl)
                 {
                     LOG_MSG("Trying to receive data using closed connection");
 
                     return -1;
                 }
 
-                BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio);
+                SSL* ssl0 = reinterpret_cast<SSL*>(ssl);
 
                 int res = 0;
 
-                if (!blocking && BIO_pending_(sslBio0) == 0)
+                if (!blocking && ssl::SSL_pending_(ssl0) == 0)
                 {
-                    res = WaitOnSocket(timeout, true);
+                    res = WaitOnSocket(ssl, timeout, true);
 
                     if (res < 0 || res == WaitResult::TIMEOUT)
                         return res;
                 }
 
-                do
-                {
-                    res = ssl::BIO_read(sslBio0, buffer, static_cast<int>(size));
-                }
-                while (ssl::BIO_should_retry_(sslBio0));
+                res = ssl::SSL_read_(ssl0, buffer, static_cast<int>(size));
 
                 return res;
             }
@@ -277,10 +213,10 @@ namespace ignite
                     }
                 }
 
-                const SSL_METHOD* method = SSLv23_method();
+                const SSL_METHOD* method = ssl::SSLv23_client_method_();
                 if (!method)
                 {
-                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not create new SSL method.");
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not get SSL method.");
 
                     return 0;
                 }
@@ -350,34 +286,180 @@ namespace ignite
                 return ctx;
             }
 
+            void* SecureSocketClient::MakeSsl(void* context, const char* hostname, uint16_t port,
+                bool& blocking, diagnostic::Diagnosable& diag)
+            {
+                BIO* bio = ssl::BIO_new_ssl_connect(reinterpret_cast<SSL_CTX*>(context));
+                if (!bio)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not create SSL connection.");
+
+                    return 0;
+                }
+
+                blocking = false;
+                long res = ssl::BIO_set_nbio_(bio, 1);
+                if (res != OPERATION_SUCCESS)
+                {
+                    blocking = true;
+
+                    diag.AddStatusRecord(SqlState::S01S02_OPTION_VALUE_CHANGED,
+                        "Can not set up non-blocking mode. Timeouts are not available.");
+                }
+
+                std::stringstream stream;
+                stream << hostname << ":" << port;
+
+                std::string address = stream.str();
+
+                res = ssl::BIO_set_conn_hostname_(bio, address.c_str());
+                if (res != OPERATION_SUCCESS)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not set SSL connection hostname.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return 0;
+                }
+
+                SSL* ssl = 0;
+                ssl::BIO_get_ssl_(bio, &ssl);
+                if (!ssl)
+                {
+                    diag.AddStatusRecord(SqlState::SHY000_GENERAL_ERROR, "Can not get SSL instance from BIO.");
+
+                    ssl::BIO_free_all(bio);
+
+                    return 0;
+                }
+
+                return ssl;
+            }
+
+            bool SecureSocketClient::CompleteConnectInternal(void* ssl, int timeout, diagnostic::Diagnosable& diag)
+            {
+                SSL* ssl0 = reinterpret_cast<SSL*>(ssl);
+
+                while (true)
+                {
+                    int res = ssl::SSL_connect_(ssl0);
+
+                    if (res == OPERATION_SUCCESS)
+                        return true;
+
+                    int sslError = ssl::SSL_get_error_(ssl0, res);
+
+                    LOG_MSG("wait res=" << res << ", sslError=" << sslError);
+
+                    if (IsActualError(sslError))
+                    {
+                        diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT,
+                            "Can not establish secure connection: " + GetSslError(ssl0, res));
+
+                        return false;
+                    }
+
+                    int want = ssl::SSL_want_(ssl0);
+
+                    res = WaitOnSocket(ssl, timeout, want == SSL_READING);
+
+                    LOG_MSG("wait res=" << res << ", want=" << want);
+
+                    if (res == WaitResult::TIMEOUT)
+                    {
+                        diag.AddStatusRecord(SqlState::SHYT01_CONNECTION_TIMEOUT,
+                            "Can not establish secure connection: Timeout expired (" +
+                                common::LexicalCast<std::string>(timeout) + " seconds)");
+
+                        return false;
+                    }
+
+                    if (res != WaitResult::SUCCESS)
+                    {
+                        diag.AddStatusRecord(SqlState::S08001_CANNOT_CONNECT,
+                            "Can not establish secure connection due to internal error");
+
+                        return false;
+                    }
+                }
+            }
+
+            std::string SecureSocketClient::GetSslError(void* ssl, int ret)
+            {
+                SSL* ssl0 = reinterpret_cast<SSL*>(ssl);
+
+                int sslError = ssl::SSL_get_error_(ssl0, ret);
+
+                LOG_MSG("ssl_error: " << sslError);
+
+                switch (sslError)
+                {
+                    case SSL_ERROR_NONE:
+                        break;
+
+                    case SSL_ERROR_WANT_WRITE:
+                        return std::string("SSL_connect wants write");
+                        
+                    case SSL_ERROR_WANT_READ:
+                        return std::string("SSL_connect wants read");
+
+                    default:
+                        return std::string("SSL error: ") + common::LexicalCast<std::string>(sslError);
+                }
+
+                long error = ssl::ERR_get_error_();
+
+                char errBuf[1024] = { 0 };
+
+                ssl::ERR_error_string_n_(error, errBuf, sizeof(errBuf));
+
+                return std::string(errBuf);
+            }
+
+            bool SecureSocketClient::IsActualError(int err)
+            {
+                switch (err)
+                {
+                    case SSL_ERROR_NONE:
+                    case SSL_ERROR_WANT_WRITE:
+                    case SSL_ERROR_WANT_READ:
+                    case SSL_ERROR_WANT_CONNECT:
+                    case SSL_ERROR_WANT_ACCEPT:
+                    case SSL_ERROR_WANT_X509_LOOKUP:
+                        return false;
+
+                    default:
+                        return true;
+                }
+            }
+
             void SecureSocketClient::CloseInteral()
             {
                 assert(SslGateway::GetInstance().Loaded());
 
-                if (sslBio)
+                if (ssl)
                 {
-                    ssl::BIO_free_all(reinterpret_cast<BIO*>(sslBio));
+                    ssl::SSL_free_(reinterpret_cast<SSL*>(ssl));
 
-                    sslBio = 0;
+                    ssl = 0;
                 }
             }
 
-            int SecureSocketClient::WaitOnSocket(int32_t timeout, bool rd)
+            int SecureSocketClient::WaitOnSocket(void* ssl, int32_t timeout, bool rd)
             {
                 int ready = 0;
                 int lastError = 0;
-                int fdSocket = 0;
-                BIO* sslBio0 = reinterpret_cast<BIO*>(sslBio);
+                SSL* ssl0 = reinterpret_cast<SSL*>(ssl);
 
                 fd_set fds;
 
-                long res = ssl::BIO_get_fd_(sslBio0, &fdSocket);
+                int fd = ssl::SSL_get_fd_(ssl0);
 
-                if (res < 0)
+                if (fd < 0)
                 {
-                    LOG_MSG("Can not get file descriptor from the SSL socket: " << res);
+                    LOG_MSG("Can not get file descriptor from the SSL socket: " << fd << ", " << GetSslError(ssl, fd));
 
-                    return res;
+                    return fd;
                 }
 
                 do {
@@ -385,7 +467,7 @@ namespace ignite
                     tv.tv_sec = timeout;
 
                     FD_ZERO(&fds);
-                    FD_SET(static_cast<long>(fdSocket), &fds);
+                    FD_SET(static_cast<long>(fd), &fds);
 
                     fd_set* readFds = 0;
                     fd_set* writeFds = 0;
@@ -395,7 +477,7 @@ namespace ignite
                     else
                         writeFds = &fds;
 
-                    ready = select(fdSocket + 1, readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv));
+                    ready = select(fd + 1, readFds, writeFds, NULL, (timeout == 0 ? NULL : &tv));
 
                     if (ready == SOCKET_ERROR)
                         lastError = system::TcpSocketClient::GetLastSocketError();
@@ -405,7 +487,7 @@ namespace ignite
                 if (ready == SOCKET_ERROR)
                     return -lastError;
 
-                lastError = system::TcpSocketClient::GetLastSocketError(fdSocket);
+                lastError = system::TcpSocketClient::GetLastSocketError(fd);
 
                 if (lastError != 0)
                     return -lastError;

http://git-wip-us.apache.org/repos/asf/ignite/blob/1840f756/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp b/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp
index 0fd7930..308302a 100644
--- a/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp
+++ b/modules/platforms/cpp/odbc/src/ssl/ssl_gateway.cpp
@@ -61,8 +61,6 @@ namespace ignite
 
                 std::string home = GetEnv(ADDITIONAL_OPENSSL_HOME_ENV);
 
-                std::cout << ADDITIONAL_OPENSSL_HOME_ENV << std::endl;
-
                 if (home.empty())
                     home = GetEnv("OPENSSL_HOME");
 
@@ -147,18 +145,27 @@ namespace ignite
                 functions.fpSSL_ctrl = LoadSslMethod("SSL_ctrl");
                 functions.fpSSL_CTX_ctrl = LoadSslMethod("SSL_CTX_ctrl");
 
-                functions.fpSSLv23_method = LoadSslMethod("SSLv23_method");
+                functions.fpSSLv23_client_method = LoadSslMethod("SSLv23_client_method");
+                functions.fpSSL_set_connect_state = LoadSslMethod("SSL_set_connect_state");
+                functions.fpSSL_connect = LoadSslMethod("SSL_connect");
+                functions.fpSSL_get_error = LoadSslMethod("SSL_get_error");
+                functions.fpSSL_want = LoadSslMethod("SSL_want");
+                functions.fpSSL_write = LoadSslMethod("SSL_write");
+                functions.fpSSL_read = LoadSslMethod("SSL_read");
+                functions.fpSSL_pending = LoadSslMethod("SSL_pending");
+                functions.fpSSL_get_fd = LoadSslMethod("SSL_get_fd");
+                functions.fpSSL_free = LoadSslMethod("SSL_free");
                 functions.fpBIO_new_ssl_connect = LoadSslMethod("BIO_new_ssl_connect");
 
                 functions.fpOPENSSL_config = LoadSslMethod("OPENSSL_config");
                 functions.fpX509_free = LoadSslMethod("X509_free");
 
-                functions.fpBIO_write = LoadSslMethod("BIO_write");
-                functions.fpBIO_read = LoadSslMethod("BIO_read");
                 functions.fpBIO_free_all = LoadSslMethod("BIO_free_all");
-                functions.fpBIO_test_flags = LoadSslMethod("BIO_test_flags");
                 functions.fpBIO_ctrl = LoadSslMethod("BIO_ctrl");
 
+                functions.fpERR_get_error = LoadSslMethod("ERR_get_error");
+                functions.fpERR_error_string_n = LoadSslMethod("ERR_error_string_n");
+
                 bool allLoaded =
                     functions.fpSSL_CTX_new != 0 &&
                     functions.fpSSL_CTX_free != 0 &&
@@ -174,15 +181,23 @@ namespace ignite
                     functions.fpSSL_get_peer_certificate != 0 &&
                     functions.fpSSL_ctrl != 0 &&
                     functions.fpSSL_CTX_ctrl != 0 &&
-                    functions.fpSSLv23_method != 0 &&
+                    functions.fpSSLv23_client_method != 0 &&
+                    functions.fpSSL_set_connect_state != 0 &&
+                    functions.fpSSL_connect != 0 &&
+                    functions.fpSSL_get_error != 0 &&
+                    functions.fpSSL_want != 0 &&
+                    functions.fpSSL_write != 0 &&
+                    functions.fpSSL_read != 0 &&
+                    functions.fpSSL_pending != 0 &&
+                    functions.fpSSL_get_fd != 0 &&
+                    functions.fpSSL_free != 0 &&
                     functions.fpBIO_new_ssl_connect != 0 &&
                     functions.fpOPENSSL_config != 0 &&
                     functions.fpX509_free != 0 &&
-                    functions.fpBIO_write != 0 &&
-                    functions.fpBIO_read != 0 &&
                     functions.fpBIO_free_all != 0 &&
-                    functions.fpBIO_test_flags != 0 &&
-                    functions.fpBIO_ctrl != 0;
+                    functions.fpBIO_ctrl != 0 &&
+                    functions.fpERR_get_error != 0 &&
+                    functions.fpERR_error_string_n != 0;
 
                 if (!allLoaded)
                 {