clean up some remaining old stuff

This commit is contained in:
Michael Zanetti 2018-08-31 14:52:51 +02:00
parent 55b4c8a798
commit 922ee3ce49
4 changed files with 2 additions and 880 deletions

View File

@ -1,572 +0,0 @@
/*
* Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file OpenSSLConnection.hpp
* @brief
*
*/
#include <iostream>
#include <util/memory/stl/Vector.hpp>
#include "OpenSSLConnection.hpp"
#include "util/logging/LogMacros.hpp"
#ifdef WIN32
#define MAX_PATH_LENGTH_ 260
#include <direct.h>
#define getcwd _getcwd // avoid MSFT "deprecation" warning
#else
#include <arpa/inet.h>
#include <limits>
#include <resolv.h>
#define MAX_PATH_LENGTH_ PATH_MAX
#endif
#define OPENSSL_WRAPPER_LOG_TAG "[OpenSSL Wrapper]"
namespace awsiotsdk {
namespace network {
OpenSSLInitializer::~OpenSSLInitializer() {
CONF_modules_free();
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_remove_thread_state(NULL);
#endif
CONF_modules_unload(1);
SSL_COMP_free_compression_methods();
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
}
OpenSSLInitializer *OpenSSLInitializer::getInstance() {
static OpenSSLInitializer initializer;
return &initializer;
}
std::atomic_bool OpenSSLConnection::is_lib_initialized(false);
OpenSSLConnection::OpenSSLConnection(util::String endpoint, uint16_t endpoint_port,
std::chrono::milliseconds tls_handshake_timeout,
std::chrono::milliseconds tls_read_timeout,
std::chrono::milliseconds tls_write_timeout,
bool server_verification_flag) {
endpoint_ = endpoint;
endpoint_port_ = endpoint_port;
server_verification_flag_ = server_verification_flag;
int timeout_ms = static_cast<int>(tls_handshake_timeout.count());
tls_handshake_timeout_ = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
timeout_ms = static_cast<int>(tls_read_timeout.count());
tls_read_timeout_ = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
timeout_ms = static_cast<int>(tls_write_timeout.count());
tls_write_timeout_ = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
is_connected_ = false;
certificates_read_flag_ = false;
initializer = OpenSSLInitializer::getInstance();
p_ssl_handle_ = nullptr;
}
OpenSSLConnection::OpenSSLConnection(util::String endpoint,
uint16_t endpoint_port,
util::String root_ca_location,
util::String device_cert_location,
util::String device_private_key_location,
std::chrono::milliseconds tls_handshake_timeout,
std::chrono::milliseconds tls_read_timeout,
std::chrono::milliseconds tls_write_timeout,
bool server_verification_flag)
: OpenSSLConnection(endpoint, endpoint_port, tls_handshake_timeout, tls_read_timeout, tls_write_timeout,
server_verification_flag) {
root_ca_location_ = root_ca_location;
device_cert_location_ = device_cert_location;
device_private_key_location_ = device_private_key_location;
}
OpenSSLConnection::OpenSSLConnection(util::String endpoint,
uint16_t endpoint_port,
util::String root_ca_location,
std::chrono::milliseconds tls_handshake_timeout,
std::chrono::milliseconds tls_read_timeout,
std::chrono::milliseconds tls_write_timeout,
bool server_verification_flag)
: OpenSSLConnection(endpoint, endpoint_port, tls_handshake_timeout, tls_read_timeout, tls_write_timeout,
server_verification_flag) {
root_ca_location_ = root_ca_location;
device_cert_location_.clear();
device_private_key_location_.clear();
}
int OpenSSLConnection::WaitForSelect(int error_code) {
fd_set socketFds;
struct timeval timeout = {tls_write_timeout_.tv_sec, tls_write_timeout_.tv_usec};
FD_ZERO(&socketFds);
FD_SET(server_tcp_socket_fd_, &socketFds);
if (SSL_ERROR_WANT_READ == error_code) {
return select(server_tcp_socket_fd_ + 1, &socketFds, NULL, NULL, &timeout);
} else if (SSL_ERROR_WANT_WRITE == error_code) {
return select(server_tcp_socket_fd_ + 1, NULL, &socketFds, NULL, &timeout);
} else {
return 0;
}
}
ResponseCode OpenSSLConnection::Initialize() {
#ifdef WIN32
// TODO : Check if it is possible to replace this with std::call_once
WSADATA wsa_data;
int result;
bool was_wsa_initialized = true;
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(INVALID_SOCKET == s) {
if(WSANOTINITIALISED == WSAGetLastError()) {
was_wsa_initialized = false;
}
} else {
closesocket(s);
}
if(!was_wsa_initialized) {
// Initialize Winsock
result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if(0 != result) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "WSAStartup failed: %d", result);
return ResponseCode::NETWORK_SSL_INIT_ERROR;
}
}
#endif
if (!is_lib_initialized) {
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
signal(SIGPIPE, SIG_IGN);
is_lib_initialized = true;
}
const SSL_METHOD *method;
if (SSL_library_init() < 0) {
return ResponseCode::NETWORK_SSL_INIT_ERROR;
}
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && OPENSSL_VERSION_NUMBER < 0x10100000L
method = TLSv1_2_method();
#else
method = TLS_method();
#endif
if ((p_ssl_context_ = SSL_CTX_new(method)) == NULL) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " SSL INIT Failed - Unable to create SSL Context");
return ResponseCode::NETWORK_SSL_INIT_ERROR;
}
return ResponseCode::SUCCESS;
}
bool OpenSSLConnection::IsPhysicalLayerConnected() {
// Use this to add implementation which can check for physical layer disconnect
return true;
}
bool OpenSSLConnection::IsConnected() {
return is_connected_;
}
ResponseCode OpenSSLConnection::ConnectTCPSocket() {
const char *endpoint_char = endpoint_.c_str();
if (nullptr == endpoint_char) {
return ResponseCode::NETWORK_TCP_NO_ENDPOINT_SPECIFIED;
}
#ifndef WIN32
if (res_init() == -1) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "DNS initialize error");
}
#endif
hostent *host = gethostbyname(endpoint_char);
if (nullptr == host) {
return ResponseCode::NETWORK_TCP_NO_ENDPOINT_SPECIFIED;
}
sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(endpoint_port_);
dest_addr.sin_addr.s_addr = *(uint32_t *) (host->h_addr);
memset(&(dest_addr.sin_zero), '\0', 8);
AWS_LOG_INFO(OPENSSL_WRAPPER_LOG_TAG,
"resolved %s to %s",
endpoint_.c_str(),
inet_ntoa(dest_addr.sin_addr));
int connect_status = connect(server_tcp_socket_fd_, (sockaddr *) &dest_addr, sizeof(sockaddr));
if (-1 != connect_status) {
return ResponseCode::SUCCESS;
}
#ifdef WIN32
closesocket(server_tcp_socket_fd_);
#else
close(server_tcp_socket_fd_);
#endif
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "connect - %s", strerror(errno));
return ResponseCode::NETWORK_TCP_CONNECT_ERROR;
}
ResponseCode OpenSSLConnection::SetSocketToNonBlocking() {
int status;
ResponseCode ret_val = ResponseCode::SUCCESS;
#if defined(WIN32) || defined(WIN64)
u_long flag = 1L;
status = ioctlsocket(server_tcp_socket_fd_, FIONBIO, &flag);
if (0 > status) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "ioctlsocket - %s", strerror(errno));
ret_val = ResponseCode::NETWORK_TCP_CONNECT_ERROR;
}
#else
int flags = fcntl(server_tcp_socket_fd_, F_GETFL, 0);
// set underlying socket to non blocking
if (0 > flags) {
ret_val = ResponseCode::NETWORK_TCP_CONNECT_ERROR;
}
status = fcntl(server_tcp_socket_fd_, F_SETFL, flags | O_NONBLOCK);
if (0 > status) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "fcntl - %s", strerror(errno));
ret_val = ResponseCode::NETWORK_TCP_CONNECT_ERROR;
}
#endif
return ret_val;
}
ResponseCode OpenSSLConnection::AttemptConnect() {
ResponseCode ret_val = ResponseCode::FAILURE;
int rc = 0;
int errorCode = 0;
int select_retCode = 0;
do {
ERR_clear_error();
rc = SSL_connect(p_ssl_handle_);
if (1 == rc) { //1 = SSL_CONNECTED, <= 0 is Error
ret_val = ResponseCode::SUCCESS;
break;
}
errorCode = SSL_get_error(p_ssl_handle_, rc);
if (SSL_ERROR_WANT_READ == errorCode) {
select_retCode = WaitForSelect(errorCode);
if (0 == select_retCode) { // 0 == SELECT_TIMEOUT
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " SSL Connect time out while waiting for read");
ret_val = ResponseCode::NETWORK_SSL_CONNECT_TIMEOUT_ERROR;
} else if (-1 == select_retCode) { // -1 == SELECT_ERROR
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " SSL Connect Select error for read %d", select_retCode);
ret_val = ResponseCode::NETWORK_SSL_CONNECT_ERROR;
}
} else if (SSL_ERROR_WANT_WRITE == errorCode) {
select_retCode = WaitForSelect(errorCode);
if (0 == select_retCode) { // 0 == SELECT_TIMEOUT
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " SSL Connect time out while waiting for write");
ret_val = ResponseCode::NETWORK_SSL_CONNECT_TIMEOUT_ERROR;
} else if (-1 == select_retCode) { // -1 == SELECT_ERROR
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG,
" SSL Connect Select error for write %d",
select_retCode);
ret_val = ResponseCode::NETWORK_SSL_CONNECT_ERROR;
}
} else {
ret_val = ResponseCode::NETWORK_SSL_CONNECT_ERROR;
}
} while (ResponseCode::NETWORK_SSL_CONNECT_ERROR != ret_val &&
ResponseCode::NETWORK_SSL_CONNECT_TIMEOUT_ERROR != ret_val);
return ret_val;
}
ResponseCode OpenSSLConnection::LoadCerts() {
AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Root CA : %s", root_ca_location_.c_str());
if (!SSL_CTX_load_verify_locations(p_ssl_context_, root_ca_location_.c_str(), NULL)) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Root CA Loading error");
return ResponseCode::NETWORK_SSL_ROOT_CRT_PARSE_ERROR;
}
// TODO: streamline error codes for TLS
if (0 < device_cert_location_.length() && 0 < device_private_key_location_.length()) {
AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device crt : %s", device_cert_location_.c_str());
if (!SSL_CTX_use_certificate_chain_file(p_ssl_context_, device_cert_location_.c_str())) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Certificate Loading error");
return ResponseCode::NETWORK_SSL_DEVICE_CRT_PARSE_ERROR;
}
AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device privkey : %s", device_private_key_location_.c_str());
if (1 != SSL_CTX_use_PrivateKey_file(p_ssl_context_,
device_private_key_location_.c_str(),
SSL_FILETYPE_PEM)) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Private Key Loading error");
return ResponseCode::NETWORK_SSL_KEY_PARSE_ERROR;
}
}
certificates_read_flag_ = true;
return ResponseCode::SUCCESS;
}
ResponseCode OpenSSLConnection::PerformSSLConnect() {
ResponseCode networkResponse = ResponseCode::SUCCESS;
// Configure a non-zero callback if desired
SSL_set_verify(p_ssl_handle_, SSL_VERIFY_PEER, nullptr);
server_tcp_socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == server_tcp_socket_fd_) {
return ResponseCode::NETWORK_TCP_SETUP_ERROR;
}
networkResponse = ConnectTCPSocket();
if (ResponseCode::SUCCESS != networkResponse) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, "TCP Connection error");
return networkResponse;
}
SSL_set_fd(p_ssl_handle_, server_tcp_socket_fd_);
networkResponse = SetSocketToNonBlocking();
if (ResponseCode::SUCCESS != networkResponse) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Unable to set the socket to Non-Blocking");
} else {
networkResponse = AttemptConnect();
if (X509_V_OK != SSL_get_verify_result(p_ssl_handle_)) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Server Certificate Verification failed.");
networkResponse = ResponseCode::NETWORK_SSL_CONNECT_ERROR;
} else {
// ensure you have a valid certificate returned, otherwise no certificate exchange happened
auto cert_destroyer = [](X509 *cert) {
if (nullptr != cert) X509_free(cert);
};
std::unique_ptr<X509, decltype(cert_destroyer)> cert(SSL_get_peer_certificate(p_ssl_handle_),
cert_destroyer);
if (nullptr == cert) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " No certificate exchange happened");
networkResponse = ResponseCode::NETWORK_SSL_CONNECT_ERROR;
}
}
}
if (ResponseCode::SUCCESS != networkResponse) {
#ifdef WIN32
closesocket(server_tcp_socket_fd_);
#else
close(server_tcp_socket_fd_);
#endif
}
return networkResponse;
}
ResponseCode OpenSSLConnection::ConnectInternal() {
ResponseCode networkResponse = ResponseCode::SUCCESS;
X509_VERIFY_PARAM *param = nullptr;
if (!certificates_read_flag_) {
networkResponse = LoadCerts();
if (ResponseCode::SUCCESS != networkResponse) {
return networkResponse;
}
}
if (nullptr == p_ssl_handle_) {
p_ssl_handle_ = SSL_new(p_ssl_context_);
}
// Requires OpenSSL v1.0.2 and above
if (server_verification_flag_) {
param = SSL_get0_param(p_ssl_handle_);
// Enable automatic hostname checks
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
// Check if it is an IPv4 or an IPv6 address to enable ip checking
// Enable host name check otherwise
char dst[INET6_ADDRSTRLEN];
if (inet_pton(AF_INET, endpoint_.c_str(), (void *) dst) ||
inet_pton(AF_INET6, endpoint_.c_str(), (void *) dst)) {
X509_VERIFY_PARAM_set1_ip_asc(param, endpoint_.c_str());
} else {
X509_VERIFY_PARAM_set1_host(param, endpoint_.c_str(), 0);
}
}
networkResponse = PerformSSLConnect();
if (ResponseCode::SUCCESS != networkResponse) {
SSL_free(p_ssl_handle_);
p_ssl_handle_ = nullptr;
}
if (ResponseCode::SUCCESS == networkResponse) {
is_connected_ = true;
}
return networkResponse;
}
ResponseCode OpenSSLConnection::WriteInternal(const util::String &buf, size_t &size_written_bytes_out) {
int error_code = 0;
int select_retCode = -1;
int cur_written_length = 0;
size_t total_written_length = 0;
ResponseCode rc = ResponseCode::SUCCESS;
size_t bytes_to_write = buf.length();
do {
ERR_clear_error();
if (nullptr == p_ssl_handle_) {
return ResponseCode::NETWORK_SSL_WRITE_ERROR;
}
cur_written_length = SSL_write(p_ssl_handle_, buf.c_str(), bytes_to_write);
error_code = SSL_get_error(p_ssl_handle_, cur_written_length);
if (0 < cur_written_length) {
total_written_length += (size_t) cur_written_length;
} else if (SSL_ERROR_WANT_WRITE == error_code) {
select_retCode = WaitForSelect(error_code);
if (0 == select_retCode) { //0 == SELECT_TIMEOUT
rc = ResponseCode::NETWORK_SSL_WRITE_TIMEOUT_ERROR;
} else if (-1 == select_retCode) { //-1 == SELECT_TIMEOUT
rc = ResponseCode::NETWORK_SSL_WRITE_ERROR;
}
} else {
rc = ResponseCode::NETWORK_SSL_WRITE_ERROR;
}
} while (is_connected_ && ResponseCode::NETWORK_SSL_WRITE_ERROR != rc &&
ResponseCode::NETWORK_SSL_WRITE_TIMEOUT_ERROR != rc &&
total_written_length < bytes_to_write);
if (ResponseCode::SUCCESS == rc) {
size_written_bytes_out = total_written_length;
}
return rc;
}
ResponseCode OpenSSLConnection::ReadInternal(util::Vector<unsigned char> &buf, size_t buf_read_offset,
size_t size_bytes_to_read, size_t &size_read_bytes_out) {
int ssl_retcode;
int select_retCode;
size_t total_read_length = buf_read_offset;
size_t remaining_bytes_to_read = size_bytes_to_read;
int cur_read_len = 0;
ResponseCode errorStatus = ResponseCode::SUCCESS;
do {
ERR_clear_error();
if (nullptr == p_ssl_handle_) {
return ResponseCode::NETWORK_SSL_READ_ERROR;
}
cur_read_len = SSL_read(p_ssl_handle_, &buf[total_read_length], (int) remaining_bytes_to_read);
if (0 < cur_read_len) {
total_read_length += (size_t) cur_read_len;
remaining_bytes_to_read -= cur_read_len;
} else {
ssl_retcode = SSL_get_error(p_ssl_handle_, cur_read_len);
switch (ssl_retcode) {
case SSL_ERROR_WANT_READ:
select_retCode = WaitForSelect(SSL_ERROR_WANT_READ);
if (0 < select_retCode) {
continue;
} else if (0 == select_retCode) { //0 == SELECT_TIMEOUT
errorStatus = ResponseCode::NETWORK_SSL_NOTHING_TO_READ;
} else { // SELECT_ERROR
errorStatus = ResponseCode::NETWORK_SSL_READ_ERROR;
}
break;
case SSL_ERROR_ZERO_RETURN:
errorStatus = ResponseCode::NETWORK_SSL_CONNECTION_CLOSED_ERROR;
break;
default:
errorStatus = ResponseCode::NETWORK_SSL_READ_ERROR;
break;
}
}
if (ResponseCode::NETWORK_SSL_NOTHING_TO_READ == errorStatus ||
ResponseCode::NETWORK_SSL_READ_ERROR == errorStatus ||
ResponseCode::NETWORK_SSL_CONNECTION_CLOSED_ERROR == errorStatus) {
break;
}
} while (is_connected_ && total_read_length < size_bytes_to_read);
if (ResponseCode::SUCCESS == errorStatus) {
size_read_bytes_out = total_read_length;
}
return errorStatus;
}
ResponseCode OpenSSLConnection::DisconnectInternal() {
if (!is_connected_) {
return ResponseCode::SUCCESS;
}
is_connected_ = false;
std::chrono::milliseconds timeout = std::chrono::milliseconds(tls_read_timeout_.tv_sec * 1000 +
tls_read_timeout_.tv_usec / 1000);
std::unique_lock<std::mutex> shutdown_lock(clean_shutdown_action_lock_);
// TODO: add config for disconnect timeout
// wait for tls_read_timeout and then exit the shutdown loop if it is not successful
this->shutdown_timeout_condition_.wait_for(shutdown_lock, std::chrono::milliseconds(timeout), [this] {
int rc = SSL_shutdown(p_ssl_handle_);
if (1 == rc) {
return true;
}
int errorCode = SSL_get_error(p_ssl_handle_, rc);
WaitForSelect(errorCode);
return false;
});
SSL_free(p_ssl_handle_);
p_ssl_handle_ = nullptr;
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_remove_thread_state(NULL);
#endif
certificates_read_flag_ = false;
#ifdef WIN32
closesocket(server_tcp_socket_fd_);
#else
close(server_tcp_socket_fd_);
#endif
return ResponseCode::SUCCESS;
}
OpenSSLConnection::~OpenSSLConnection() {
if (is_connected_) {
Disconnect();
}
SSL_CTX_free(p_ssl_context_);
#ifdef WIN32
WSACleanup();
#endif
}
}
}

