diff --git a/include/evse_security/evse_security.hpp b/include/evse_security/evse_security.hpp index 3469e17..200656a 100644 --- a/include/evse_security/evse_security.hpp +++ b/include/evse_security/evse_security.hpp @@ -225,9 +225,16 @@ class EvseSecurity { /// update_leaf_certificate /// @param certificate_type /// @return CA certificate file + std::string get_verify_file(CaCertificateType certificate_type); + + /// @brief Retrieves the PEM formatted CA bundle location for the given \p certificate_type It is not recommended to + /// add the SUBCAs to any root certificate bundle, but to leave them in the leaf file. Returns either file + /// or directory where the cerificates are located + /// @param certificate_type + /// @return CA certificate location std::string get_verify_location(CaCertificateType certificate_type); - /// @brief An extension of 'get_verify_location' with error handling included + /// @brief An extension of 'get_verify_file' with error handling included GetCertificateInfoResult get_ca_certificate_info(CaCertificateType certificate_type); /// @brief Gets the expiry day count for the leaf certificate of the given \p certificate_type diff --git a/lib/evse_security/evse_security.cpp b/lib/evse_security/evse_security.cpp index 591f8a6..d458ef9 100644 --- a/lib/evse_security/evse_security.cpp +++ b/lib/evse_security/evse_security.cpp @@ -1492,24 +1492,38 @@ GetCertificateInfoResult EvseSecurity::get_ca_certificate_info_internal(CaCertif try { // Support bundle files, in case the certificates contain // multiple entries (should be 3) as per the specification - X509CertificateBundle verify_location(this->ca_bundle_path_map.at(certificate_type), EncodingFormat::PEM); + X509CertificateBundle verify_file(this->ca_bundle_path_map.at(certificate_type), EncodingFormat::PEM); - EVLOG_info << "Requesting certificate location: [" - << conversions::ca_certificate_type_to_string(certificate_type) - << "] location:" << verify_location.get_path(); + EVLOG_info << "Requesting certificate file: [" << conversions::ca_certificate_type_to_string(certificate_type) + << "] file:" << verify_file.get_path(); - if (!verify_location.empty()) { + // If we are using a directory, search for the first valid root file + if (verify_file.is_using_directory()) { + auto& hierarchy = verify_file.get_certficate_hierarchy(); + + // Get all roots and search for a valid self-signed + for (auto& root : hierarchy.get_hierarchy()) { + if (root.certificate.is_selfsigned() && root.certificate.is_valid()) { + CertificateInfo info; + info.certificate = root.certificate.get_file().value(); + info.certificate_single = root.certificate.get_file().value(); + + result.info = info; + result.status = GetCertificateInfoStatus::Accepted; + return result; + } + } + } else { CertificateInfo info; - info.certificate = verify_location.get_path(); - info.certificate_single = verify_location.get_path(); + info.certificate = verify_file.get_path(); + info.certificate_single = verify_file.get_path(); result.info = info; result.status = GetCertificateInfoStatus::Accepted; return result; } - } catch (const CertificateLoadException& e) { - EVLOG_error << "Could not obtain verify location, wrong format for certificate: " + EVLOG_error << "Could not obtain verify file, wrong format for certificate: " << this->ca_bundle_path_map.at(certificate_type) << " with error: " << e.what(); } @@ -1526,7 +1540,7 @@ GetCertificateInfoResult EvseSecurity::get_ca_certificate_info(CaCertificateType return get_ca_certificate_info_internal(certificate_type); } -std::string EvseSecurity::get_verify_location(CaCertificateType certificate_type) { +std::string EvseSecurity::get_verify_file(CaCertificateType certificate_type) { std::lock_guard guard(EvseSecurity::security_mutex); auto result = get_ca_certificate_info_internal(certificate_type); @@ -1540,6 +1554,35 @@ std::string EvseSecurity::get_verify_location(CaCertificateType certificate_type return {}; } +std::string EvseSecurity::get_verify_location(CaCertificateType certificate_type) { + + std::lock_guard guard(EvseSecurity::security_mutex); + GetCertificateInfoResult result{}; + + try { + // Support bundle files, in case the certificates contain + // multiple entries (should be 3) as per the specification + X509CertificateBundle verify_location(this->ca_bundle_path_map.at(certificate_type), EncodingFormat::PEM); + + EVLOG_info << "Requesting certificate location: [" + << conversions::ca_certificate_type_to_string(certificate_type) + << "] location:" << verify_location.get_path(); + + if (!verify_location.empty()) { + return verify_location.get_path(); + } + + } catch (const CertificateLoadException& e) { + EVLOG_error << "Could not obtain verify location, wrong format for certificate: " + << this->ca_bundle_path_map.at(certificate_type) << " with error: " << e.what(); + } + + EVLOG_error << "Could not find any CA certificate for: " + << conversions::ca_certificate_type_to_string(certificate_type); + + return {}; +} + int EvseSecurity::get_leaf_expiry_days_count(LeafCertificateType certificate_type) { std::lock_guard guard(EvseSecurity::security_mutex); diff --git a/tests/tests.cpp b/tests/tests.cpp index b2e3409..2e87714 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -407,7 +407,7 @@ TEST_F(EvseSecurityTests, verify_v2g_cert_02) { TEST_F(EvseSecurityTests, retrieve_root_ca) { std::string path = "certs/ca/v2g/V2G_CA_BUNDLE.pem"; - std::string retrieved_path = this->evse_security->get_verify_location(CaCertificateType::V2G); + std::string retrieved_path = this->evse_security->get_verify_file(CaCertificateType::V2G); ASSERT_EQ(path, retrieved_path); } @@ -418,7 +418,7 @@ TEST_F(EvseSecurityTests, install_root_ca_01) { ASSERT_TRUE(result == InstallCertificateResult::Accepted); std::string path = "certs/ca/v2g/V2G_CA_BUNDLE.pem"; - ASSERT_EQ(this->evse_security->get_verify_location(CaCertificateType::V2G), path); + ASSERT_EQ(this->evse_security->get_verify_file(CaCertificateType::V2G), path); const auto read_v2g_root_ca = read_file_to_string(path); X509CertificateBundle root_bundle(read_v2g_root_ca, EncodingFormat::PEM);