Skip to content

Commit

Permalink
Add initial implementation of tls client and server
Browse files Browse the repository at this point in the history
  • Loading branch information
Iandiehard committed Oct 8, 2023
1 parent 13c5d95 commit d67bc35
Show file tree
Hide file tree
Showing 12 changed files with 852 additions and 15 deletions.
10 changes: 10 additions & 0 deletions .github/install_cmake.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
CMAKE_MAJOR_VERSION="3"
CMAKE_MINOR_VERSION="25"
CMAKE_PATCH_VERSION="3"
wget "https://github.com/Kitware/CMake/archive/refs/tags/v${OPENSSL_CMAKE_MAJOR_VERSION}.${OPENSSL_CMAKE_MINOR_VERSION}.${OPENSSL_CMAKE_PATCH_VERSION}.tar.gz"
tar -zxvf cmake-${OPENSSL_CMAKE_MAJOR_VERSION}.${OPENSSL_CMAKE_MINOR_VERSION}.${OPENSSL_CMAKE_PATCH_VERSION}.tar.gz
cd cmake-${OPENSSL_CMAKE_MAJOR_VERSION}.${OPENSSL_CMAKE_MINOR_VERSION}.${OPENSSL_CMAKE_PATCH_VERSION}
./bootstrap
make
sudo make install
12 changes: 12 additions & 0 deletions .github/install_openssl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
OPENSSL_CMAKE_MAJOR_VERSION="3"
OPENSSL_CMAKE_MINOR_VERSION="1"
OPENSSL_CMAKE_PATCH_VERSION="3"
wget "https://github.com/jimmy-park/openssl-cmake/archive/refs/tags/3.1.3.tar.gz"
mkdir openssl-cmake
tar -xvf ${OPENSSL_CMAKE_MAJOR_VERSION}.${OPENSSL_CMAKE_MINOR_VERSION}.${OPENSSL_CMAKE_PATCH_VERSION}.tar.gz -C openssl-cmake
mkdir -p openssl-cmake/openssl-cmake-${OPENSSL_CMAKE_MAJOR_VERSION}.${OPENSSL_CMAKE_MINOR_VERSION}.${OPENSSL_CMAKE_PATCH_VERSION}/build
cd openssl-cmake/openssl-cmake-${OPENSSL_CMAKE_MAJOR_VERSION}.${OPENSSL_CMAKE_MINOR_VERSION}.${OPENSSL_CMAKE_PATCH_VERSION} || exit
cmake -B build -DOPENSSL_CONFIGURE_OPTIONS=no-shared no-tests -DOPENSSL_TARGET_VERSION=1.1.1w -DOPENSSL_CONFIGURE_VERBOSE=ON -DOPENSSL_INSTALL=ON
cmake --build build
cmake --install build
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#
# Entry Project CMake
#
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.25)
project(diag-client)

# Cmake options
Expand Down
3 changes: 2 additions & 1 deletion diag-client-lib/lib/boost-support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(Boost 1.78.0)

