Skip to content

Commit

Permalink
Added config possibility for v201, removed extra check code
Browse files Browse the repository at this point in the history
Signed-off-by: AssemblyJohn <[email protected]>
  • Loading branch information
AssemblyJohn committed Mar 8, 2024
1 parent 549a676 commit ba68d6d
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 110 deletions.
4 changes: 2 additions & 2 deletions config/v16/profile_schemas/Internal.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,13 @@
"VerifyCsmsCommonName": {
"$comment": "Verify that the CSMS certificates commonName matches the CSMS FQDN",
"type": "boolean",
"readOnly": true,
"readOnly": false,
"default": true
},
"VerifyCsmsAllowWildcards": {
"$comment": "Allow wildcards when verifying the CSMS commonName",
"type": "boolean",
"readOnly": true,
"readOnly": false,
"default": false
},
"OcspRequestInterval": {
Expand Down
45 changes: 45 additions & 0 deletions config/v201/component_schemas/standardized/InternalCtrlr.json
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,51 @@
"default": true,
"type": "boolean"
},
"VerifyCsmsCommonName": {
"variable_name": "VerifyCsmsCommonName",
"characteristics": {
"supportsMonitoring": false,
"dataType": "boolean"
},
"attributes": [
{
"type": "Actual",
"mutability": "ReadWrite"
}
],
"default": true,
"type": "boolean"
},
"UseTPM": {
"variable_name": "UseTPM",
"characteristics": {
"supportsMonitoring": false,
"dataType": "boolean"
},
"attributes": [
{
"type": "Actual",
"mutability": "ReadOnly"
}
],
"default": false,
"type": "boolean"
},
"VerifyCsmsAllowWildcards": {
"variable_name": "VerifyCsmsAllowWildcards",
"characteristics": {
"supportsMonitoring": false,
"dataType": "boolean"
},
"attributes": [
{
"type": "Actual",
"mutability": "ReadWrite"
}
],
"default": false,
"type": "boolean"
},
"OcspRequestInterval": {
"variable_name": "OcspRequestInterval",
"characteristics": {
Expand Down
2 changes: 2 additions & 0 deletions include/ocpp/v16/charge_point_configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class ChargePointConfiguration {
bool getVerifyCsmsCommonName();
KeyValue getVerifyCsmsCommonNameKeyValue();
bool getVerifyCsmsAllowWildcards();
void setVerifyCsmsAllowWildcards(bool verify_csms_allow_wildcards);
KeyValue getVerifyCsmsAllowWildcardsKeyValue();
bool getUseTPM();
std::string getSupportedMeasurands();
KeyValue getSupportedMeasurandsKeyValue();
Expand Down
3 changes: 3 additions & 0 deletions include/ocpp/v201/ctrlr_component_variables.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ extern const ComponentVariable& RoundClockAlignedTimestamps;
extern const ComponentVariable& MaxCompositeScheduleDuration;
extern const RequiredComponentVariable& NumberOfConnectors;
extern const ComponentVariable& UseSslDefaultVerifyPaths;
extern const ComponentVariable& VerifyCsmsCommonName;
extern const ComponentVariable& UseTPM;
extern const ComponentVariable& VerifyCsmsAllowWildcards;
extern const ComponentVariable& OcspRequestInterval;
extern const ComponentVariable& WebsocketPingPayload;
extern const ComponentVariable& WebsocketPongTimeout;
Expand Down
102 changes: 2 additions & 100 deletions lib/ocpp/common/websocket/websocket_tls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,98 +16,6 @@

namespace ocpp {

static std::vector<std::string> get_subject_alt_names(const X509* x509) {
std::vector<std::string> list;
GENERAL_NAMES* subject_alt_names =
static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL));
if (subject_alt_names == nullptr) {
return list;
}
for (int i = 0; i < sk_GENERAL_NAME_num(subject_alt_names); i++) {
GENERAL_NAME* gen = sk_GENERAL_NAME_value(subject_alt_names, i);
if (gen == nullptr) {
continue;
}
if (gen->type == GEN_URI || gen->type == GEN_DNS || gen->type == GEN_EMAIL) {
ASN1_IA5STRING* asn1_str = gen->d.uniformResourceIdentifier;
std::string san = std::string(reinterpret_cast<const char*>(ASN1_STRING_get0_data(asn1_str)),
ASN1_STRING_length(asn1_str));
list.push_back(san);
} else if (gen->type == GEN_IPADD) {
unsigned char* ip = gen->d.ip->data;
if (gen->d.ip->length == 4) { // only support IPv4 for now
std::stringstream ip_stream;
ip_stream << static_cast<int>(ip[0]) << '.' << static_cast<int>(ip[1]) << '.' << static_cast<int>(ip[2])
<< '.' << static_cast<int>(ip[3]);
list.push_back(ip_stream.str());
}
}
}
GENERAL_NAMES_free(subject_alt_names);
return list;
}

bool WebsocketTLS::verify_csms_cn(const std::string& hostname, bool preverified,
boost::asio::ssl::verify_context& ctx) {

// Error depth gives the depth in the chain (with 0 = leaf certificate) where
// a potential (!) error occurred; error here means current error code and can also be "OK".
// This thus gives also the position (in the chain) of the currently to be verified certificate.
// If depth is 0, we need to check the leaf certificate;
// If depth > 0, we are verifying a CA (or SUB-CA) certificate and thus trust "preverified"
int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());

if (!preverified) {
int error = X509_STORE_CTX_get_error(ctx.native_handle());
EVLOG_warning << "Invalid certificate error '" << X509_verify_cert_error_string(error) << "' (at chain depth '"
<< depth << "')";

this->connection_failed_callback(ConnectionFailedReason::InvalidCSMSCertificate);
}

// only check for CSMS server certificate
if (depth == 0 and preverified) {
// Get server certificate
X509* server_cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());

// Extract CN from csms server's certificate
X509_NAME* subject_name = X509_get_subject_name(server_cert);
char common_name[256];
if (X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name, sizeof(common_name)) <= 0) {
EVLOG_error << "Could not extract CN from CSMS server certificate";
this->connection_failed_callback(ConnectionFailedReason::InvalidCSMSCertificate);
return false;
}

auto alt_names = get_subject_alt_names(server_cert);

// Compare the extracted CN with the expected FQDN
if (hostname == common_name) {
EVLOG_debug << "FQDN matches CN of server certificate: " << hostname;
return true;
}

// If the CN does not match, go through all alternative names
for (auto name : alt_names) {
if (hostname == name) {
EVLOG_debug << "FQDN matches alternative name of server certificate: " << hostname;
return true;
}
}

std::stringstream s;
s << "FQDN '" << hostname << "' does not match CN '" << common_name << "' or any alternative names";
for (auto alt_name : alt_names) {
s << " '" << alt_name << "'";
}
EVLOG_warning << s.str();
this->connection_failed_callback(ConnectionFailedReason::InvalidCSMSCertificate);
return false;
}

