Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding tls key logger for EvseV2G (openssl part) #910

Merged
merged 6 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/config-sil-dc-tls.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ active_modules:
config_module:
device: auto
tls_security: force
tls_key_logging: true
connections:
security:
- module_id: evse_security
Expand Down
5 changes: 5 additions & 0 deletions lib/staging/tls/openssl_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ bool certificate_subject_public_key_sha_1(openssl::sha_1_digest_t& digest, const

enum class log_level_t : std::uint8_t {
debug,
info,
warning,
error,
};
Expand All @@ -523,6 +524,10 @@ static inline void log_debug(const std::string& str) {
log(log_level_t::debug, str);
}

static inline void log_info(const std::string& str) {
log(log_level_t::info, str);
}

using log_handler_t = void (*)(log_level_t level, const std::string& err);

/**
Expand Down
3 changes: 3 additions & 0 deletions lib/staging/tls/tests/gtest_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ void log_handler(openssl::log_level_t level, const std::string& str) {
case openssl::log_level_t::debug:
// std::cout << "DEBUG: " << str << std::endl;
break;
case openssl::log_level_t::info:
std::cout << "INFO: " << str << std::endl;
break;
case openssl::log_level_t::warning:
std::cout << "WARN: " << str << std::endl;
break;
Expand Down
149 changes: 146 additions & 3 deletions lib/staging/tls/tls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
#include "extensions/trusted_ca_keys.hpp"
#include "openssl_util.hpp"

#include <arpa/inet.h>
#include <array>
#include <cassert>
#include <csignal>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <fcntl.h>
#include <fstream>
#include <memory>
#include <mutex>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
Expand Down Expand Up @@ -63,6 +66,7 @@ template <> class default_delete<BIO_ADDRINFO> {
} // namespace std

using ::openssl::log_error;
using ::openssl::log_info;
using ::openssl::log_warning;

namespace {
Expand Down Expand Up @@ -692,8 +696,43 @@ std::uint32_t ServerConnection::m_count{0};
std::mutex ServerConnection::m_cv_mutex;
std::condition_variable ServerConnection::m_cv;

namespace {

int ssl_keylog_file_index{-1};
int ssl_keylog_server_index{-1};

SebaLukas marked this conversation as resolved.
Show resolved Hide resolved
void keylog_callback(const SSL* ssl, const char* line) {

auto keylog_server = static_cast<TlsKeyLoggingServer*>(SSL_get_ex_data(ssl, ssl_keylog_server_index));

std::string key_log_msg = "TLS Handshake keys on port ";
key_log_msg += std::to_string(keylog_server->get_port()) + ": ";
key_log_msg += std::string(line);

log_info(key_log_msg);

if (keylog_server->get_fd() != -1) {
const auto result = keylog_server->send(line);
if (result not_eq strlen(line)) {
log_error("key_logging_server send() failed!");
}
}

auto keylog_file_path =
static_cast<std::filesystem::path*>(SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl), ssl_keylog_file_index));

if (not keylog_file_path->empty()) {
std::ofstream ofs;
ofs.open(keylog_file_path->string(), std::ofstream::out | std::ofstream::app);
ofs << line << std::endl;
ofs.close();
}
}

} // namespace

ServerConnection::ServerConnection(SslContext* ctx, int soc, const char* ip_in, const char* service_in,
std::int32_t timeout_ms) :
std::int32_t timeout_ms, const ConfigItem& tls_key_interface) :
Connection(ctx, soc, ip_in, service_in, timeout_ms), m_tck_data{m_trusted_ca_keys, m_flags} {
{
std::lock_guard lock(m_cv_mutex);
Expand All @@ -703,6 +742,12 @@ ServerConnection::ServerConnection(SslContext* ctx, int soc, const char* ip_in,
SSL_set_accept_state(m_context->ctx.get());
ServerStatusRequestV2::set_data(m_context->ctx.get(), &m_flags);
ServerTrustedCaKeys::set_data(m_context->ctx.get(), &m_tck_data);

if (tls_key_interface != nullptr) {
const auto port = std::stoul(service_in);
m_keylog_server = std::make_unique<TlsKeyLoggingServer>(std::string(tls_key_interface), port);
SSL_set_ex_data(m_context->ctx.get(), ssl_keylog_server_index, m_keylog_server.get());
}
}
}

Expand Down Expand Up @@ -885,6 +930,26 @@ bool Server::init_ssl(const config_t& cfg) {
// use the first server chain
result = configure_ssl_ctx(ctx, cfg.ciphersuites, cfg.cipher_list, cfg.chains[0], true);
if (result) {

if (cfg.tls_key_logging) {
tls_key_log_file_path = std::filesystem::path(cfg.tls_key_logging_path) /= "tls_session_keys.log";

ssl_keylog_file_index = SSL_CTX_get_ex_new_index(0, std::string("").data(), nullptr, nullptr, nullptr);
ssl_keylog_server_index = SSL_get_ex_new_index(0, std::string("").data(), nullptr, nullptr, nullptr);

if (ssl_keylog_file_index == -1 or ssl_keylog_server_index == -1) {
auto error_msg = std::string("_get_ex_new_index failed: ssl_keylog_file_index: ");
error_msg += std::to_string(ssl_keylog_file_index);
error_msg += ", ssl_keylog_server_index: " + std::to_string(ssl_keylog_server_index);
log_error(error_msg);
} else {
SSL_CTX_set_ex_data(ctx, ssl_keylog_file_index, &tls_key_log_file_path);

SSL_CTX_set_keylog_callback(ctx, keylog_callback);
m_tls_key_interface = cfg.host;
}
}

int mode = SSL_VERIFY_NONE;

// TODO(james-ctc): verify may need to change based on TLS version
Expand Down Expand Up @@ -1062,8 +1127,9 @@ void Server::wait_for_connection(const ConnectionHandler& handler) {
// new connection, pass to handler
auto* ip = BIO_ADDR_hostname_string(peer.get(), 1);
auto* service = BIO_ADDR_service_string(peer.get(), 1);
auto connection =
std::make_unique<ServerConnection>(m_context->ctx.get(), soc, ip, service, m_timeout_ms);

auto connection = std::make_unique<ServerConnection>(m_context->ctx.get(), soc, ip, service,
m_timeout_ms, m_tls_key_interface);
handler(std::move(connection));
OPENSSL_free(ip);
OPENSSL_free(service);
Expand Down Expand Up @@ -1345,4 +1411,81 @@ Client::override_t Client::default_overrides() {
};
}

// ----------------------------------------------------------------------------
// TlsKeyLoggingServer

TlsKeyLoggingServer::TlsKeyLoggingServer(const std::string& interface_name, uint16_t port_) : port(port_) {
static constexpr auto LINK_LOCAL_MULTICAST = "ff02::1";
bool result{true};

fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd == -1) {
log_error("Could not create socket");
result = false;
}

if (result) {
// source setup
// find port between 49152-65535
auto could_bind = false;
auto source_port = 49152;
for (; source_port < 65535; source_port++) {
sockaddr_in6 source_address = {AF_INET6, htons(source_port), 0, {}, 0};
if (bind(fd, reinterpret_cast<sockaddr*>(&source_address), sizeof(sockaddr_in6)) == 0) {
could_bind = true;
break;
}
}

if (could_bind) {
log_info("UDP socket bound to source port: " + std::to_string(source_port));
} else {
log_error("Could not bind");
result = false;
}
}

if (result) {
auto mreq = ipv6_mreq{};
const auto index = if_nametoindex(interface_name.c_str());
mreq.ipv6mr_interface = index;
if (inet_pton(AF_INET6, LINK_LOCAL_MULTICAST, &mreq.ipv6mr_multiaddr) <= 0) {
log_error("Failed to setup multicast address");
result = false;
}

if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
log_error("Could not add multicast group membership");
result = false;
}

if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0) {
log_error("Could not set interface name:" + interface_name);
result = false;
}

destination_address = {AF_INET6, htons(port), 0, {}, 0};
if (inet_pton(AF_INET6, LINK_LOCAL_MULTICAST, &destination_address.sin6_addr) <= 0) {
log_error("Failed to setup server address, reset key_log_fd");
result = false;
}
}

if (!result && fd != -1) {
close(fd);
fd = -1;
}
}

TlsKeyLoggingServer::~TlsKeyLoggingServer() {
if (fd != -1) {
close(fd);
}
}

ssize_t TlsKeyLoggingServer::send(const char* line) {
return sendto(fd, line, strlen(line), 0, reinterpret_cast<const sockaddr*>(&destination_address),
sizeof(destination_address));
}

} // namespace tls
34 changes: 33 additions & 1 deletion lib/staging/tls/tls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <functional>
#include <memory>
#include <mutex>
#include <netinet/in.h>
#include <openssl/types.h>
#include <optional>
#include <pthread.h>
Expand Down Expand Up @@ -57,6 +59,27 @@ class ConfigItem {
}
};

class TlsKeyLoggingServer {
public:
TlsKeyLoggingServer(const std::string& interface_name, uint16_t port_);
~TlsKeyLoggingServer();

ssize_t send(const char* line);

auto get_fd() const {
return fd;
}

auto get_port() const {
return port;
}

private:
int fd{-1};
uint16_t port{0};
sockaddr_in6 destination_address{};
};

// ----------------------------------------------------------------------------
// Connection represents a TLS connection

Expand Down Expand Up @@ -258,8 +281,11 @@ class ServerConnection : public Connection {
StatusFlags m_flags; //!< extension flags
server_trusted_ca_keys_t m_tck_data; //!< extension per connection data

std::unique_ptr<TlsKeyLoggingServer> m_keylog_server{nullptr};

public:
ServerConnection(SslContext* ctx, int soc, const char* ip_in, const char* service_in, std::int32_t timeout_ms);
ServerConnection(SslContext* ctx, int soc, const char* ip_in, const char* service_in, std::int32_t timeout_ms,
const ConfigItem& tls_key_interface);
ServerConnection() = delete;
ServerConnection(const ServerConnection&) = delete;
ServerConnection(ServerConnection&&) = delete;
Expand Down Expand Up @@ -381,6 +407,9 @@ class Server {
ConfigItem service{nullptr}; //!< TLS port number as a string
int socket{INVALID_SOCKET}; //!< use this specific socket - bypasses socket setup in init_socket() when set
bool ipv6_only{true}; //!< listen on IPv6 only, when false listen on IPv4 only

bool tls_key_logging{false}; //!< tls key logging is active when true
std::string tls_key_logging_path; //!< tls key logging file path
};

using ConnectionPtr = std::unique_ptr<ServerConnection>;
Expand Down Expand Up @@ -409,6 +438,9 @@ class Server {
static int s_sig_int; //!< signal to use to wakeup serve()
ConfigurationCallback m_init_callback{nullptr}; //!< callback to retrieve SSL configuration

ConfigItem m_tls_key_interface{nullptr};
std::filesystem::path tls_key_log_file_path{};

/**
* \brief initialise the server socket
* \param[in] cfg server configuration
Expand Down
3 changes: 3 additions & 0 deletions modules/EvseV2G/EvseV2G.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ void log_handler(openssl::log_level_t level, const std::string& str) {
case openssl::log_level_t::debug:
// ignore debug logs
break;
case openssl::log_level_t::info:
EVLOG_info << str;
break;
case openssl::log_level_t::warning:
EVLOG_warning << str;
break;
Expand Down
4 changes: 4 additions & 0 deletions modules/EvseV2G/connection/tls_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ bool build_config(tls::Server::config_t& config, struct v2g_context* ctx) {
config.socket = ctx->tls_socket.fd;
config.io_timeout_ms = static_cast<std::int32_t>(ctx->network_read_timeout_tls);

config.tls_key_logging = ctx->tls_key_logging;
config.tls_key_logging_path = ctx->tls_key_logging_path;
config.host = ctx->if_name;

// information from libevse-security
const auto cert_info =
ctx->r_security->call_get_all_valid_certificates_info(LeafCertificateType::V2G, EncodingFormat::PEM, true);
Expand Down
24 changes: 24 additions & 0 deletions modules/IsoMux/IsoMux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@
#include "log.hpp"
#include "sdp.hpp"

#include <openssl_util.hpp>
namespace {
void log_handler(openssl::log_level_t level, const std::string& str) {
switch (level) {
case openssl::log_level_t::debug:
// ignore debug logs
break;
case openssl::log_level_t::info:
EVLOG_info << str;
break;
case openssl::log_level_t::warning:
EVLOG_warning << str;
break;
case openssl::log_level_t::error:
default:
EVLOG_error << str;
break;
}
}
} // namespace

struct v2g_context* v2g_ctx = nullptr;

namespace module {
Expand All @@ -21,6 +42,9 @@ void IsoMux::init() {
v2g_ctx->proxy_port_iso20 = config.proxy_port_iso20;
v2g_ctx->selected_iso20 = false;

v2g_ctx->tls_key_logging = config.tls_key_logging;

(void)openssl::set_log_handler(log_handler);
v2g_ctx->tls_server = &tls_server;

invoke_init(*p_charger);
Expand Down
2 changes: 2 additions & 0 deletions modules/IsoMux/connection/tls_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ bool build_config(tls::Server::config_t& config, struct v2g_context* ctx) {
config.socket = ctx->tls_socket.fd;
config.io_timeout_ms = static_cast<std::int32_t>(ctx->network_read_timeout_tls);

config.tls_key_logging = ctx->tls_key_logging;

// information from libevse-security
const auto cert_info =
ctx->r_security->call_get_leaf_certificate_info(LeafCertificateType::V2G, EncodingFormat::PEM, false);
Expand Down
2 changes: 2 additions & 0 deletions modules/IsoMux/v2g.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ struct v2g_context {
} tls_socket;
tls::Server* tls_server;

bool tls_key_logging;

enum V2gMsgTypeId current_v2g_msg; /* holds the last v2g msg type */
int state; /* holds the current state id */
std::atomic_bool is_connection_terminated; /* Is set to true if the connection is terminated (CP State A/F, shutdown
Expand Down
Loading