View File

@ -1,286 +0,0 @@
/*
* Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
* @file OpenSSLConnection.hpp
* @brief Defines a reference implementation for an OpenSSL library wrapper
*/
#pragma once
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32")
#else
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <atomic>
#include <condition_variable>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/x509_vfy.h>
#include <string.h>
#include "NetworkConnection.hpp"
#include "ResponseCode.hpp"
namespace awsiotsdk {
namespace network {
/**
* @brief Dummy class for uninitializing the OpenSSL library'
*
* TODO: This is a hotfix and will be updated after design changes
*/
class OpenSSLInitializer {
private:
// Rule of 5 stuff
// Default constructor
OpenSSLInitializer() = default;
// Default Copy constructor
OpenSSLInitializer(const OpenSSLInitializer &) = default;
// Default Move constructor
OpenSSLInitializer(OpenSSLInitializer &&) = default;
// Default Copy assignment operator
OpenSSLInitializer &operator=(const OpenSSLInitializer &) & = default;
// Default Move assignment operator
OpenSSLInitializer &operator=(OpenSSLInitializer &&) & = default;
public:
static OpenSSLInitializer* getInstance();
~OpenSSLInitializer();
};
/**
* @brief OpenSSL Wrapper Class
*
* Defines a reference wrapper for OpenSSL libraries
*/
class OpenSSLConnection : public NetworkConnection {
protected:
static std::atomic_bool is_lib_initialized; ///< Boolean, True = Library is initialized, False otherwise
OpenSSLInitializer *initializer; ///< Pointer to dummy library instance
util::String root_ca_location_; ///< Pointer to string containing the filename (including path) of the root CA file.
util::String device_cert_location_; ///< Pointer to string containing the filename (including path) of the device certificate.
util::String device_private_key_location_; ///< Pointer to string containing the filename (including path) of the device private key file.
bool server_verification_flag_; ///< Boolean. True = perform server certificate hostname validation. False = skip validation \b NOT recommended.
std::atomic_bool is_connected_; ///< Boolean indicating connection status
struct timeval tls_handshake_timeout_; ///< Timeout for TLS handshake command
struct timeval tls_read_timeout_; ///< Timeout for the TLS Read command
struct timeval tls_write_timeout_; ///< Timeout for the TLS Write command
// Endpoint information
uint16_t endpoint_port_; ///< Endpoint port
util::String endpoint_; ///< Endpoint for this connection
SSL_CTX *p_ssl_context_; ///< SSL Context instance
SSL *p_ssl_handle_; ///< SSL Handle
int server_tcp_socket_fd_; ///< Server Socket descriptor
bool certificates_read_flag_;
std::mutex clean_shutdown_action_lock_;
std::condition_variable shutdown_timeout_condition_;
/**
* @brief Wait for socket FDs to become ready for read or write operations
*
* It is assumed that this function will be called only on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
*
* @param error_code - error generated by preceding socket operation
* @return int - return code of the select operation
*/
int WaitForSelect(int error_code);
/**
* @brief Set TLS socket to non-blocking mode
*
* @return ResponseCode - successful operation or TLS error
*/
ResponseCode SetSocketToNonBlocking();
/**
* @brief Create a TCP socket and open the connection
*
* Creates an open socket connection
*
* @return ResponseCode - successful connection or TCP error
*/
ResponseCode ConnectTCPSocket();
/**
* @brief Attempt connection
*
* Attempts TLS Connection
*
* @return ResponseCode - successful connection or TLS error
*/
ResponseCode AttemptConnect();
/**
* @brief Create a TLS socket and open the connection
*
* Creates an open socket connection including TLS handshake.
*
* @return ResponseCode - successful connection or TLS error
*/
ResponseCode LoadCerts();
/**
* @brief Perform the connect process after creating the SSL handle and context
*
* Performs the steps necessary for connecting to an endpoint after the creation of the SSL instance
*
* @return ResponseCode - successful connection or TLS error
*/
ResponseCode PerformSSLConnect();
/**
* @brief Create a TLS socket and open the connection
*
* Creates an open socket connection including TLS handshake.
*
* @return ResponseCode - successful connection or TLS error
*/
ResponseCode ConnectInternal();
/**
* @brief Write bytes to the network socket
*
* @param util::String - const reference to buffer which should be written to socket
* @return size_t - number of bytes written or Network error
* @return ResponseCode - successful write or Network error code
*/
ResponseCode WriteInternal(const util::String &buf, size_t &size_written_bytes_out);
/**
* @brief Read bytes from the network socket
*
* @param util::String - reference to buffer where read bytes should be copied
* @param size_t - number of bytes to read
* @param size_t - reference to store number of bytes read
* @return ResponseCode - successful read or TLS error code
*/
ResponseCode ReadInternal(util::Vector<unsigned char> &buf, size_t buf_read_offset,
size_t size_bytes_to_read, size_t &size_read_bytes_out);
/**
* @brief Disconnect from network socket
*
* @return ResponseCode - successful read or TLS error code
*/
ResponseCode DisconnectInternal();
public:
OpenSSLConnection(util::String endpoint, uint16_t endpoint_port,
std::chrono::milliseconds tls_handshake_timeout,
std::chrono::milliseconds tls_read_timeout,
std::chrono::milliseconds tls_write_timeout,
bool server_verification_flag);
/**
* @brief Constructor for the OpenSSL TLS implementation
*
* Performs any initialization required by the TLS layer.
*
* @param util::String endpoint - The target endpoint to connect to
* @param uint16_t endpoint_port - The port on the target to connect to
* @param util::String root_ca_location - Path of the location of the Root CA
* @param util::String device_cert_location - Path to the location of the Device Cert
* @param util::String device_private_key_location - Path to the location of the device private key file
* @param std::chrono::milliseconds tls_handshake_timeout - The value to use for timeout of handshake operation
* @param std::chrono::milliseconds tls_read_timeout - The value to use for timeout of read operation
* @param std::chrono::milliseconds tls_write_timeout - The value to use for timeout of write operation
* @param bool server_verification_flag - used to decide whether server verification is needed or not
*
*/
OpenSSLConnection(util::String endpoint, uint16_t endpoint_port, util::String root_ca_location,
util::String device_cert_location, util::String device_private_key_location,
std::chrono::milliseconds tls_handshake_timeout,
std::chrono::milliseconds tls_read_timeout, std::chrono::milliseconds tls_write_timeout,
bool server_verification_flag);
OpenSSLConnection(util::String endpoint, uint16_t endpoint_port, util::String root_ca_location,
std::chrono::milliseconds tls_handshake_timeout,
std::chrono::milliseconds tls_read_timeout, std::chrono::milliseconds tls_write_timeout,
bool server_verification_flag);
/**
* @brief Initialize the OpenSSL object
*
* Initializes the OpenSSL object
*/
ResponseCode Initialize();
/**
* @brief sets the path to the root CA
*
* Called to change the location of the root CA after the constructor has initialized the OpenSSL object.
*
* @param root_ca_location
*/
void SetRootCAPath(util::String root_ca_location) {
root_ca_location_ = root_ca_location;
certificates_read_flag_ = false;
}
/**
* @brief sets the endpoint and the port
*
* Called to change the endpoint and the port after the constructor has initialized the OpenSSL object.
* @param endpoint
* @param endpoint_port
*/
void SetEndpointAndPort(util::String endpoint, uint16_t endpoint_port) {
endpoint_ = endpoint;
endpoint_port_ = endpoint_port;
}
/**
* @brief Check if TLS layer is still connected
*
* Called to check if the TLS layer is still connected or not.
*
* @return bool - indicating status of network TLS layer connection
*/
bool IsConnected();
/**
* @brief Check if Network Physical layer is still connected
*
* Called to check if the Network Physical layer is still connected or not.
*
* @return bool - indicating status of network physical layer connection
*/
bool IsPhysicalLayerConnected();
virtual ~OpenSSLConnection();
};
}
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2017 Michael Zanetti <michael.zanetti@guh.io> *
* Copyright (C) 2017-2018 Michael Zanetti <michael.zanetti@guh.io> *
* *
* This file is part of nymea. *
* *

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2017 Michael Zanetti <michael.zanetti@guh.io> *
* Copyright (C) 2017-2018 Michael Zanetti <michael.zanetti@guh.io> *
* *
* This file is part of nymea. *
* *
@ -27,13 +27,6 @@
#include <qmqtt/qmqtt.h>
//#include "OpenSSL/OpenSSLConnection.hpp"
//#include <mqtt/Client.hpp>
//#include <mqtt/Common.hpp>
//#include "util/logging/Logging.hpp"
//#include "util/logging/LogMacros.hpp"
//#include "util/logging/ConsoleLogSystem.hpp"
class AWSConnector : public QObject
{
Q_OBJECT
@ -93,12 +86,6 @@ private slots:
private:
quint16 publish(const QString &topic, const QVariantMap &message);
void subscribe(const QStringList &topics);
// static void publishCallback(uint16_t actionId, awsiotsdk::ResponseCode rc);
// static void subscribeCallback(uint16_t actionId, awsiotsdk::ResponseCode rc);
// static awsiotsdk::ResponseCode onSubscriptionReceivedCallback(awsiotsdk::util::String topic_name, awsiotsdk::util::String payload,
// std::shared_ptr<awsiotsdk::mqtt::SubscriptionHandlerContextData> p_app_handler_data);
// static awsiotsdk::ResponseCode onDisconnectedCallback(awsiotsdk::util::String mqtt_client_id,
// std::shared_ptr<awsiotsdk::DisconnectCallbackContextData> p_app_handler_data);
void storeRegisteredFlag(bool registered);
bool readRegisteredFlag() const;
@ -109,8 +96,6 @@ private:
QString getCertificateFingerprint(const QString &certificateFilePath) const;
private:
// std::shared_ptr<awsiotsdk::network::OpenSSLConnection> m_networkConnection;
// std::shared_ptr<awsiotsdk::MqttClient> m_client;
QMQTT::Client *m_client = nullptr;
QString m_currentEndpoint;
QString m_caFile;
@ -133,11 +118,6 @@ private:
QStringList m_subscriptionCache;
QPair<QVariantMap, QDateTime> m_cachedTURNCredentials;
// std::shared_ptr<awsiotsdk::mqtt::SubscriptionHandlerContextData> m_subscriptionContextData;
// std::shared_ptr<awsiotsdk::DisconnectCallbackContextData> m_disconnectContextData;
// static AWSConnector* s_instance;
// QHash<quint16, AWSConnector*> m_requestMap;
};
Q_DECLARE_METATYPE(AWSConnector::PushNotificationsEndpoint)