diff --git a/include/evse_security/evse_security.hpp b/include/evse_security/evse_security.hpp index 36520ab..c993008 100644 --- a/include/evse_security/evse_security.hpp +++ b/include/evse_security/evse_security.hpp @@ -122,7 +122,7 @@ class EvseSecurity { /// @param certificate_chain PEM formatted certificate or certificate chain /// @param certificate_type type of the leaf certificate /// @return contains OCSP request data - OCSPRequestDataList get_ocsp_request_data(const std::string& certificate_chain); + OCSPRequestDataList get_mo_ocsp_request_data(const std::string& certificate_chain); /// @brief Updates the OCSP cache for the given \p certificate_hash_data with the given \p ocsp_response /// @param certificate_hash_data identifies the certificate for which the \p ocsp_response is specified diff --git a/lib/evse_security/evse_security.cpp b/lib/evse_security/evse_security.cpp index 52d08f8..736d0dc 100644 --- a/lib/evse_security/evse_security.cpp +++ b/lib/evse_security/evse_security.cpp @@ -160,9 +160,8 @@ static std::set get_certificate_path_of_key(const fs::path& key, const throw NoCertificateValidException(error); } -X509CertificateBundle get_leaf_certificates(const fs::path& cert_dir) { - return X509CertificateBundle(cert_dir, EncodingFormat::PEM); -} +// Declared here to avoid requirement of X509Wrapper include in header +static OCSPRequestDataList get_ocsp_request_data_internal(fs::path& root_path, std::vector& leaf_chain); std::mutex EvseSecurity::security_mutex; @@ -624,63 +623,86 @@ int EvseSecurity::get_count_of_installed_certificates(const std::vector guard(EvseSecurity::security_mutex); - OCSPRequestDataList response; - std::vector ocsp_request_data_list; - try { const auto secc_key_pair = this->get_key_pair_internal(LeafCertificateType::V2G, EncodingFormat::PEM); + if (secc_key_pair.status != GetKeyPairStatus::Accepted or !secc_key_pair.pair.has_value()) { - return response; + EVLOG_error << "Could not get key pair, for v2g ocsp request!"; + return OCSPRequestDataList(); } - X509CertificateBundle leaf_bundle(secc_key_pair.pair.value().certificate, EncodingFormat::PEM); + std::vector chain = + std::move(X509CertificateBundle(secc_key_pair.pair.value().certificate, EncodingFormat::PEM).split()); + return get_ocsp_request_data_internal(this->ca_bundle_path_map.at(CaCertificateType::V2G), chain); + } catch (const CertificateLoadException& e) { + EVLOG_error << "Could not get v2g ocsp cache, certificate load failure: " << e.what(); + } - // Build hierarchy for the bundle - auto& hierarchy = leaf_bundle.get_certficate_hierarchy(); + return OCSPRequestDataList(); +} - // Iterate cache, get hashes - hierarchy.for_each([&](const X509Node& node) { - std::string responder_url = node.certificate.get_responder_url(); - auto certificate_hash_data = node.hash; - if (!responder_url.empty() and certificate_hash_data.is_valid()) { - OCSPRequestData ocsp_request_data = {certificate_hash_data, responder_url}; - ocsp_request_data_list.push_back(ocsp_request_data); - } +OCSPRequestDataList EvseSecurity::get_mo_ocsp_request_data(const std::string& certificate_chain) { + std::lock_guard guard(EvseSecurity::security_mutex); - return true; - }); + try { + std::vector chain = + std::move(X509CertificateBundle(certificate_chain, EncodingFormat::PEM).split()); - response.ocsp_request_data_list = ocsp_request_data_list; + // Find the MO root + return get_ocsp_request_data_internal(this->ca_bundle_path_map.at(CaCertificateType::MO), chain); } catch (const CertificateLoadException& e) { - EVLOG_error << "Could not get ocsp cache, certificate load failure: " << e.what(); + EVLOG_error << "Could not get mo ocsp cache, certificate load failure: " << e.what(); } - return response; + return OCSPRequestDataList(); } -OCSPRequestDataList EvseSecurity::get_ocsp_request_data(const std::string& certificate_chain) { - std::lock_guard guard(EvseSecurity::security_mutex); - +OCSPRequestDataList get_ocsp_request_data_internal(fs::path& root_path, std::vector& leaf_chain) { OCSPRequestDataList response; std::vector ocsp_request_data_list; try { - X509CertificateBundle leaf_bundle(certificate_chain, EncodingFormat::PEM); - X509CertificateHierarchy& hierarchy = leaf_bundle.get_certficate_hierarchy(); - - hierarchy.for_each([&](const X509Node& node) { - std::string responder_url = node.certificate.get_responder_url(); - auto certificate_hash_data = node.hash; - if (!responder_url.empty() and certificate_hash_data.is_valid()) { - OCSPRequestData ocsp_request_data = {certificate_hash_data, responder_url}; - ocsp_request_data_list.push_back(ocsp_request_data); + std::vector full_hierarchy = X509CertificateBundle(root_path, EncodingFormat::PEM).split(); + std::move(std::begin(leaf_chain), std::end(leaf_chain), std::back_inserter(full_hierarchy)); + + // Build the full hierarchy + auto hierarchy = X509CertificateHierarchy::build_hierarchy(full_hierarchy); + + // Search for the first valid root, and collect all the chain + for (auto& root : hierarchy.get_hierarchy()) { + if (root.certificate.is_selfsigned() && root.certificate.is_valid()) { + // Collect the chain + std::vector descendants = hierarchy.collect_descendants(root.certificate); + bool has_proper_descendants = (descendants.size() > 0); + + for (auto& certificate : descendants) { + std::string responder_url = certificate.get_responder_url(); + + if (!responder_url.empty()) { + try { + auto certificate_hash_data = hierarchy.get_certificate_hash(certificate); + OCSPRequestData ocsp_request_data = {certificate_hash_data, responder_url}; + ocsp_request_data_list.push_back(ocsp_request_data); + } catch (const NoCertificateFound& e) { + EVLOG_error << "Could not find hash for certificate: " << certificate.get_common_name() + << " with error: " << e.what(); + } + } + } + + // If we have collected the descendants we can break + // else we can continue iterating for a proper root + if (has_proper_descendants) { + break; + } } + } - return true; - }); response.ocsp_request_data_list = ocsp_request_data_list; } catch (const CertificateLoadException& e) { EVLOG_error << "Could not get ocsp cache, certificate load failure: " << e.what(); + } catch (const NoCertificateFound& e) { + EVLOG_error << "Could not find proper root: " << e.what(); } return response; @@ -843,7 +865,7 @@ GetKeyPairResult EvseSecurity::get_key_pair_internal(LeafCertificateType certifi // choose appropriate cert (valid_from / valid_to) try { - auto leaf_certificates = std::move(get_leaf_certificates(cert_dir)); + auto leaf_certificates = X509CertificateBundle(cert_dir, EncodingFormat::PEM); if (leaf_certificates.empty()) { EVLOG_warning << "Could not find any key pair";