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)
{