return preverified;
}

WebsocketTLS::WebsocketTLS(const WebsocketConnectionOptions& connection_options,
std::shared_ptr<EvseSecurity> evse_security) :
WebsocketBase(), evse_security(evse_security) {
Expand Down Expand Up @@ -308,9 +216,9 @@ tls_context WebsocketTLS::on_tls_init(std::string hostname, websocketpp::connect
if (this->connection_options.verify_csms_common_name) {

// Verify hostname
X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new();
X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();

if(this->connection_options.verify_csms_allow_wildcards) {
if (this->connection_options.verify_csms_allow_wildcards) {
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
} else {
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_WILDCARDS);
Expand All @@ -321,12 +229,6 @@ tls_context WebsocketTLS::on_tls_init(std::string hostname, websocketpp::connect
SSL_CTX_set1_param(context->native_handle(), param);

X509_VERIFY_PARAM_free(param);

/*
context->set_verify_callback([this, hostname](bool preverified, boost::asio::ssl::verify_context& ctx) {
return this->verify_csms_cn(hostname, preverified, ctx);
});
*/
} else {
EVLOG_warning << "Not verifying the CSMS certificates commonName with the Fully Qualified Domain Name "
"(FQDN) of the server because it has been explicitly turned off via the configuration!";
Expand Down
23 changes: 23 additions & 0 deletions lib/ocpp/v16/charge_point_configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,10 @@ bool ChargePointConfiguration::getVerifyCsmsAllowWildcards() {
return this->config["Internal"]["VerifyCsmsAllowWildcards"];
}

void ChargePointConfiguration::setVerifyCsmsAllowWildcards(bool verify_csms_allow_wildcards) {
this->config["Internal"]["VerifyCsmsAllowWildcards"] = verify_csms_allow_wildcards;
this->setInUserConfig("Internal", "VerifyCsmsAllowWildcards", verify_csms_allow_wildcards);
}

std::string ChargePointConfiguration::getSupportedMeasurands() {
return this->config["Internal"]["SupportedMeasurands"];
Expand Down Expand Up @@ -550,6 +554,14 @@ KeyValue ChargePointConfiguration::getVerifyCsmsCommonNameKeyValue() {
return kv;
}

KeyValue ChargePointConfiguration::getVerifyCsmsAllowWildcardsKeyValue() {
KeyValue kv;
kv.key = "VerifyCsmsAllowWildcards";
kv.readonly = true;
kv.value.emplace(ocpp::conversions::bool_to_string(this->getVerifyCsmsAllowWildcards()));
return kv;
}

KeyValue ChargePointConfiguration::getSupportedMeasurandsKeyValue() {
KeyValue kv;
kv.key = "SupportedMeasurands";
Expand Down Expand Up @@ -2256,6 +2268,9 @@ std::optional<KeyValue> ChargePointConfiguration::get(CiString<50> key) {
if (key == "VerifyCsmsCommonName") {
return this->getVerifyCsmsCommonNameKeyValue();
}
if (key == "VerifyCsmsAllowWildcards") {
return this->getVerifyCsmsAllowWildcardsKeyValue();
}
if (key == "OcspRequestInterval") {
return this->getOcspRequestIntervalKeyValue();
}
Expand Down Expand Up @@ -2841,6 +2856,14 @@ ConfigurationStatus ChargePointConfiguration::set(CiString<50> key, CiString<500
}
}

if (key == "VerifyCsmsAllowWildcards") {
if (isBool(value.get())) {
this->setVerifyCsmsAllowWildcards(ocpp::conversions::string_to_bool(value.get()));
} else {
return ConfigurationStatus::Rejected;
}
}

// Hubject PnC Extension keys
if (key == "SeccLeafSubjectCommonName") {
if (this->getSeccLeafSubjectCommonName().has_value()) {
Expand Down
3 changes: 1 addition & 2 deletions lib/ocpp/v16/charge_point_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,7 @@ WebsocketConnectionOptions ChargePointImpl::get_ws_connection_options() {
this->configuration->getHostName(),
this->configuration->getVerifyCsmsCommonName(),
this->configuration->getUseTPM(),
this->configuration->getVerifyCsmsAllowWildcards()
};
this->configuration->getVerifyCsmsAllowWildcards()};
return connection_options;
}

Expand Down
14 changes: 8 additions & 6 deletions lib/ocpp/v201/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,10 +860,10 @@ WebsocketConnectionOptions ChargePoint::get_ws_connection_options(const int32_t
this->device_model->get_optional_value<bool>(ControllerComponentVariables::AdditionalRootCertificateCheck)
.value_or(false),
std::nullopt, // hostName
true, // verify_csms_common_name
false, // use tpm
false // verify_csms_allow_wildcards
};
this->device_model->get_optional_value<bool>(ControllerComponentVariables::VerifyCsmsCommonName).value_or(true),
this->device_model->get_optional_value<bool>(ControllerComponentVariables::UseTPM).value_or(false),
this->device_model->get_optional_value<bool>(ControllerComponentVariables::VerifyCsmsAllowWildcards)
.value_or(false)};

return connection_options;
}
Expand Down Expand Up @@ -1612,9 +1612,11 @@ void ChargePoint::sign_certificate_req(const ocpp::CertificateSigningUseEnum& ce
return;
}

// TODO: use_tpm is hardcoded false here, see if it will require change
bool should_use_tpm =
this->device_model->get_optional_value<bool>(ControllerComponentVariables::UseTPM).value_or(false);

const auto csr = this->evse_security->generate_certificate_signing_request(
certificate_signing_use, country.value(), organization.value(), common.value(), false);
certificate_signing_use, country.value(), organization.value(), common.value(), should_use_tpm);
req.csr = csr;

this->awaited_certificate_signing_use_enum = certificate_signing_use;
Expand Down
21 changes: 21 additions & 0 deletions lib/ocpp/v201/ctrlr_component_variables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,27 @@ const ComponentVariable& UseSslDefaultVerifyPaths = {
"UseSslDefaultVerifyPaths",
}),
};
const ComponentVariable& VerifyCsmsCommonName = {
ControllerComponents::InternalCtrlr,
std::nullopt,
std::optional<Variable>({
"VerifyCsmsCommonName",
}),
};
const ComponentVariable& UseTPM = {
ControllerComponents::InternalCtrlr,
std::nullopt,
std::optional<Variable>({
"UseTPM",
}),
};
const ComponentVariable& VerifyCsmsAllowWildcards = {
ControllerComponents::InternalCtrlr,
std::nullopt,
std::optional<Variable>({
"VerifyCsmsAllowWildcards",
}),
};
const ComponentVariable& OcspRequestInterval = {
ControllerComponents::InternalCtrlr,
std::nullopt,
Expand Down

0 comments on commit ba68d6d

Please sign in to comment.