diff --git a/include/ocpp/common/evse_security.hpp b/include/ocpp/common/evse_security.hpp index 576151578..cd4f45ec0 100644 --- a/include/ocpp/common/evse_security.hpp +++ b/include/ocpp/common/evse_security.hpp @@ -87,7 +87,7 @@ class EvseSecurity { /// \param organization /// \param common /// \return the PEM formatted certificate signing request - virtual std::optional + virtual GetCertificateSignRequestResult generate_certificate_signing_request(const CertificateSigningUseEnum& certificate_type, const std::string& country, const std::string& organization, const std::string& common, bool use_tpm) = 0; diff --git a/include/ocpp/common/evse_security_impl.hpp b/include/ocpp/common/evse_security_impl.hpp index 9d61ba92a..f3b90c4c8 100644 --- a/include/ocpp/common/evse_security_impl.hpp +++ b/include/ocpp/common/evse_security_impl.hpp @@ -48,10 +48,10 @@ class EvseSecurityImpl : public EvseSecurity { void update_ocsp_cache(const CertificateHashDataType& certificate_hash_data, const std::string& ocsp_response) override; bool is_ca_certificate_installed(const CaCertificateType& certificate_type) override; - std::optional generate_certificate_signing_request(const CertificateSigningUseEnum& certificate_type, - const std::string& country, - const std::string& organization, - const std::string& common, bool use_tpm) override; + GetCertificateSignRequestResult + generate_certificate_signing_request(const CertificateSigningUseEnum& certificate_type, const std::string& country, + const std::string& organization, const std::string& common, + bool use_tpm) override; std::optional get_leaf_certificate_info(const CertificateSigningUseEnum& certificate_type, bool include_ocsp = false) override; bool update_certificate_links(const CertificateSigningUseEnum& certificate_type) override; @@ -61,6 +61,7 @@ class EvseSecurityImpl : public EvseSecurity { namespace conversions { +GetCertificateSignRequestStatus to_ocpp(evse_security::GetCertificateSignRequestStatus other); CaCertificateType to_ocpp(evse_security::CaCertificateType other); CertificateSigningUseEnum to_ocpp(evse_security::LeafCertificateType other); CertificateType to_ocpp(evse_security::CertificateType other); diff --git a/include/ocpp/common/types.hpp b/include/ocpp/common/types.hpp index 14aa41ac9..6dded170f 100644 --- a/include/ocpp/common/types.hpp +++ b/include/ocpp/common/types.hpp @@ -531,6 +531,18 @@ struct OCSPRequestData { std::string responderUrl; }; +enum class GetCertificateSignRequestStatus { + Accepted, + InvalidRequestedType, ///< Requested a CSR for non CSMS/V2G leafs + KeyGenError, ///< The key could not be generated with the requested/default parameters + GenerationError, ///< Any other error when creating the CSR +}; + +struct GetCertificateSignRequestResult { + GetCertificateSignRequestStatus status; + std::optional csr; +}; + struct CertificateOCSP { CertificateHashDataType hash; std::optional ocsp_path; @@ -587,6 +599,11 @@ enum class FirmwareStatusNotification { SignatureVerified }; +namespace conversions { +/// \brief Converts GetCertificateSignRequestStatus to string +std::string generate_certificate_signing_request_status_to_string(const GetCertificateSignRequestStatus status); +} // namespace conversions + namespace conversions { /// \brief Converts ocpp::FirmwareStatusNotification to v16::FirmwareStatus @@ -620,6 +637,7 @@ namespace security_events { inline const std::string FIRMWARE_UPDATED = "FirmwareUpdated"; // CRITICAL inline const std::string FAILEDTOAUTHENTICATEATCSMS = "FailedToAuthenticateAtCsms"; inline const std::string CSMSFAILEDTOAUTHENTICATE = "CsmsFailedToAuthenticate"; +inline const std::string CSRGENERATIONFAILED = "CSRGenerationFailed"; inline const std::string SETTINGSYSTEMTIME = "SettingSystemTime"; // CRITICAL inline const std::string RESET_OR_REBOOT = "ResetOrReboot"; // CRITICAL inline const std::string STARTUP_OF_THE_DEVICE = "StartupOfTheDevice"; // CRITICAL diff --git a/lib/ocpp/common/evse_security_impl.cpp b/lib/ocpp/common/evse_security_impl.cpp index b01063924..f0a989835 100644 --- a/lib/ocpp/common/evse_security_impl.cpp +++ b/lib/ocpp/common/evse_security_impl.cpp @@ -96,19 +96,21 @@ bool EvseSecurityImpl::is_ca_certificate_installed(const CaCertificateType& cert return this->evse_security->is_ca_certificate_installed(conversions::from_ocpp(certificate_type)); } -std::optional +GetCertificateSignRequestResult EvseSecurityImpl::generate_certificate_signing_request(const CertificateSigningUseEnum& certificate_type, const std::string& country, const std::string& organization, const std::string& common, bool use_tpm) { auto csr_response = this->evse_security->generate_certificate_signing_request( conversions::from_ocpp(certificate_type), country, organization, common, use_tpm); - if (csr_response.status == evse_security::GetCertificateSignRequestStatus::Accepted && - csr_response.csr.has_value()) { - return csr_response.csr; - } else { - return std::nullopt; + GetCertificateSignRequestResult result; + result.status = conversions::to_ocpp(csr_response.status); + + if (csr_response.csr.has_value()) { + result.csr = csr_response.csr; } + + return result; } std::optional @@ -137,6 +139,22 @@ int EvseSecurityImpl::get_leaf_expiry_days_count(const CertificateSigningUseEnum namespace conversions { +GetCertificateSignRequestStatus to_ocpp(evse_security::GetCertificateSignRequestStatus other) { + switch (other) { + case evse_security::GetCertificateSignRequestStatus::Accepted: + return GetCertificateSignRequestStatus::Accepted; + case evse_security::GetCertificateSignRequestStatus::InvalidRequestedType: + return GetCertificateSignRequestStatus::InvalidRequestedType; + case evse_security::GetCertificateSignRequestStatus::KeyGenError: + return GetCertificateSignRequestStatus::KeyGenError; + case evse_security::GetCertificateSignRequestStatus::GenerationError: + return GetCertificateSignRequestStatus::GenerationError; + default: + throw std::runtime_error( + "Could not convert evse_security::GetCertificateSignRequestStatus to GetCertificateSignRequestStatus"); + } +} + CaCertificateType to_ocpp(evse_security::CaCertificateType other) { switch (other) { case evse_security::CaCertificateType::V2G: diff --git a/lib/ocpp/common/types.cpp b/lib/ocpp/common/types.cpp index 976bb1092..8342b613c 100644 --- a/lib/ocpp/common/types.cpp +++ b/lib/ocpp/common/types.cpp @@ -996,6 +996,23 @@ std::string double_to_string(double d) { } // namespace conversions +namespace conversions { +std::string generate_certificate_signing_request_status_to_string(const GetCertificateSignRequestStatus status) { + switch (status) { + case GetCertificateSignRequestStatus::Accepted: + return "Accepted"; + case GetCertificateSignRequestStatus::InvalidRequestedType: + return "InvalidRequestedType"; + case GetCertificateSignRequestStatus::KeyGenError: + return "KeyGenError"; + case GetCertificateSignRequestStatus::GenerationError: + return "GenerationError"; + default: + throw std::out_of_range("Could not convert GetCertificateSignRequestStatus to string"); + } +} +} // namespace conversions + namespace conversions { v16::FirmwareStatus firmware_status_notification_to_firmware_status(const FirmwareStatusNotification status) { switch (status) { diff --git a/lib/ocpp/v16/charge_point_impl.cpp b/lib/ocpp/v16/charge_point_impl.cpp index 74516123c..f638bd6d9 100644 --- a/lib/ocpp/v16/charge_point_impl.cpp +++ b/lib/ocpp/v16/charge_point_impl.cpp @@ -2240,19 +2240,25 @@ void ChargePointImpl::sign_certificate(const ocpp::CertificateSigningUseEnum& ce EVLOG_info << "Create CSR (TPM=" << this->configuration->getUseTPM() << ")"; SignCertificateRequest req; - const auto csr = this->evse_security->generate_certificate_signing_request( + const auto response = this->evse_security->generate_certificate_signing_request( certificate_signing_use, this->configuration->getSeccLeafSubjectCountry().value_or("DE"), this->configuration->getCpoName().value(), this->configuration->getChargeBoxSerialNumber(), this->configuration->getUseTPM()); - if (!csr.has_value()) { + if (response.status != GetCertificateSignRequestStatus::Accepted || !response.csr.has_value()) { EVLOG_error << "Create CSR (TPM=" << this->configuration->getUseTPM() << ")" << " failed for:" << ocpp::conversions::certificate_signing_use_enum_to_string(certificate_signing_use); + + std::string gen_error = + "Sign certificate failed due to:" + + ocpp::conversions::generate_certificate_signing_request_status_to_string(response.status); + this->securityEventNotification(ocpp::security_events::CSRGENERATIONFAILED, gen_error, true); + return; } - req.csr = csr.value(); + req.csr = response.csr.value(); ocpp::Call call(req, this->message_queue->createMessageId()); this->send(call, initiated_by_trigger_message); @@ -2934,19 +2940,24 @@ void ChargePointImpl::data_transfer_pnc_sign_certificate() { ocpp::v201::SignCertificateRequest csr_req; - const auto csr = this->evse_security->generate_certificate_signing_request( + const auto result = this->evse_security->generate_certificate_signing_request( ocpp::CertificateSigningUseEnum::V2GCertificate, this->configuration->getSeccLeafSubjectCountry().value_or("DE"), this->configuration->getSeccLeafSubjectOrganization().value_or(this->configuration->getCpoName().value()), this->configuration->getSeccLeafSubjectCommonName().value_or(this->configuration->getChargeBoxSerialNumber()), this->configuration->getUseTPM()); - if (!csr.has_value()) { + if (result.status != GetCertificateSignRequestStatus::Accepted || !result.csr.has_value()) { EVLOG_error << "Could not request new V2GCertificate, because the CSR was not successful."; + + std::string gen_error = "Data transfer pnc csr failed due to:" + + ocpp::conversions::generate_certificate_signing_request_status_to_string(result.status); + this->securityEventNotification(ocpp::security_events::CSRGENERATIONFAILED, gen_error, true); + return; } - csr_req.csr = csr.value(); + csr_req.csr = result.csr.value(); csr_req.certificateType = ocpp::v201::CertificateSigningUseEnum::V2GCertificate; req.data.emplace(json(csr_req).dump()); diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 9f7a5d0b5..01df10e74 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1800,16 +1800,21 @@ void ChargePoint::sign_certificate_req(const ocpp::CertificateSigningUseEnum& ce 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( + const auto result = this->evse_security->generate_certificate_signing_request( certificate_signing_use, country.value(), organization.value(), common.value(), should_use_tpm); - if (!csr.has_value()) { + if (result.status != GetCertificateSignRequestStatus::Accepted || !result.csr.has_value()) { EVLOG_error << "CSR generation was unsuccessful for sign request: " << ocpp::conversions::certificate_signing_use_enum_to_string(certificate_signing_use); + + std::string gen_error = "Sign certificate req failed due to:" + + ocpp::conversions::generate_certificate_signing_request_status_to_string(result.status); + this->security_event_notification_req(ocpp::security_events::CSRGENERATIONFAILED, + std::optional>(gen_error), true, true); return; } - req.csr = csr.value(); + req.csr = result.csr.value(); this->awaited_certificate_signing_use_enum = certificate_signing_use; diff --git a/tests/evse_security_mock.hpp b/tests/evse_security_mock.hpp index 2f8fb4e58..a0d6699a3 100644 --- a/tests/evse_security_mock.hpp +++ b/tests/evse_security_mock.hpp @@ -26,7 +26,7 @@ class EvseSecurityMock : public EvseSecurity { MOCK_METHOD(std::vector, get_mo_ocsp_request_data, (const std::string&), (override)); MOCK_METHOD(void, update_ocsp_cache, (const CertificateHashDataType&, const std::string&), (override)); MOCK_METHOD(bool, is_ca_certificate_installed, (const CaCertificateType&), (override)); - MOCK_METHOD(std::optional, generate_certificate_signing_request, + MOCK_METHOD(GetCertificateSignRequestResult, generate_certificate_signing_request, (const CertificateSigningUseEnum&, const std::string&, const std::string&, const std::string&, bool), (override)); MOCK_METHOD(std::optional, get_leaf_certificate_info, (const CertificateSigningUseEnum&, bool),