Skip to content

Commit

Permalink
fix: support delayed getting certificates from libevse-security
Browse files Browse the repository at this point in the history
Originally information was fetched from libevse-security every
connection. The OpenSSL addition moved away from that so that
configuration was checked at module start.

The problem occurs when there isn't valid configuration.
This change splits config into two sets:
1. config that must exist at module start
2. config that can be obtained at 1st connection

TCP socket information is covered in 1.
SSL certificates, keys and OCSP resonses are in 2.

Signed-off-by: James Chapman <[email protected]>
  • Loading branch information
james-ctc committed Jul 10, 2024
1 parent b6b5cb1 commit 7284fdb
Show file tree
Hide file tree
Showing 10 changed files with 539 additions and 100 deletions.
3 changes: 2 additions & 1 deletion config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ generate_config_run_script(CONFIG sil-two-evse)
generate_config_run_script(CONFIG sil-ocpp)
generate_config_run_script(CONFIG sil-ocpp201)
generate_config_run_script(CONFIG sil-dc)
generate_config_run_script(CONFIG sil-dc-tls)
generate_config_run_script(CONFIG sil-dc-sae-v2g)
generate_config_run_script(CONFIG sil-dc-sae-v2h)
generate_config_run_script(CONFIG sil-two-evse-dc)
Expand All @@ -25,7 +26,7 @@ install(
install(
DIRECTORY "certs"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/everest"
FILES_MATCHING PATTERN "*.pem" PATTERN "*.key" PATTERN "*.der" PATTERN "*.txt" PATTERN "*.jks" PATTERN "*.p12"
FILES_MATCHING PATTERN "*.pem" PATTERN "*.key" PATTERN "*.der" PATTERN "*.txt" PATTERN "*.jks" PATTERN "*.p12"
)

install(
Expand Down
147 changes: 147 additions & 0 deletions config/config-sil-dc-tls.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
active_modules:
iso15118_charger:
module: EvseV2G
config_module:
device: auto
tls_security: force
connections:
security:
- module_id: evse_security
implementation_id: main
iso15118_car:
module: PyEvJosev
config_module:
device: auto
supported_DIN70121: false
supported_ISO15118_2: true
tls_active: true
enforce_tls: true
evse_manager:
module: EvseManager
config_module:
connector_id: 1
country_code: DE
evse_id: DE*PNX*E12345*1
evse_id_din: 49A80737A45678
session_logging: true
session_logging_xml: false
session_logging_path: /tmp/everest-logs
charge_mode: DC
hack_allow_bpt_with_iso2: true
payment_enable_contract: false
connections:
bsp:
- module_id: yeti_driver
implementation_id: board_support
powermeter_car_side:
- module_id: powersupply_dc
implementation_id: powermeter
slac:
- module_id: slac
implementation_id: evse
hlc:
- module_id: iso15118_charger
implementation_id: charger
powersupply_DC:
- module_id: powersupply_dc
implementation_id: main
imd:
- module_id: imd
implementation_id: main
powersupply_dc:
module: DCSupplySimulator
yeti_driver:
module: JsYetiSimulator
config_module:
connector_id: 1
slac:
module: JsSlacSimulator
imd:
config_implementation:
main:
selftest_success: true
module: IMDSimulator
ev_manager:
module: EvManager
config_module:
connector_id: 1
auto_enable: true
auto_exec: false
auto_exec_commands: sleep 1;iec_wait_pwr_ready;sleep 1;draw_power_regulated 16,3;sleep 30;unplug
dc_target_current: 20
dc_target_voltage: 400
connections:
ev_board_support:
- module_id: yeti_driver
implementation_id: ev_board_support
ev:
- module_id: iso15118_car
implementation_id: ev
slac:
- module_id: slac
implementation_id: ev
auth:
module: Auth
config_module:
connection_timeout: 10
selection_algorithm: FindFirst
connections:
token_provider:
- module_id: token_provider
implementation_id: main
token_validator:
- module_id: token_validator
implementation_id: main
evse_manager:
- module_id: evse_manager
implementation_id: evse
token_provider:
module: DummyTokenProvider
config_implementation:
main:
token: TOKEN1
connections:
evse:
- module_id: evse_manager
implementation_id: evse
token_validator:
module: DummyTokenValidator
config_implementation:
main:
validation_result: Accepted
validation_reason: Token seems valid
sleep: 0.25
evse_security:
module: EvseSecurity
config_module:
private_key_password: "123456"
energy_manager:
module: EnergyManager
config_module:
schedule_total_duration: 1
schedule_interval_duration: 60
debug: false
connections:
energy_trunk:
- module_id: grid_connection_point
implementation_id: energy_grid
grid_connection_point:
module: EnergyNode
config_module:
fuse_limit_A: 40.0
phase_count: 3
connections:
price_information: []
energy_consumer:
- module_id: evse_manager
implementation_id: energy_grid
powermeter:
- module_id: yeti_driver
implementation_id: powermeter
api:
module: API
connections:
evse_manager:
- module_id: evse_manager
implementation_id: evse
x-module-layout: {}
44 changes: 22 additions & 22 deletions lib/staging/tls/openssl_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,34 +329,34 @@ bool signature_to_bn(bn_t& r, bn_t& s, const std::uint8_t* sig_p, std::size_t le
};

std::vector<Certificate_ptr> load_certificates(const char* filename) {
assert(filename != nullptr);

std::vector<Certificate_ptr> result{};
auto* store = OSSL_STORE_open(filename, UI_null(), nullptr, nullptr, nullptr);

if (store != nullptr) {
while (OSSL_STORE_eof(store) != 1) {
auto* info = OSSL_STORE_load(store);

if (info != nullptr) {
if (OSSL_STORE_error(store) == 1) {
log_error("OSSL_STORE_load");
} else {
const auto type = OSSL_STORE_INFO_get_type(info);

if (type == OSSL_STORE_INFO_CERT) {
// get a copy of the certificate
auto cert = OSSL_STORE_INFO_get1_CERT(info);
result.push_back({cert, &X509_free});

if (filename != nullptr) {
auto* store = OSSL_STORE_open(filename, UI_null(), nullptr, nullptr, nullptr);
if (store != nullptr) {
while (OSSL_STORE_eof(store) != 1) {
auto* info = OSSL_STORE_load(store);

if (info != nullptr) {
if (OSSL_STORE_error(store) == 1) {
log_error("OSSL_STORE_load");
} else {
const auto type = OSSL_STORE_INFO_get_type(info);

if (type == OSSL_STORE_INFO_CERT) {
// get a copy of the certificate
auto cert = OSSL_STORE_INFO_get1_CERT(info);
result.push_back({cert, &X509_free});
}
}
}
}

OSSL_STORE_INFO_free(info);
OSSL_STORE_INFO_free(info);
}
}
}

OSSL_STORE_close(store);
OSSL_STORE_close(store);
}
return result;
}

Expand Down
40 changes: 37 additions & 3 deletions lib/staging/tls/tests/patched_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class OcspTest : public testing::Test {
server_config.service = "8444";
server_config.ipv6_only = false;
server_config.verify_client = false;
server_config.io_timeout_ms = 100;
server_config.io_timeout_ms = 500;

client_config.cipher_list = "ECDHE-ECDSA-AES128-SHA256";
// client_config.ciphersuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384";
Expand All @@ -194,8 +194,10 @@ class OcspTest : public testing::Test {
}
}

void start() {
if (server.init(server_config)) {
void start(const std::function<bool(tls::Server& server)>& init_ssl = nullptr) {
using state_t = tls::Server::state_t;
const auto res = server.init(server_config, init_ssl);
if ((res == state_t::init_complete) || (res == state_t::init_socket)) {
server_thread = std::thread(&run_server, std::ref(server));
server.wait_running();
}
Expand Down Expand Up @@ -228,6 +230,24 @@ class OcspTest : public testing::Test {
}
};

bool ssl_init(tls::Server& server) {
std::cout << "ssl_init" << std::endl;
tls::Server::config_t server_config;
server_config.cipher_list = "ECDHE-ECDSA-AES128-SHA256";
server_config.ciphersuites = "";
server_config.certificate_chain_file = "server_chain.pem";
server_config.private_key_file = "server_priv.pem";
server_config.ocsp_response_files = {"ocsp_response.der", "ocsp_response.der"};
server_config.host = "localhost";
server_config.service = "8444";
server_config.ipv6_only = false;
server_config.verify_client = false;
server_config.io_timeout_ms = 100;
const auto res = server.update(server_config);
EXPECT_TRUE(res);
return res;
}

// ----------------------------------------------------------------------------
// The tests

Expand All @@ -246,6 +266,20 @@ TEST_F(OcspTest, NonBlockingConnect) {
EXPECT_TRUE(is_reset(flags_t::status_request_v2));
}

TEST_F(OcspTest, delayedConfig) {
// partial config
server_config.certificate_chain_file = nullptr;
server_config.private_key_file = nullptr;
server_config.ocsp_response_files.clear();

start(ssl_init);
connect();
EXPECT_TRUE(is_set(flags_t::connected));
EXPECT_TRUE(is_reset(flags_t::status_request_cb));
EXPECT_TRUE(is_reset(flags_t::status_request));
EXPECT_TRUE(is_reset(flags_t::status_request_v2));
}

TEST_F(OcspTest, TLS12) {
// test using TLS 1.2
start();
Expand Down
2 changes: 1 addition & 1 deletion lib/staging/tls/tests/tls_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ int main() {
server.stop();
});

server.init(config);
server.init(config, nullptr);
server.wait_stopped();

// server.serve(&handle_connection);
Expand Down
68 changes: 68 additions & 0 deletions lib/staging/tls/tests/tls_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,74 @@ std::string to_string(const openssl::sha_256_digest_t& digest) {

namespace {

TEST(strdup, usage) {
// auto* r1 = strdup(nullptr); need to ensure non-nullptr
auto* r2 = strdup("");
auto* r3 = strdup("hello");
// free(r1);
free(r2);
free(r3);
free(nullptr);
}

TEST(string, use) {
// was hoping to use std::string for config, but ...
std::string empty;
std::string space{""};
std::string value{"something"};

EXPECT_TRUE(empty.empty());
// EXPECT_FALSE(space.empty()); was hoping it would be true
EXPECT_FALSE(value.empty());

// EXPECT_EQ(empty.c_str(), nullptr); was hoping it would be nullptr
EXPECT_NE(space.c_str(), nullptr);
EXPECT_NE(value.c_str(), nullptr);
}

TEST(ConfigItem, test) {
tls::ConfigItem i1;
tls::ConfigItem i2{nullptr};
tls::ConfigItem i3{"Hello"};
tls::ConfigItem i4 = nullptr;
tls::ConfigItem i5(nullptr);
tls::ConfigItem i6("Hello");

EXPECT_EQ(i1, nullptr);
EXPECT_EQ(i4, nullptr);
EXPECT_EQ(i5, nullptr);

EXPECT_EQ(i2, i5);
EXPECT_EQ(i3, i6);

EXPECT_EQ(i1, i2);
EXPECT_NE(i1, i3);
EXPECT_EQ(i1, i5);
EXPECT_NE(i1, i6);

auto j1(std::move(i3));
auto j2 = std::move(i6);
EXPECT_EQ(i6, i3);
EXPECT_EQ(j1, j2);
EXPECT_EQ(j1, "Hello");
EXPECT_NE(j1, i6);

EXPECT_NE(j1, nullptr);
EXPECT_NE(j2, nullptr);

EXPECT_EQ(i3, nullptr);
EXPECT_EQ(i6, nullptr);
EXPECT_EQ(i6, i3);

std::vector<tls::ConfigItem> j3 = {"one", "two", nullptr};
EXPECT_EQ(j3[0], "one");
EXPECT_EQ(j3[1], "two");
EXPECT_EQ(j3[2], nullptr);

const char* p = j1;
EXPECT_STREQ(p, "Hello");
}

TEST(OcspCache, initEmpty) {
tls::OcspCache cache;
openssl::sha_256_digest_t digest{};
Expand Down
Loading

0 comments on commit 7284fdb

Please sign in to comment.