find_package(OpenSSL)
file(GLOB LIBBOOST_COMMON_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp")
file(GLOB LIBBOOST_SOCKET_TCP_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/socket/tcp/*.cpp")
file(GLOB LIBBOOST_SOCKET_UDP_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/socket/udp/*.cpp")
Expand Down Expand Up @@ -41,6 +41,7 @@ target_link_libraries(${PROJECT_NAME}
platform-core
utility-support
${Boost_LIBRARIES}
OpenSSL::SSL
)

install(TARGETS ${PROJECT_NAME}
Expand Down
10 changes: 5 additions & 5 deletions diag-client-lib/lib/boost-support/common/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef DIAGNOSTIC_CLIENT_LIB_LIB_BOOST_SUPPORT_COMMON_LOGGER_H
#define DIAGNOSTIC_CLIENT_LIB_LIB_BOOST_SUPPORT_COMMON_LOGGER_H
#ifndef DIAG_CLIENT_LIB_LIB_BOOST_SUPPORT_COMMON_LOGGER_H_
#define DIAG_CLIENT_LIB_LIB_BOOST_SUPPORT_COMMON_LOGGER_H_

#include "utility/logger.h"

Expand All @@ -15,10 +15,10 @@ namespace common {
namespace logger {
using Logger = utility::logger::Logger;

class LibBoostLogger {
class LibBoostLogger final {
public:
auto static GetLibBoostLogger() noexcept -> LibBoostLogger& {
static LibBoostLogger boost_logger;
static LibBoostLogger boost_logger{};
return boost_logger;
}

Expand All @@ -33,4 +33,4 @@ class LibBoostLogger {
} // namespace logger
} // namespace common
} // namespace boost_support
#endif // DIAGNOSTIC_CLIENT_LIB_LIB_BOOST_SUPPORT_COMMON_LOGGER_H
#endif // DIAG_CLIENT_LIB_LIB_BOOST_SUPPORT_COMMON_LOGGER_H_
242 changes: 242 additions & 0 deletions diag-client-lib/lib/boost-support/socket/tcp/tls_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
/* Diagnostic Client library
* Copyright (C) 2023 Avijit Dey
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "socket/tcp/tls_client.h"

#include <utility>

#include "common/logger.h"

namespace boost_support {
namespace socket {
namespace tcp {

TlsClientSocket::TlsClientSocket(std::string_view local_ip_address, std::uint16_t local_port_num,
TcpHandlerRead tcp_handler_read)
: local_ip_address_{local_ip_address},
local_port_num_{local_port_num},
io_service{},
io_ssl_context_{boost::asio::ssl::context::tlsv12_client},
tls_socket_{io_service, io_ssl_context_},
exit_request_{false},
running_{false},
cond_var_{},
mutex_{},
tcp_handler_read_{std::move(tcp_handler_read)} {
// Set verification mode
tls_socket_.set_verify_mode(boost::asio::ssl::verify_peer);
// Set the verification callback
tls_socket_.set_verify_callback(
[](bool pre_verified, boost::asio::ssl::verify_context &ctx) noexcept -> bool { return true; });
// Start thread to receive messages
thread_ = std::thread([this]() {
std::unique_lock<std::mutex> lck(mutex_);
while (!exit_request_) {
if (!running_) {
cond_var_.wait(lck, [this]() { return exit_request_ || running_; });
}
if (!exit_request_.load()) {
if (running_) {
lck.unlock();
HandleMessage();
lck.lock();
}
}
}
});
}

TlsClientSocket::~TlsClientSocket() {
exit_request_ = true;
running_ = false;
cond_var_.notify_all();
thread_.join();
}

core_type::Result<void, TlsClientSocket::TlsErrorCode> TlsClientSocket::Open() {
core_type::Result<void, TlsErrorCode> result{TlsErrorCode::kGenericError};
TcpErrorCodeType ec{};

// Open the socket
GetNativeTcpSocket().open(Tcp::v4(), ec);
if (ec.value() == boost::system::errc::success) {
// reuse address
GetNativeTcpSocket().set_option(boost::asio::socket_base::reuse_address{true});
// Set socket to non blocking
GetNativeTcpSocket().non_blocking(false);
// Bind to local ip address and random port
GetNativeTcpSocket().bind(Tcp::endpoint(TcpIpAddress::from_string(local_ip_address_), local_port_num_), ec);

if (ec.value() == boost::system::errc::success) {
// Socket binding success
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogDebug(
__FILE__, __LINE__, __func__, [this](std::stringstream &msg) {
Tcp::endpoint const endpoint_{GetNativeTcpSocket().local_endpoint()};
msg << "Tcp Socket opened and bound to "
<< "<" << endpoint_.address().to_string() << "," << endpoint_.port() << ">";
});
result.EmplaceValue();
} else {
// Socket binding failed
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogError(
__FILE__, __LINE__, __func__,
[ec](std::stringstream &msg) { msg << "Tcp Socket binding failed with message: " << ec.message(); });
result.EmplaceError(TlsErrorCode::kBindingFailed);
}
} else {
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogError(
__FILE__, __LINE__, __func__,
[ec](std::stringstream &msg) { msg << "Tcp Socket opening failed with error: " << ec.message(); });
result.EmplaceError(TlsErrorCode::kOpenFailed);
}
return result;
}

core_type::Result<void, TlsClientSocket::TlsErrorCode> TlsClientSocket::ConnectToHost(std::string_view host_ip_address,
std::uint16_t host_port_num) {
core_type::Result<void, TlsErrorCode> result{TlsErrorCode::kGenericError};
TcpErrorCodeType ec{};

// Connect to provided ipAddress
GetNativeTcpSocket().connect(Tcp::endpoint(TcpIpAddress::from_string(std::string{host_ip_address}), host_port_num),
ec);
if (ec.value() == boost::system::errc::success) {
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogDebug(
__FILE__, __LINE__, __func__, [this](std::stringstream &msg) {
Tcp::endpoint const endpoint_{GetNativeTcpSocket().remote_endpoint()};
msg << "Tcp Socket connected to host "
<< "<" << endpoint_.address().to_string() << "," << endpoint_.port() << ">";
});
// Perform TLS handshake
tls_socket_.handshake(boost::asio::ssl::stream_base::client, ec);
if (ec.value() == boost::system::errc::success) {
{ // start reading
std::lock_guard<std::mutex> lock{mutex_};
running_ = true;
cond_var_.notify_all();
}
result.EmplaceValue();
} else {
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogError(
__FILE__, __LINE__, __func__,
[ec](std::stringstream &msg) { msg << "Tls handshake with host failed with error: " << ec.message(); });
result.EmplaceError(TlsErrorCode::kTlsHandshakeFailed);
}
} else {
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogError(
__FILE__, __LINE__, __func__,
[ec](std::stringstream &msg) { msg << "Tcp Socket connect to host failed with error: " << ec.message(); });
result.EmplaceError(TlsErrorCode::kConnectFailed);
}
return result;
}

core_type::Result<void, TlsClientSocket::TlsErrorCode> TlsClientSocket::DisconnectFromHost() {
core_type::Result<void, TlsErrorCode> result{TlsErrorCode::kGenericError};
TcpErrorCodeType ec{};
// Shutdown TLS connection
tls_socket_.shutdown(ec);
// Shutdown of TCP connection
GetNativeTcpSocket().shutdown(TcpSocket::shutdown_both, ec);

if (ec.value() == boost::system::errc::success) {
// stop reading
running_ = false;
// Socket shutdown success
result.EmplaceValue();
} else {
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogError(
__FILE__, __LINE__, __func__, [ec](std::stringstream &msg) {
msg << "Tcp Socket disconnection from host failed with error: " << ec.message();
});
}
return result;
}

core_type::Result<void, TlsClientSocket::TlsErrorCode> TlsClientSocket::Transmit(TcpMessageConstPtr tcp_message) {
core_type::Result<void, TlsErrorCode> result{TlsErrorCode::kGenericError};
TcpErrorCodeType ec{};

boost::asio::write(tls_socket_, boost::asio::buffer(tcp_message->GetTxBuffer(), tcp_message->GetTxBuffer().size()),
ec);
// Check for error
if (ec.value() == boost::system::errc::success) {
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogDebug(
__FILE__, __LINE__, __func__, [this](std::stringstream &msg) {
Tcp::endpoint const endpoint_{GetNativeTcpSocket().remote_endpoint()};
msg << "Tcp message sent to "
<< "<" << endpoint_.address().to_string() << "," << endpoint_.port() << ">";
});
result.EmplaceValue();
} else {
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogError(
__FILE__, __LINE__, __func__,
[ec](std::stringstream &msg) { msg << "Tcp message sending failed with error: " << ec.message(); });
}
return result;
}

core_type::Result<void, TlsClientSocket::TlsErrorCode> TlsClientSocket::Destroy() {
core_type::Result<void, TlsErrorCode> result{TlsErrorCode::kGenericError};
// destroy the socket
GetNativeTcpSocket().close();
result.EmplaceValue();
return result;
}

void TlsClientSocket::HandleMessage() {
TcpErrorCodeType ec{};
// create and reserve the buffer
TcpMessage::BufferType rx_buffer{};
rx_buffer.resize(kDoipheadrSize);
// start blocking read to read Header first
boost::asio::read(tls_socket_, boost::asio::buffer(&rx_buffer[0u], kDoipheadrSize), ec);
// Check for error
if (ec.value() == boost::system::errc::success) {
// read the next bytes to read
std::uint32_t const read_next_bytes = [&rx_buffer]() noexcept -> std::uint32_t {
return static_cast<std::uint32_t>((static_cast<std::uint32_t>(rx_buffer[4u] << 24u) & 0xFF000000) |
(static_cast<std::uint32_t>(rx_buffer[5u] << 16u) & 0x00FF0000) |
(static_cast<std::uint32_t>(rx_buffer[6u] << 8u) & 0x0000FF00) |
(static_cast<std::uint32_t>(rx_buffer[7u] & 0x000000FF)));
}();
// reserve the buffer
rx_buffer.resize(kDoipheadrSize + std::size_t(read_next_bytes));
boost::asio::read(tls_socket_, boost::asio::buffer(&rx_buffer[kDoipheadrSize], read_next_bytes), ec);

// all message received, transfer to upper layer
Tcp::endpoint const endpoint_{GetNativeTcpSocket().remote_endpoint()};
TcpMessagePtr tcp_rx_message{
std::make_unique<TcpMessage>(endpoint_.address().to_string(), endpoint_.port(), std::move(rx_buffer))};
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogDebug(
__FILE__, __LINE__, __func__, [endpoint_](std::stringstream &msg) {
msg << "Tcp Message received from "
<< "<" << endpoint_.address().to_string() << "," << endpoint_.port() << ">";
});
// notify upper layer about received message
tcp_handler_read_(std::move(tcp_rx_message));
} else if (ec.value() == boost::asio::error::eof) {
running_ = false;
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogDebug(
__FILE__, __LINE__, __func__,
[ec](std::stringstream &msg) { msg << "Remote Disconnected with: " << ec.message(); });
} else {
running_ = false;
common::logger::LibBoostLogger::GetLibBoostLogger().GetLogger().LogError(
__FILE__, __LINE__, __func__,
[ec](std::stringstream &msg) { msg << "Remote Disconnected with undefined error: " << ec.message(); });
}
}

TlsClientSocket::TlsStream::lowest_layer_type &TlsClientSocket::GetNativeTcpSocket() {
return tls_socket_.lowest_layer();
}

} // namespace tcp
} // namespace socket
} // namespace boost_support
Loading

0 comments on commit d67bc35

Please sign in to comment.