From ba68d6d7a5f56da7634f6a2e7429535638c895ca Mon Sep 17 00:00:00 2001 From: AssemblyJohn Date: Mon, 4 Mar 2024 15:53:28 +0200 Subject: [PATCH] Added config possibility for v201, removed extra check code Signed-off-by: AssemblyJohn --- config/v16/profile_schemas/Internal.json | 4 +- .../standardized/InternalCtrlr.json | 45 ++++++++ .../ocpp/v16/charge_point_configuration.hpp | 2 + .../ocpp/v201/ctrlr_component_variables.hpp | 3 + lib/ocpp/common/websocket/websocket_tls.cpp | 102 +----------------- lib/ocpp/v16/charge_point_configuration.cpp | 23 ++++ lib/ocpp/v16/charge_point_impl.cpp | 3 +- lib/ocpp/v201/charge_point.cpp | 14 +-- lib/ocpp/v201/ctrlr_component_variables.cpp | 21 ++++ 9 files changed, 107 insertions(+), 110 deletions(-) diff --git a/config/v16/profile_schemas/Internal.json b/config/v16/profile_schemas/Internal.json index 343154aed1..346296aaa1 100644 --- a/config/v16/profile_schemas/Internal.json +++ b/config/v16/profile_schemas/Internal.json @@ -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": { diff --git a/config/v201/component_schemas/standardized/InternalCtrlr.json b/config/v201/component_schemas/standardized/InternalCtrlr.json index c03deb5aa3..9a4c36574b 100644 --- a/config/v201/component_schemas/standardized/InternalCtrlr.json +++ b/config/v201/component_schemas/standardized/InternalCtrlr.json @@ -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": { diff --git a/include/ocpp/v16/charge_point_configuration.hpp b/include/ocpp/v16/charge_point_configuration.hpp index 9f6957ff06..222131a98f 100644 --- a/include/ocpp/v16/charge_point_configuration.hpp +++ b/include/ocpp/v16/charge_point_configuration.hpp @@ -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(); diff --git a/include/ocpp/v201/ctrlr_component_variables.hpp b/include/ocpp/v201/ctrlr_component_variables.hpp index 3009f2b289..603e094314 100644 --- a/include/ocpp/v201/ctrlr_component_variables.hpp +++ b/include/ocpp/v201/ctrlr_component_variables.hpp @@ -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; diff --git a/lib/ocpp/common/websocket/websocket_tls.cpp b/lib/ocpp/common/websocket/websocket_tls.cpp index 3fb673bbdb..bb82d43145 100644 --- a/lib/ocpp/common/websocket/websocket_tls.cpp +++ b/lib/ocpp/common/websocket/websocket_tls.cpp @@ -16,98 +16,6 @@ namespace ocpp { -static std::vector get_subject_alt_names(const X509* x509) { - std::vector list; - GENERAL_NAMES* subject_alt_names = - static_cast(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(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(ip[0]) << '.' << static_cast(ip[1]) << '.' << static_cast(ip[2]) - << '.' << static_cast(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 evse_security) : WebsocketBase(), evse_security(evse_security) { @@ -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); @@ -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!"; diff --git a/lib/ocpp/v16/charge_point_configuration.cpp b/lib/ocpp/v16/charge_point_configuration.cpp index cb0aa0fe21..a82c73ea24 100644 --- a/lib/ocpp/v16/charge_point_configuration.cpp +++ b/lib/ocpp/v16/charge_point_configuration.cpp @@ -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"]; @@ -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"; @@ -2256,6 +2268,9 @@ std::optional ChargePointConfiguration::get(CiString<50> key) { if (key == "VerifyCsmsCommonName") { return this->getVerifyCsmsCommonNameKeyValue(); } + if (key == "VerifyCsmsAllowWildcards") { + return this->getVerifyCsmsAllowWildcardsKeyValue(); + } if (key == "OcspRequestInterval") { return this->getOcspRequestIntervalKeyValue(); } @@ -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()) { diff --git a/lib/ocpp/v16/charge_point_impl.cpp b/lib/ocpp/v16/charge_point_impl.cpp index bcbf36c802..88aee7032a 100644 --- a/lib/ocpp/v16/charge_point_impl.cpp +++ b/lib/ocpp/v16/charge_point_impl.cpp @@ -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; } diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 1da5ee4bf7..0f1d460b30 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -860,10 +860,10 @@ WebsocketConnectionOptions ChargePoint::get_ws_connection_options(const int32_t this->device_model->get_optional_value(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(ControllerComponentVariables::VerifyCsmsCommonName).value_or(true), + this->device_model->get_optional_value(ControllerComponentVariables::UseTPM).value_or(false), + this->device_model->get_optional_value(ControllerComponentVariables::VerifyCsmsAllowWildcards) + .value_or(false)}; return connection_options; } @@ -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(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; diff --git a/lib/ocpp/v201/ctrlr_component_variables.cpp b/lib/ocpp/v201/ctrlr_component_variables.cpp index 6f31079e6f..1945b21a2d 100644 --- a/lib/ocpp/v201/ctrlr_component_variables.cpp +++ b/lib/ocpp/v201/ctrlr_component_variables.cpp @@ -193,6 +193,27 @@ const ComponentVariable& UseSslDefaultVerifyPaths = { "UseSslDefaultVerifyPaths", }), }; +const ComponentVariable& VerifyCsmsCommonName = { + ControllerComponents::InternalCtrlr, + std::nullopt, + std::optional({ + "VerifyCsmsCommonName", + }), +}; +const ComponentVariable& UseTPM = { + ControllerComponents::InternalCtrlr, + std::nullopt, + std::optional({ + "UseTPM", + }), +}; +const ComponentVariable& VerifyCsmsAllowWildcards = { + ControllerComponents::InternalCtrlr, + std::nullopt, + std::optional({ + "VerifyCsmsAllowWildcards", + }), +}; const ComponentVariable& OcspRequestInterval = { ControllerComponents::InternalCtrlr, std::nullopt,