From 83993da158534a4498fab7f808c312e2308a0b0f Mon Sep 17 00:00:00 2001 From: Marc Emmers <35759328+marcemmers@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:59:48 +0100 Subject: [PATCH] Optionally allow security level 0 connections (#856) * Add option to allow security level 0 connection in OCPP 2.0.1 Signed-off-by: Marc Emmers * Add warning print in case we do use security level 0 Signed-off-by: Marc Emmers * Update description in json Signed-off-by: Marc Emmers * Skip profile instead of crashing when invalid Signed-off-by: Marc Emmers * Add throw if all profiles are 0 since we would never start connecting anyway Signed-off-by: Marc Emmers --------- Signed-off-by: Marc Emmers --- .../standardized/InternalCtrlr.json | 16 +++++++++++ .../ocpp/v201/ctrlr_component_variables.hpp | 1 + lib/ocpp/v201/connectivity_manager.cpp | 28 +++++++++++++++---- lib/ocpp/v201/ctrlr_component_variables.cpp | 7 +++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/config/v201/component_config/standardized/InternalCtrlr.json b/config/v201/component_config/standardized/InternalCtrlr.json index d743ad569..f2ca627fc 100644 --- a/config/v201/component_config/standardized/InternalCtrlr.json +++ b/config/v201/component_config/standardized/InternalCtrlr.json @@ -802,6 +802,22 @@ "description": "The flag that indicates if installation of ManufacturerRootCertificate is allowed when security profile is 1.", "default": true, "type": "boolean" + }, + "AllowSecurityLevelZeroConnections": { + "variable_name": "AllowSecurityLevelZeroConnections", + "characteristics": { + "supportsMonitoring": false, + "dataType": "boolean" + }, + "attributes": [ + { + "type": "Actual", + "mutability": "ReadOnly" + } + ], + "description": "If enabled we allow connections using security level 0. This does pose a security risk and is not allowed according to the OCPP spec", + "default": false, + "type": "boolean" } }, "required": [ diff --git a/include/ocpp/v201/ctrlr_component_variables.hpp b/include/ocpp/v201/ctrlr_component_variables.hpp index 6f3dad8bb..dfe37e4e3 100644 --- a/include/ocpp/v201/ctrlr_component_variables.hpp +++ b/include/ocpp/v201/ctrlr_component_variables.hpp @@ -86,6 +86,7 @@ extern const ComponentVariable& ClientCertificateExpireCheckIntervalSeconds; extern const ComponentVariable& MessageQueueSizeThreshold; extern const ComponentVariable& MaxMessageSize; extern const ComponentVariable& ResumeTransactionsOnBoot; +extern const ComponentVariable& AllowSecurityLevelZeroConnections; extern const ComponentVariable& AlignedDataCtrlrEnabled; extern const ComponentVariable& AlignedDataCtrlrAvailable; extern const RequiredComponentVariable& AlignedDataInterval; diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index d06c2de14..98e14b76a 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -75,11 +75,13 @@ ConnectivityManager::get_network_connection_profile(const int32_t configuration_ for (const auto& network_profile : this->cached_network_connection_profiles) { if (network_profile.configurationSlot == configuration_slot) { - if (network_profile.connectionData.securityProfile == - security::OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION) { - throw std::invalid_argument( - "security_profile = " + std::to_string(network_profile.connectionData.securityProfile) + - " not officially allowed in OCPP 2.0.1"); + if (!this->device_model + .get_optional_value(ControllerComponentVariables::AllowSecurityLevelZeroConnections) + .value_or(false) && + network_profile.connectionData.securityProfile == + security::OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION) { + EVLOG_error << "security_profile 0 not officially allowed in OCPP 2.0.1, skipping profile"; + return std::nullopt; } return network_profile.connectionData; @@ -211,6 +213,11 @@ void ConnectivityManager::try_connect_websocket() { this->active_network_configuration_priority = get_priority_from_configuration_slot(configuration_slot_to_set).value(); + if (connection_options->security_profile == + security::OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION) { + EVLOG_warning << "Using insecure security profile 0 without authentication"; + } + EVLOG_info << "Open websocket with NetworkConfigurationPriority: " << this->active_network_configuration_priority + 1 << " which is configurationSlot " << configuration_slot_to_set; @@ -410,6 +417,17 @@ void ConnectivityManager::cache_network_connection_profiles() { this->cached_network_connection_profiles = json::parse(this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); + if (!this->device_model.get_optional_value(ControllerComponentVariables::AllowSecurityLevelZeroConnections) + .value_or(false) && + std::none_of(this->cached_network_connection_profiles.begin(), this->cached_network_connection_profiles.end(), + [](const SetNetworkProfileRequest& profile) { + return profile.connectionData.securityProfile != + security::OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION; + })) { + throw std::invalid_argument( + "All profiles configured have security_profile 0 which is not officially allowed in OCPP 2.0.1"); + } + for (const std::string& str : ocpp::split_string( this->device_model.get_value(ControllerComponentVariables::NetworkConfigurationPriority), ',')) { diff --git a/lib/ocpp/v201/ctrlr_component_variables.cpp b/lib/ocpp/v201/ctrlr_component_variables.cpp index 474abb1dc..52c3cb9c4 100644 --- a/lib/ocpp/v201/ctrlr_component_variables.cpp +++ b/lib/ocpp/v201/ctrlr_component_variables.cpp @@ -373,6 +373,13 @@ const ComponentVariable& AllowMFRootCertInstallWithUnsecureConnection = { "AllowMFRootCertInstallWithUnsecureConnection", }), }; +const ComponentVariable& AllowSecurityLevelZeroConnections = { + ControllerComponents::InternalCtrlr, + std::nullopt, + std::optional({ + "AllowSecurityLevelZeroConnections", + }), +}; const ComponentVariable& AlignedDataCtrlrEnabled = { ControllerComponents::AlignedDataCtrlr, std::nullopt,