Repository: ignite Updated Branches: refs/heads/ignite-2.5 05f9280a2 -> e190e35a9
IGNITE-8394: ODBC: Fixed async establishing of SSL connection (cherry picked from commit 1840f75) Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/e190e35a Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/e190e35a Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/e190e35a Branch: refs/heads/ignite-2.5 Commit: e190e35a97ffe1f7a1cbc8a2803bb9b9f301a417 Parents: 05f9280 Author: Igor Sapego <[email protected]> Authored: Thu Apr 26 19:36:25 2018 +0300 Committer: Igor Sapego <[email protected]> Committed: Thu Apr 26 19:50:50 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/e190e35a/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/e190e35a/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/e190e35a/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/e190e35a/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/e190e35a/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/e190e35a/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/e190e35a/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) {
