xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
35968caeeSMarri Devender Rao #pragma once
45968caeeSMarri Devender Rao 
5*d7857201SEd Tanous #include "bmcweb_config.h"
6*d7857201SEd Tanous 
73ccb3adbSEd Tanous #include "app.hpp"
83ccb3adbSEd Tanous #include "async_resp.hpp"
9*d7857201SEd Tanous #include "dbus_singleton.hpp"
107a1dbc48SGeorge Liu #include "dbus_utility.hpp"
11*d7857201SEd Tanous #include "error_messages.hpp"
121aa0c2b8SEd Tanous #include "http/parsing.hpp"
13*d7857201SEd Tanous #include "http_request.hpp"
143ccb3adbSEd Tanous #include "http_response.hpp"
15*d7857201SEd Tanous #include "logging.hpp"
16*d7857201SEd Tanous #include "privileges.hpp"
173ccb3adbSEd Tanous #include "query.hpp"
183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
19*d7857201SEd Tanous #include "utility.hpp"
209b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp"
213ccb3adbSEd Tanous #include "utils/json_utils.hpp"
223ccb3adbSEd Tanous #include "utils/time_utils.hpp"
239b12d1f9SKrzysztof Grobelny 
24*d7857201SEd Tanous // NOLINTNEXTLINE(modernize-deprecated-headers)
25*d7857201SEd Tanous #include <stdlib.h>
26*d7857201SEd Tanous #include <systemd/sd-bus.h>
27*d7857201SEd Tanous 
28*d7857201SEd Tanous #include <boost/asio/error.hpp>
29*d7857201SEd Tanous #include <boost/asio/steady_timer.hpp>
30*d7857201SEd Tanous #include <boost/beast/http/field.hpp>
31*d7857201SEd Tanous #include <boost/beast/http/status.hpp>
32*d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
33*d7857201SEd Tanous #include <boost/system/result.hpp>
34ef4c65b7SEd Tanous #include <boost/url/format.hpp>
35*d7857201SEd Tanous #include <boost/url/parse.hpp>
36*d7857201SEd Tanous #include <boost/url/url.hpp>
37*d7857201SEd Tanous #include <nlohmann/json.hpp>
383ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
39*d7857201SEd Tanous #include <sdbusplus/message.hpp>
40*d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
419b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
421214b7e7SGunnar Mills 
437a1dbc48SGeorge Liu #include <array>
44*d7857201SEd Tanous #include <chrono>
45*d7857201SEd Tanous #include <cstddef>
46*d7857201SEd Tanous #include <cstdint>
47*d7857201SEd Tanous #include <cstdlib>
48*d7857201SEd Tanous #include <filesystem>
49*d7857201SEd Tanous #include <format>
50*d7857201SEd Tanous #include <fstream>
51*d7857201SEd Tanous #include <functional>
52*d7857201SEd Tanous #include <iterator>
533ccb3adbSEd Tanous #include <memory>
54*d7857201SEd Tanous #include <optional>
55*d7857201SEd Tanous #include <string>
567a1dbc48SGeorge Liu #include <string_view>
57*d7857201SEd Tanous #include <system_error>
58*d7857201SEd Tanous #include <utility>
59*d7857201SEd Tanous #include <vector>
607a1dbc48SGeorge Liu 
615968caeeSMarri Devender Rao namespace redfish
625968caeeSMarri Devender Rao {
635968caeeSMarri Devender Rao namespace certs
645968caeeSMarri Devender Rao {
6589492a15SPatrick Williams constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install";
6689492a15SPatrick Williams constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
6789492a15SPatrick Williams constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
6889492a15SPatrick Williams constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
6989492a15SPatrick Williams constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties";
7089492a15SPatrick Williams constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
7189492a15SPatrick Williams constexpr const char* httpsServiceName =
7237cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
7389492a15SPatrick Williams constexpr const char* ldapServiceName =
7437cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
7589492a15SPatrick Williams constexpr const char* authorityServiceName =
76b2254ccdSMichal Orzel     "xyz.openbmc_project.Certs.Manager.Authority.Truststore";
7789492a15SPatrick Williams constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs";
7889492a15SPatrick Williams constexpr const char* httpsObjectPath =
79c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
8089492a15SPatrick Williams constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
8189492a15SPatrick Williams constexpr const char* authorityObjectPath =
82b2254ccdSMichal Orzel     "/xyz/openbmc_project/certs/authority/truststore";
835968caeeSMarri Devender Rao } // namespace certs
845968caeeSMarri Devender Rao 
855968caeeSMarri Devender Rao /**
865968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
875968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
885968caeeSMarri Devender Rao  * are installed.
895968caeeSMarri Devender Rao  */
907e860f15SJohn Edward Broadbent 
918d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
928d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9358eb238fSKowalski, Kamil     const crow::Request& req)
9458eb238fSKowalski, Kamil {
951aa0c2b8SEd Tanous     nlohmann::json reqJson;
961aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, reqJson);
971aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
9858eb238fSKowalski, Kamil     {
9958eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
10033c6b580SEd Tanous         return req.body();
10158eb238fSKowalski, Kamil     }
10258eb238fSKowalski, Kamil 
10358eb238fSKowalski, Kamil     std::string certificate;
10458eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
10558eb238fSKowalski, Kamil 
106afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
107afc474aeSMyung Bae             req, asyncResp->res, //
108afc474aeSMyung Bae             "CertificateString", certificate, //
109afc474aeSMyung Bae             "CertificateType", certificateType //
110afc474aeSMyung Bae             ))
11158eb238fSKowalski, Kamil     {
11262598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
11358eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
114abb93cddSEd Tanous         return {};
11558eb238fSKowalski, Kamil     }
11658eb238fSKowalski, Kamil 
11758eb238fSKowalski, Kamil     if (*certificateType != "PEM")
11858eb238fSKowalski, Kamil     {
11958eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
12058eb238fSKowalski, Kamil                                          "CertificateType");
121abb93cddSEd Tanous         return {};
12258eb238fSKowalski, Kamil     }
12358eb238fSKowalski, Kamil 
12458eb238fSKowalski, Kamil     return certificate;
12558eb238fSKowalski, Kamil }
12658eb238fSKowalski, Kamil 
1275968caeeSMarri Devender Rao /**
1285968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
1295968caeeSMarri Devender Rao  */
1305968caeeSMarri Devender Rao class CertificateFile
1315968caeeSMarri Devender Rao {
1325968caeeSMarri Devender Rao   public:
1335968caeeSMarri Devender Rao     CertificateFile() = delete;
1345968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
1355968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
1365968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
1375968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
1384e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
1395968caeeSMarri Devender Rao     {
14072d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1415207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1425207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1435207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
144e662eae8SEd Tanous         if (tempDirectory != nullptr)
1455968caeeSMarri Devender Rao         {
1465968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1475968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
148bd79bce8SPatrick Williams             std::ofstream out(certificateFile,
149bd79bce8SPatrick Williams                               std::ofstream::out | std::ofstream::binary |
1505968caeeSMarri Devender Rao                                   std::ofstream::trunc);
1515968caeeSMarri Devender Rao             out << certString;
1525968caeeSMarri Devender Rao             out.close();
15362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Creating certificate file{}",
15462598e31SEd Tanous                              certificateFile.string());
1555968caeeSMarri Devender Rao         }
1565968caeeSMarri Devender Rao     }
1575968caeeSMarri Devender Rao     ~CertificateFile()
1585968caeeSMarri Devender Rao     {
1595968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1605968caeeSMarri Devender Rao         {
16162598e31SEd Tanous             BMCWEB_LOG_DEBUG("Removing certificate file{}",
16262598e31SEd Tanous                              certificateFile.string());
16323a21a1cSEd Tanous             std::error_code ec;
16423a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
16523a21a1cSEd Tanous             if (ec)
1665968caeeSMarri Devender Rao             {
16762598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to remove temp directory{}",
16862598e31SEd Tanous                                  certDirectory.string());
1695968caeeSMarri Devender Rao             }
1705968caeeSMarri Devender Rao         }
1715968caeeSMarri Devender Rao     }
1725968caeeSMarri Devender Rao     std::string getCertFilePath()
1735968caeeSMarri Devender Rao     {
1745968caeeSMarri Devender Rao         return certificateFile;
1755968caeeSMarri Devender Rao     }
1765968caeeSMarri Devender Rao 
1775968caeeSMarri Devender Rao   private:
1785968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1795968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1805968caeeSMarri Devender Rao };
1815968caeeSMarri Devender Rao 
1825968caeeSMarri Devender Rao /**
1834e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1845968caeeSMarri Devender Rao  *
1855968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1865968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1875968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1885968caeeSMarri Devender Rao  * @return None
1895968caeeSMarri Devender Rao  */
1904ff0f1f4SEd Tanous inline void updateCertIssuerOrSubject(nlohmann::json& out,
19126ccae32SEd Tanous                                       std::string_view value)
1925968caeeSMarri Devender Rao {
1935968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1945968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1955968caeeSMarri Devender Rao     while (i != value.end())
1965968caeeSMarri Devender Rao     {
1975968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1985968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1995968caeeSMarri Devender Rao         {
2006da47babSPatrick Williams             std::advance(i, 1);
2015968caeeSMarri Devender Rao         }
2025968caeeSMarri Devender Rao         if (i == value.end())
2035968caeeSMarri Devender Rao         {
2045968caeeSMarri Devender Rao             break;
2055968caeeSMarri Devender Rao         }
20626ccae32SEd Tanous         std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin));
2076da47babSPatrick Williams         std::advance(i, 1);
2085968caeeSMarri Devender Rao         tokenBegin = i;
2095968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
2105968caeeSMarri Devender Rao         {
2116da47babSPatrick Williams             std::advance(i, 1);
2125968caeeSMarri Devender Rao         }
21326ccae32SEd Tanous         std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin));
2145968caeeSMarri Devender Rao         if (key == "L")
2155968caeeSMarri Devender Rao         {
2165968caeeSMarri Devender Rao             out["City"] = val;
2175968caeeSMarri Devender Rao         }
2185968caeeSMarri Devender Rao         else if (key == "CN")
2195968caeeSMarri Devender Rao         {
2205968caeeSMarri Devender Rao             out["CommonName"] = val;
2215968caeeSMarri Devender Rao         }
2225968caeeSMarri Devender Rao         else if (key == "C")
2235968caeeSMarri Devender Rao         {
2245968caeeSMarri Devender Rao             out["Country"] = val;
2255968caeeSMarri Devender Rao         }
2265968caeeSMarri Devender Rao         else if (key == "O")
2275968caeeSMarri Devender Rao         {
2285968caeeSMarri Devender Rao             out["Organization"] = val;
2295968caeeSMarri Devender Rao         }
2305968caeeSMarri Devender Rao         else if (key == "OU")
2315968caeeSMarri Devender Rao         {
2325968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
2335968caeeSMarri Devender Rao         }
2345968caeeSMarri Devender Rao         else if (key == "ST")
2355968caeeSMarri Devender Rao         {
2365968caeeSMarri Devender Rao             out["State"] = val;
2375968caeeSMarri Devender Rao         }
2385968caeeSMarri Devender Rao         // skip comma character
2395968caeeSMarri Devender Rao         if (i != value.end())
2405968caeeSMarri Devender Rao         {
2416da47babSPatrick Williams             std::advance(i, 1);
2425968caeeSMarri Devender Rao         }
2435968caeeSMarri Devender Rao     }
2445968caeeSMarri Devender Rao }
2455968caeeSMarri Devender Rao 
2465968caeeSMarri Devender Rao /**
247d3f92ce7SJiaqing Zhao  * @brief Retrieve the installed certificate list
248d3f92ce7SJiaqing Zhao  *
249d3f92ce7SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
250d3f92ce7SJiaqing Zhao  * @param[in] basePath DBus object path to search
251d3f92ce7SJiaqing Zhao  * @param[in] listPtr Json pointer to the list in asyncResp
252d3f92ce7SJiaqing Zhao  * @param[in] countPtr Json pointer to the count in asyncResp
253d3f92ce7SJiaqing Zhao  * @return None
254d3f92ce7SJiaqing Zhao  */
2554ff0f1f4SEd Tanous inline void getCertificateList(
256bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
257bd79bce8SPatrick Williams     const std::string& basePath, const nlohmann::json::json_pointer& listPtr,
258d3f92ce7SJiaqing Zhao     const nlohmann::json::json_pointer& countPtr)
259d3f92ce7SJiaqing Zhao {
2607a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2617a1dbc48SGeorge Liu         certs::certPropIntf};
2627a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
2637a1dbc48SGeorge Liu         basePath, 0, interfaces,
264d3f92ce7SJiaqing Zhao         [asyncResp, listPtr, countPtr](
2657a1dbc48SGeorge Liu             const boost::system::error_code& ec,
266d3f92ce7SJiaqing Zhao             const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
267d3f92ce7SJiaqing Zhao             if (ec)
268d3f92ce7SJiaqing Zhao             {
26962598e31SEd Tanous                 BMCWEB_LOG_ERROR("Certificate collection query failed: {}", ec);
270d3f92ce7SJiaqing Zhao                 messages::internalError(asyncResp->res);
271d3f92ce7SJiaqing Zhao                 return;
272d3f92ce7SJiaqing Zhao             }
273d3f92ce7SJiaqing Zhao 
274d3f92ce7SJiaqing Zhao             nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
275d3f92ce7SJiaqing Zhao             links = nlohmann::json::array();
276d3f92ce7SJiaqing Zhao             for (const auto& certPath : certPaths)
277d3f92ce7SJiaqing Zhao             {
278d3f92ce7SJiaqing Zhao                 sdbusplus::message::object_path objPath(certPath);
279d3f92ce7SJiaqing Zhao                 std::string certId = objPath.filename();
280d3f92ce7SJiaqing Zhao                 if (certId.empty())
281d3f92ce7SJiaqing Zhao                 {
282bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR("Invalid certificate objPath {}",
283bd79bce8SPatrick Williams                                      certPath);
284d3f92ce7SJiaqing Zhao                     continue;
285d3f92ce7SJiaqing Zhao                 }
286d3f92ce7SJiaqing Zhao 
287d3f92ce7SJiaqing Zhao                 boost::urls::url certURL;
288d3f92ce7SJiaqing Zhao                 if (objPath.parent_path() == certs::httpsObjectPath)
289d3f92ce7SJiaqing Zhao                 {
290ef4c65b7SEd Tanous                     certURL = boost::urls::format(
291253f11b8SEd Tanous                         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
292253f11b8SEd Tanous                         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
293d3f92ce7SJiaqing Zhao                 }
294d3f92ce7SJiaqing Zhao                 else if (objPath.parent_path() == certs::ldapObjectPath)
295d3f92ce7SJiaqing Zhao                 {
296ef4c65b7SEd Tanous                     certURL = boost::urls::format(
297bd79bce8SPatrick Williams                         "/redfish/v1/AccountService/LDAP/Certificates/{}",
298bd79bce8SPatrick Williams                         certId);
299d3f92ce7SJiaqing Zhao                 }
300d3f92ce7SJiaqing Zhao                 else if (objPath.parent_path() == certs::authorityObjectPath)
301d3f92ce7SJiaqing Zhao                 {
302ef4c65b7SEd Tanous                     certURL = boost::urls::format(
303253f11b8SEd Tanous                         "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
304253f11b8SEd Tanous                         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
305d3f92ce7SJiaqing Zhao                 }
306d3f92ce7SJiaqing Zhao                 else
307d3f92ce7SJiaqing Zhao                 {
308d3f92ce7SJiaqing Zhao                     continue;
309d3f92ce7SJiaqing Zhao                 }
310d3f92ce7SJiaqing Zhao 
311d3f92ce7SJiaqing Zhao                 nlohmann::json::object_t link;
312d3f92ce7SJiaqing Zhao                 link["@odata.id"] = certURL;
313d3f92ce7SJiaqing Zhao                 links.emplace_back(std::move(link));
314d3f92ce7SJiaqing Zhao             }
315d3f92ce7SJiaqing Zhao 
316d3f92ce7SJiaqing Zhao             asyncResp->res.jsonValue[countPtr] = links.size();
3177a1dbc48SGeorge Liu         });
318d3f92ce7SJiaqing Zhao }
319d3f92ce7SJiaqing Zhao 
320d3f92ce7SJiaqing Zhao /**
3215968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
3225968caeeSMarri Devender Rao  * message
3235968caeeSMarri Devender Rao  *
3245968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
3255968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
3265968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
3275968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
3285968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
3295968caeeSMarri Devender Rao  * @return None
3305968caeeSMarri Devender Rao  */
3314ff0f1f4SEd Tanous inline void getCertificateProperties(
3328d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
333e19e97e2SJiaqing Zhao     const std::string& objectPath, const std::string& service,
3341e312598SJiaqing Zhao     const std::string& certId, const boost::urls::url& certURL,
335e19e97e2SJiaqing Zhao     const std::string& name)
3365968caeeSMarri Devender Rao {
33762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}",
33862598e31SEd Tanous                      objectPath, certId, certURL);
339deae6a78SEd Tanous     dbus::utility::getAllProperties(
340deae6a78SEd Tanous         service, objectPath, certs::certPropIntf,
341b9d36b47SEd Tanous         [asyncResp, certURL, certId,
3425e7e2dc5SEd Tanous          name](const boost::system::error_code& ec,
343b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
3445968caeeSMarri Devender Rao             if (ec)
3455968caeeSMarri Devender Rao             {
34662598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
347bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Certificate",
348bd79bce8SPatrick Williams                                            certId);
3495968caeeSMarri Devender Rao                 return;
3505968caeeSMarri Devender Rao             }
3519b12d1f9SKrzysztof Grobelny 
3529b12d1f9SKrzysztof Grobelny             const std::string* certificateString = nullptr;
3539b12d1f9SKrzysztof Grobelny             const std::vector<std::string>* keyUsage = nullptr;
3549b12d1f9SKrzysztof Grobelny             const std::string* issuer = nullptr;
3559b12d1f9SKrzysztof Grobelny             const std::string* subject = nullptr;
3569b12d1f9SKrzysztof Grobelny             const uint64_t* validNotAfter = nullptr;
3579b12d1f9SKrzysztof Grobelny             const uint64_t* validNotBefore = nullptr;
3589b12d1f9SKrzysztof Grobelny 
3599b12d1f9SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
360bd79bce8SPatrick Williams                 dbus_utils::UnpackErrorPrinter(), properties,
361bd79bce8SPatrick Williams                 "CertificateString", certificateString, "KeyUsage", keyUsage,
362bd79bce8SPatrick Williams                 "Issuer", issuer, "Subject", subject, "ValidNotAfter",
363bd79bce8SPatrick Williams                 validNotAfter, "ValidNotBefore", validNotBefore);
3649b12d1f9SKrzysztof Grobelny 
3659b12d1f9SKrzysztof Grobelny             if (!success)
3669b12d1f9SKrzysztof Grobelny             {
3679b12d1f9SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
3689b12d1f9SKrzysztof Grobelny                 return;
3699b12d1f9SKrzysztof Grobelny             }
3709b12d1f9SKrzysztof Grobelny 
3711476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = certURL;
3721476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
3731476687dSEd Tanous                 "#Certificate.v1_0_0.Certificate";
374e19e97e2SJiaqing Zhao             asyncResp->res.jsonValue["Id"] = certId;
3751476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = name;
3761476687dSEd Tanous             asyncResp->res.jsonValue["Description"] = name;
3775968caeeSMarri Devender Rao             asyncResp->res.jsonValue["CertificateString"] = "";
3789b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
3799b12d1f9SKrzysztof Grobelny 
3809b12d1f9SKrzysztof Grobelny             if (certificateString != nullptr)
3815968caeeSMarri Devender Rao             {
382bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["CertificateString"] =
383bd79bce8SPatrick Williams                     *certificateString;
3845968caeeSMarri Devender Rao             }
3859b12d1f9SKrzysztof Grobelny 
3869b12d1f9SKrzysztof Grobelny             if (keyUsage != nullptr)
3875968caeeSMarri Devender Rao             {
3889b12d1f9SKrzysztof Grobelny                 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
3895968caeeSMarri Devender Rao             }
3909b12d1f9SKrzysztof Grobelny 
3919b12d1f9SKrzysztof Grobelny             if (issuer != nullptr)
3925968caeeSMarri Devender Rao             {
3939b12d1f9SKrzysztof Grobelny                 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
3949b12d1f9SKrzysztof Grobelny                                           *issuer);
3955968caeeSMarri Devender Rao             }
3969b12d1f9SKrzysztof Grobelny 
3979b12d1f9SKrzysztof Grobelny             if (subject != nullptr)
3985968caeeSMarri Devender Rao             {
3999b12d1f9SKrzysztof Grobelny                 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
4009b12d1f9SKrzysztof Grobelny                                           *subject);
4015968caeeSMarri Devender Rao             }
4029b12d1f9SKrzysztof Grobelny 
4039b12d1f9SKrzysztof Grobelny             if (validNotAfter != nullptr)
4045968caeeSMarri Devender Rao             {
4055968caeeSMarri Devender Rao                 asyncResp->res.jsonValue["ValidNotAfter"] =
4069b12d1f9SKrzysztof Grobelny                     redfish::time_utils::getDateTimeUint(*validNotAfter);
4075968caeeSMarri Devender Rao             }
4089b12d1f9SKrzysztof Grobelny 
4099b12d1f9SKrzysztof Grobelny             if (validNotBefore != nullptr)
4105968caeeSMarri Devender Rao             {
4115968caeeSMarri Devender Rao                 asyncResp->res.jsonValue["ValidNotBefore"] =
4129b12d1f9SKrzysztof Grobelny                     redfish::time_utils::getDateTimeUint(*validNotBefore);
4135968caeeSMarri Devender Rao             }
4149b12d1f9SKrzysztof Grobelny 
4151e312598SJiaqing Zhao             asyncResp->res.addHeader(
416d9f6c621SEd Tanous                 boost::beast::http::field::location,
417d9f6c621SEd Tanous                 std::string_view(certURL.data(), certURL.size()));
4189b12d1f9SKrzysztof Grobelny         });
4195968caeeSMarri Devender Rao }
4205968caeeSMarri Devender Rao 
4214ff0f1f4SEd Tanous inline void
4227a3a8f7aSJiaqing Zhao     deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4237a3a8f7aSJiaqing Zhao                       const std::string& service,
4247a3a8f7aSJiaqing Zhao                       const sdbusplus::message::object_path& objectPath)
4257a3a8f7aSJiaqing Zhao {
4267a3a8f7aSJiaqing Zhao     crow::connections::systemBus->async_method_call(
4277a3a8f7aSJiaqing Zhao         [asyncResp,
4285e7e2dc5SEd Tanous          id{objectPath.filename()}](const boost::system::error_code& ec) {
4297a3a8f7aSJiaqing Zhao             if (ec)
4307a3a8f7aSJiaqing Zhao             {
4317a3a8f7aSJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
4327a3a8f7aSJiaqing Zhao                 return;
4337a3a8f7aSJiaqing Zhao             }
43462598e31SEd Tanous             BMCWEB_LOG_INFO("Certificate deleted");
4357a3a8f7aSJiaqing Zhao             asyncResp->res.result(boost::beast::http::status::no_content);
4367a3a8f7aSJiaqing Zhao         },
4377a3a8f7aSJiaqing Zhao         service, objectPath, certs::objDeleteIntf, "Delete");
4387a3a8f7aSJiaqing Zhao }
4397a3a8f7aSJiaqing Zhao 
440828252d5SJiaqing Zhao inline void handleCertificateServiceGet(
441828252d5SJiaqing Zhao     App& app, const crow::Request& req,
442828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4435968caeeSMarri Devender Rao {
444828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
445828252d5SJiaqing Zhao     {
446828252d5SJiaqing Zhao         return;
447828252d5SJiaqing Zhao     }
448828252d5SJiaqing Zhao 
4493e72c202SNinad Palsule     if (req.session == nullptr)
4503e72c202SNinad Palsule     {
4513e72c202SNinad Palsule         messages::internalError(asyncResp->res);
4523e72c202SNinad Palsule         return;
4533e72c202SNinad Palsule     }
4543e72c202SNinad Palsule 
455828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
456828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
457828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
458828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
459828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
460828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
461828252d5SJiaqing Zhao         "Actions available to manage certificates";
462828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
463828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
464828252d5SJiaqing Zhao     // has permissions ConfigureManager
465828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
4663e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
467828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
468828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
469828252d5SJiaqing Zhao     {
470828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
471828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
472828252d5SJiaqing Zhao     }
473828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
474828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
475828252d5SJiaqing Zhao     replace["target"] =
476828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
477828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
478ad539545SPatrick Williams     allowed.emplace_back("PEM");
479828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
480828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
481828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
482828252d5SJiaqing Zhao }
483828252d5SJiaqing Zhao 
484828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
485828252d5SJiaqing Zhao     App& app, const crow::Request& req,
486828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
487828252d5SJiaqing Zhao {
488828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
489828252d5SJiaqing Zhao     {
490828252d5SJiaqing Zhao         return;
491828252d5SJiaqing Zhao     }
492828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
493828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
494828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
495828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
496828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
497828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
498828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
499828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
500828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
501828252d5SJiaqing Zhao 
502828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
503828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
504828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
505828252d5SJiaqing Zhao }
506828252d5SJiaqing Zhao 
50726d3b0fbSChandra Harkude inline void handleError(const std::string_view dbusErrorName,
50826d3b0fbSChandra Harkude                         const std::string& id, const std::string& certificate,
50926d3b0fbSChandra Harkude                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
51026d3b0fbSChandra Harkude {
51126d3b0fbSChandra Harkude     if (dbusErrorName == "org.freedesktop.DBus.Error.UnknownObject")
51226d3b0fbSChandra Harkude     {
51326d3b0fbSChandra Harkude         messages::resourceNotFound(asyncResp->res, "Certificate", id);
51426d3b0fbSChandra Harkude     }
51526d3b0fbSChandra Harkude     else if (dbusErrorName ==
51626d3b0fbSChandra Harkude              "xyz.openbmc_project.Certs.Error.InvalidCertificate")
51726d3b0fbSChandra Harkude     {
51826d3b0fbSChandra Harkude         messages::propertyValueIncorrect(asyncResp->res, "Certificate",
51926d3b0fbSChandra Harkude                                          certificate);
52026d3b0fbSChandra Harkude     }
52126d3b0fbSChandra Harkude     else
52226d3b0fbSChandra Harkude     {
52326d3b0fbSChandra Harkude         messages::internalError(asyncResp->res);
52426d3b0fbSChandra Harkude     }
52526d3b0fbSChandra Harkude }
52626d3b0fbSChandra Harkude 
527828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
528828252d5SJiaqing Zhao     App& app, const crow::Request& req,
529828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
530828252d5SJiaqing Zhao {
5313ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
53245ca1b86SEd Tanous     {
53345ca1b86SEd Tanous         return;
53445ca1b86SEd Tanous     }
5355968caeeSMarri Devender Rao     std::string certificate;
5367a31e336SEd Tanous     std::string certURI;
5375968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
5388d1b46d7Szhanghch05 
539afc474aeSMyung Bae     if (!json_util::readJsonAction( //
540afc474aeSMyung Bae             req, asyncResp->res, //
541afc474aeSMyung Bae             "CertificateString", certificate, //
542afc474aeSMyung Bae             "CertificateType", certificateType, //
543afc474aeSMyung Bae             "CertificateUri/@odata.id", certURI //
544afc474aeSMyung Bae             ))
5455968caeeSMarri Devender Rao     {
54662598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
5475968caeeSMarri Devender Rao         return;
5485968caeeSMarri Devender Rao     }
5495968caeeSMarri Devender Rao 
5505968caeeSMarri Devender Rao     if (!certificateType)
5515968caeeSMarri Devender Rao     {
5525968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
5535968caeeSMarri Devender Rao         return;
5545968caeeSMarri Devender Rao     }
5555968caeeSMarri Devender Rao     if (certificateType != "PEM")
5565968caeeSMarri Devender Rao     {
557828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
558828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5595968caeeSMarri Devender Rao         return;
5605968caeeSMarri Devender Rao     }
5615968caeeSMarri Devender Rao 
56262598e31SEd Tanous     BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI);
5635968caeeSMarri Devender Rao 
5646fd29553SEd Tanous     boost::system::result<boost::urls::url> parsedUrl =
56575b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
56675b63a2cSJiaqing Zhao     if (!parsedUrl)
5675968caeeSMarri Devender Rao     {
568828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
569828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
5705968caeeSMarri Devender Rao         return;
5715968caeeSMarri Devender Rao     }
57275b63a2cSJiaqing Zhao 
57375b63a2cSJiaqing Zhao     std::string id;
57475b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
5755968caeeSMarri Devender Rao     std::string name;
57637cce918SMarri Devender Rao     std::string service;
577828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
578828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
579828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5805968caeeSMarri Devender Rao     {
58189492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) /
58289492a15SPatrick Williams                      id;
5835968caeeSMarri Devender Rao         name = "HTTPS certificate";
58437cce918SMarri Devender Rao         service = certs::httpsServiceName;
58537cce918SMarri Devender Rao     }
58675b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
58775b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
58875b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
58937cce918SMarri Devender Rao     {
59089492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) /
59189492a15SPatrick Williams                      id;
59237cce918SMarri Devender Rao         name = "LDAP certificate";
59337cce918SMarri Devender Rao         service = certs::ldapServiceName;
5945968caeeSMarri Devender Rao     }
59575b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
59675b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
59775b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
598cfcd5f6bSMarri Devender Rao     {
59975b63a2cSJiaqing Zhao         objectPath =
600828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
601cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
602cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
603cfcd5f6bSMarri Devender Rao     }
6045968caeeSMarri Devender Rao     else
6055968caeeSMarri Devender Rao     {
606828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
607828252d5SJiaqing Zhao                                               "ReplaceCertificate");
6085968caeeSMarri Devender Rao         return;
6095968caeeSMarri Devender Rao     }
6105968caeeSMarri Devender Rao 
6115968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
6125968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
6135968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
61426d3b0fbSChandra Harkude         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, name,
61526d3b0fbSChandra Harkude          certificate](const boost::system::error_code& ec,
616d3e0859cSPatrick Williams                       sdbusplus::message_t& m) {
6175968caeeSMarri Devender Rao             if (ec)
6185968caeeSMarri Devender Rao             {
61962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
62026d3b0fbSChandra Harkude                 const sd_bus_error* dbusError = m.get_error();
62126d3b0fbSChandra Harkude                 if ((dbusError != nullptr) && (dbusError->name != nullptr))
62290d2d1e8SJiaqing Zhao                 {
62326d3b0fbSChandra Harkude                     handleError(dbusError->name, id, certificate, asyncResp);
6245968caeeSMarri Devender Rao                 }
62526d3b0fbSChandra Harkude                 else
62626d3b0fbSChandra Harkude                 {
62790d2d1e8SJiaqing Zhao                     messages::internalError(asyncResp->res);
62826d3b0fbSChandra Harkude                 }
62990d2d1e8SJiaqing Zhao                 return;
63090d2d1e8SJiaqing Zhao             }
631bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath, service, id, url,
632bd79bce8SPatrick Williams                                      name);
63362598e31SEd Tanous             BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
63462598e31SEd Tanous                              certFile->getCertFilePath());
6355968caeeSMarri Devender Rao         },
6365968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
6375968caeeSMarri Devender Rao         certFile->getCertFilePath());
638828252d5SJiaqing Zhao }
6395968caeeSMarri Devender Rao 
640cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
641828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
6425968caeeSMarri Devender Rao /**
643828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
644828252d5SJiaqing Zhao  *
645828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
6468ece0e45SEd Tanous  * @param[in] certURI Link to certificate collection URI
647828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
648828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
649828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
650828252d5SJiaqing Zhao  * @return None
6515968caeeSMarri Devender Rao  */
6524ff0f1f4SEd Tanous inline void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
653828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
654828252d5SJiaqing Zhao                    const std::string& certObjPath,
655828252d5SJiaqing Zhao                    const std::string& csrObjPath)
6565968caeeSMarri Devender Rao {
65762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}",
65862598e31SEd Tanous                      certObjPath, csrObjPath, service);
659828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
660bd79bce8SPatrick Williams         [asyncResp,
661bd79bce8SPatrick Williams          certURI](const boost::system::error_code& ec, const std::string& csr) {
662828252d5SJiaqing Zhao             if (ec)
663828252d5SJiaqing Zhao             {
66462598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
665828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
666828252d5SJiaqing Zhao                 return;
667828252d5SJiaqing Zhao             }
668828252d5SJiaqing Zhao             if (csr.empty())
669828252d5SJiaqing Zhao             {
67062598e31SEd Tanous                 BMCWEB_LOG_ERROR("CSR read is empty");
671828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
672828252d5SJiaqing Zhao                 return;
673828252d5SJiaqing Zhao             }
674828252d5SJiaqing Zhao             asyncResp->res.jsonValue["CSRString"] = csr;
675828252d5SJiaqing Zhao             asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
676828252d5SJiaqing Zhao                 certURI;
677828252d5SJiaqing Zhao         },
678828252d5SJiaqing Zhao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
679828252d5SJiaqing Zhao }
680828252d5SJiaqing Zhao 
681828252d5SJiaqing Zhao inline void
682828252d5SJiaqing Zhao     handleGenerateCSRAction(App& app, const crow::Request& req,
683828252d5SJiaqing Zhao                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
684828252d5SJiaqing Zhao {
6853ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
68645ca1b86SEd Tanous     {
68745ca1b86SEd Tanous         return;
68845ca1b86SEd Tanous     }
689828252d5SJiaqing Zhao     static const int rsaKeyBitLength = 2048;
6905968caeeSMarri Devender Rao 
691828252d5SJiaqing Zhao     // Required parameters
692828252d5SJiaqing Zhao     std::string city;
693828252d5SJiaqing Zhao     std::string commonName;
694828252d5SJiaqing Zhao     std::string country;
695828252d5SJiaqing Zhao     std::string organization;
696828252d5SJiaqing Zhao     std::string organizationalUnit;
697828252d5SJiaqing Zhao     std::string state;
6987a31e336SEd Tanous     std::string certURI;
699828252d5SJiaqing Zhao 
700828252d5SJiaqing Zhao     // Optional parameters
701828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optAlternativeNames =
702828252d5SJiaqing Zhao         std::vector<std::string>();
703828252d5SJiaqing Zhao     std::optional<std::string> optContactPerson = "";
704828252d5SJiaqing Zhao     std::optional<std::string> optChallengePassword = "";
705828252d5SJiaqing Zhao     std::optional<std::string> optEmail = "";
706828252d5SJiaqing Zhao     std::optional<std::string> optGivenName = "";
707828252d5SJiaqing Zhao     std::optional<std::string> optInitials = "";
708828252d5SJiaqing Zhao     std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
709828252d5SJiaqing Zhao     std::optional<std::string> optKeyCurveId = "secp384r1";
710828252d5SJiaqing Zhao     std::optional<std::string> optKeyPairAlgorithm = "EC";
711828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optKeyUsage =
712828252d5SJiaqing Zhao         std::vector<std::string>();
713828252d5SJiaqing Zhao     std::optional<std::string> optSurname = "";
714828252d5SJiaqing Zhao     std::optional<std::string> optUnstructuredName = "";
715afc474aeSMyung Bae     if (!json_util::readJsonAction( //
716afc474aeSMyung Bae             req, asyncResp->res, //
717afc474aeSMyung Bae             "AlternativeNames", optAlternativeNames, //
718afc474aeSMyung Bae             "CertificateCollection/@odata.id", certURI, //
719afc474aeSMyung Bae             "ChallengePassword", optChallengePassword, //
720afc474aeSMyung Bae             "City", city, //
721afc474aeSMyung Bae             "CommonName", commonName, //
722afc474aeSMyung Bae             "ContactPerson", optContactPerson, //
723afc474aeSMyung Bae             "Country", country, //
724afc474aeSMyung Bae             "Email", optEmail, //
725afc474aeSMyung Bae             "GivenName", optGivenName, //
726afc474aeSMyung Bae             "Initials", optInitials, //
727afc474aeSMyung Bae             "KeyBitLength", optKeyBitLength, //
728afc474aeSMyung Bae             "KeyCurveId", optKeyCurveId, //
729afc474aeSMyung Bae             "KeyPairAlgorithm", optKeyPairAlgorithm, //
730afc474aeSMyung Bae             "KeyUsage", optKeyUsage, //
731afc474aeSMyung Bae             "Organization", organization, //
732afc474aeSMyung Bae             "OrganizationalUnit", organizationalUnit, //
733afc474aeSMyung Bae             "State", state, //
734afc474aeSMyung Bae             "Surname", optSurname, //
735afc474aeSMyung Bae             "UnstructuredName", optUnstructuredName //
736afc474aeSMyung Bae             ))
737828252d5SJiaqing Zhao     {
738828252d5SJiaqing Zhao         return;
7395968caeeSMarri Devender Rao     }
7405968caeeSMarri Devender Rao 
741828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
742828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
743828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
744828252d5SJiaqing Zhao     // value
745828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
7465968caeeSMarri Devender Rao     {
747828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
748828252d5SJiaqing Zhao                                               "ChallengePassword");
749828252d5SJiaqing Zhao         return;
750828252d5SJiaqing Zhao     }
751828252d5SJiaqing Zhao 
752828252d5SJiaqing Zhao     std::string objectPath;
753828252d5SJiaqing Zhao     std::string service;
754253f11b8SEd Tanous     if (certURI.starts_with(std::format(
755253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
756253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
757828252d5SJiaqing Zhao     {
758828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
759828252d5SJiaqing Zhao         service = certs::httpsServiceName;
760828252d5SJiaqing Zhao     }
761828252d5SJiaqing Zhao     else if (certURI.starts_with(
762828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
763828252d5SJiaqing Zhao     {
764828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
765828252d5SJiaqing Zhao         service = certs::ldapServiceName;
766828252d5SJiaqing Zhao     }
767828252d5SJiaqing Zhao     else
768828252d5SJiaqing Zhao     {
769828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
770828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
771828252d5SJiaqing Zhao         return;
772828252d5SJiaqing Zhao     }
773828252d5SJiaqing Zhao 
774828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
775828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
776828252d5SJiaqing Zhao     {
777828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
778828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
779828252d5SJiaqing Zhao         return;
780828252d5SJiaqing Zhao     }
781828252d5SJiaqing Zhao 
782828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
783828252d5SJiaqing Zhao     // time consumed in generating private key
784828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
785828252d5SJiaqing Zhao     {
786e2616cc5SEd Tanous         messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
787e2616cc5SEd Tanous                                          "KeyBitLength");
788828252d5SJiaqing Zhao         return;
789828252d5SJiaqing Zhao     }
790828252d5SJiaqing Zhao 
791828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
792253f11b8SEd Tanous     if (certURI.starts_with(std::format(
793253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
794253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
795828252d5SJiaqing Zhao     {
796828252d5SJiaqing Zhao         if (optKeyUsage->empty())
797828252d5SJiaqing Zhao         {
798b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ServerAuthentication");
799828252d5SJiaqing Zhao         }
800828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
801828252d5SJiaqing Zhao         {
802828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
803828252d5SJiaqing Zhao             {
804828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
805828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
806828252d5SJiaqing Zhao                 return;
807828252d5SJiaqing Zhao             }
808828252d5SJiaqing Zhao         }
809828252d5SJiaqing Zhao         else
810828252d5SJiaqing Zhao         {
811828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
812828252d5SJiaqing Zhao                                                   "GenerateCSR");
813828252d5SJiaqing Zhao             return;
814828252d5SJiaqing Zhao         }
815828252d5SJiaqing Zhao     }
816828252d5SJiaqing Zhao     else if (certURI.starts_with(
817828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
818828252d5SJiaqing Zhao     {
819828252d5SJiaqing Zhao         if (optKeyUsage->empty())
820828252d5SJiaqing Zhao         {
821b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ClientAuthentication");
822828252d5SJiaqing Zhao         }
823828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
824828252d5SJiaqing Zhao         {
825828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
826828252d5SJiaqing Zhao             {
827828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
828828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
829828252d5SJiaqing Zhao                 return;
830828252d5SJiaqing Zhao             }
831828252d5SJiaqing Zhao         }
832828252d5SJiaqing Zhao         else
833828252d5SJiaqing Zhao         {
834828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
835828252d5SJiaqing Zhao                                                   "GenerateCSR");
836828252d5SJiaqing Zhao             return;
837828252d5SJiaqing Zhao         }
838828252d5SJiaqing Zhao     }
839828252d5SJiaqing Zhao 
840828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
841828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
842828252d5SJiaqing Zhao     static const int timeOut = 10;
843828252d5SJiaqing Zhao     if (csrMatcher)
844828252d5SJiaqing Zhao     {
845828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
846828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
847828252d5SJiaqing Zhao         return;
848828252d5SJiaqing Zhao     }
849828252d5SJiaqing Zhao 
8508e8245dbSEd Tanous     if (req.ioService == nullptr)
8518e8245dbSEd Tanous     {
8528e8245dbSEd Tanous         messages::internalError(asyncResp->res);
8538e8245dbSEd Tanous         return;
8548e8245dbSEd Tanous     }
8558e8245dbSEd Tanous 
856828252d5SJiaqing Zhao     // Make this static so it survives outside this method
857828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
858828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
859828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
860828252d5SJiaqing Zhao         csrMatcher = nullptr;
861828252d5SJiaqing Zhao         if (ec)
862828252d5SJiaqing Zhao         {
863828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
864828252d5SJiaqing Zhao             // before completion.
865828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
866828252d5SJiaqing Zhao             {
86762598e31SEd Tanous                 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
868828252d5SJiaqing Zhao             }
869828252d5SJiaqing Zhao             return;
870828252d5SJiaqing Zhao         }
87162598e31SEd Tanous         BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
872828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
873828252d5SJiaqing Zhao     });
874828252d5SJiaqing Zhao 
875828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
87662598e31SEd Tanous     BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
877828252d5SJiaqing Zhao     std::string match("type='signal',"
878828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
879828252d5SJiaqing Zhao                       "path='" +
880828252d5SJiaqing Zhao                       objectPath +
881828252d5SJiaqing Zhao                       "',"
882828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
883828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
884828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
885828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
886828252d5SJiaqing Zhao             timeout.cancel();
887828252d5SJiaqing Zhao             if (m.is_method_error())
888828252d5SJiaqing Zhao             {
88962598e31SEd Tanous                 BMCWEB_LOG_ERROR("Dbus method error!!!");
890828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
891828252d5SJiaqing Zhao                 return;
892828252d5SJiaqing Zhao             }
893828252d5SJiaqing Zhao 
89480f79a40SMichael Shen             dbus::utility::DBusInterfacesMap interfacesProperties;
895828252d5SJiaqing Zhao 
896828252d5SJiaqing Zhao             sdbusplus::message::object_path csrObjectPath;
897828252d5SJiaqing Zhao             m.read(csrObjectPath, interfacesProperties);
89862598e31SEd Tanous             BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
899828252d5SJiaqing Zhao             for (const auto& interface : interfacesProperties)
900828252d5SJiaqing Zhao             {
901828252d5SJiaqing Zhao                 if (interface.first == "xyz.openbmc_project.Certs.CSR")
902828252d5SJiaqing Zhao                 {
903828252d5SJiaqing Zhao                     getCSR(asyncResp, certURI, service, objectPath,
904828252d5SJiaqing Zhao                            csrObjectPath.str);
905828252d5SJiaqing Zhao                     break;
906828252d5SJiaqing Zhao                 }
907828252d5SJiaqing Zhao             }
908828252d5SJiaqing Zhao         });
909828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
9105e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec, const std::string&) {
911828252d5SJiaqing Zhao             if (ec)
912828252d5SJiaqing Zhao             {
91362598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
914828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
915828252d5SJiaqing Zhao                 return;
916828252d5SJiaqing Zhao             }
917828252d5SJiaqing Zhao         },
918828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
919828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
920828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
921828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
922828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
923828252d5SJiaqing Zhao         *optUnstructuredName);
924828252d5SJiaqing Zhao }
925828252d5SJiaqing Zhao 
926828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
927828252d5SJiaqing Zhao {
928828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
929828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
930002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
931828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
932828252d5SJiaqing Zhao 
933828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
934828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
935828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
936828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
937828252d5SJiaqing Zhao 
938828252d5SJiaqing Zhao     BMCWEB_ROUTE(
939828252d5SJiaqing Zhao         app,
940828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
941828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
942828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
943828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
944828252d5SJiaqing Zhao 
945828252d5SJiaqing Zhao     BMCWEB_ROUTE(
946828252d5SJiaqing Zhao         app,
947828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
948828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
949828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
950828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
951828252d5SJiaqing Zhao } // requestRoutesCertificateService
952828252d5SJiaqing Zhao 
953828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
954828252d5SJiaqing Zhao     App& app, const crow::Request& req,
955253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
956253f11b8SEd Tanous     const std::string& managerId)
957828252d5SJiaqing Zhao {
9583ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
95945ca1b86SEd Tanous     {
96045ca1b86SEd Tanous         return;
96145ca1b86SEd Tanous     }
9621476687dSEd Tanous 
963253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
964253f11b8SEd Tanous     {
965253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
966253f11b8SEd Tanous         return;
967253f11b8SEd Tanous     }
968253f11b8SEd Tanous 
969253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
970253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
971253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME);
9721476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
9731476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
9741476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
9751476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
9761476687dSEd Tanous         "A Collection of HTTPS certificate instances";
9778d1b46d7Szhanghch05 
978d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
979d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
980d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
981828252d5SJiaqing Zhao }
9825968caeeSMarri Devender Rao 
983828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
984828252d5SJiaqing Zhao     App& app, const crow::Request& req,
985253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
986253f11b8SEd Tanous     const std::string& managerId)
987828252d5SJiaqing Zhao {
9883ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
98945ca1b86SEd Tanous     {
99045ca1b86SEd Tanous         return;
99145ca1b86SEd Tanous     }
992253f11b8SEd Tanous 
993253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
994253f11b8SEd Tanous     {
995253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
996253f11b8SEd Tanous         return;
997253f11b8SEd Tanous     }
998253f11b8SEd Tanous 
99962598e31SEd Tanous     BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
10008d1b46d7Szhanghch05 
10011476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
10021476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
10035968caeeSMarri Devender Rao 
1004b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
100558eb238fSKowalski, Kamil 
1006b2896149SEd Tanous     if (certHttpBody.empty())
100758eb238fSKowalski, Kamil     {
100862598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1009a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
101058eb238fSKowalski, Kamil         return;
101158eb238fSKowalski, Kamil     }
101258eb238fSKowalski, Kamil 
10135968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
1014b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
10155968caeeSMarri Devender Rao 
10165968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
10175e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1018656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
10195968caeeSMarri Devender Rao             if (ec)
10205968caeeSMarri Devender Rao             {
102162598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
10225968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
10235968caeeSMarri Devender Rao                 return;
10245968caeeSMarri Devender Rao             }
1025717b9802SJiaqing Zhao 
1026717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
1027717b9802SJiaqing Zhao             std::string certId = path.filename();
1028ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
1029253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
1030253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1031bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath,
1032bd79bce8SPatrick Williams                                      certs::httpsServiceName, certId, certURL,
1033bd79bce8SPatrick Williams                                      "HTTPS Certificate");
103462598e31SEd Tanous             BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
103562598e31SEd Tanous                              certFile->getCertFilePath());
10365968caeeSMarri Devender Rao         },
1037828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
1038828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1039828252d5SJiaqing Zhao }
10405968caeeSMarri Devender Rao 
1041828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
1042828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1043253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1044253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
10457e860f15SJohn Edward Broadbent {
10463ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
104745ca1b86SEd Tanous     {
104845ca1b86SEd Tanous         return;
104945ca1b86SEd Tanous     }
10507e860f15SJohn Edward Broadbent 
1051253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1052253f11b8SEd Tanous     {
1053253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1054253f11b8SEd Tanous         return;
1055253f11b8SEd Tanous     }
1056253f11b8SEd Tanous 
1057253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId);
1058ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1059253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
1060253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1061828252d5SJiaqing Zhao     std::string objPath =
1062253f11b8SEd Tanous         sdbusplus::message::object_path(certs::httpsObjectPath) / certId;
1063253f11b8SEd Tanous     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName,
1064253f11b8SEd Tanous                              certId, certURL, "HTTPS Certificate");
10657e860f15SJohn Edward Broadbent }
106637cce918SMarri Devender Rao 
1067828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
106837cce918SMarri Devender Rao {
1069253f11b8SEd Tanous     BMCWEB_ROUTE(
1070253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
1071ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
1072828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1073828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
1074828252d5SJiaqing Zhao 
1075253f11b8SEd Tanous     BMCWEB_ROUTE(
1076253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
1077828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1078828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1079828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
1080828252d5SJiaqing Zhao 
1081828252d5SJiaqing Zhao     BMCWEB_ROUTE(
1082828252d5SJiaqing Zhao         app,
1083253f11b8SEd Tanous         "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/")
1084828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1085002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1086828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
1087828252d5SJiaqing Zhao }
1088828252d5SJiaqing Zhao 
1089828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
1090828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1091828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1092828252d5SJiaqing Zhao {
10933ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
109445ca1b86SEd Tanous     {
109545ca1b86SEd Tanous         return;
109645ca1b86SEd Tanous     }
10971476687dSEd Tanous 
10981476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
10991476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
11001476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11011476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
11021476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
11031476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
11041476687dSEd Tanous         "A Collection of LDAP certificate instances";
11058d1b46d7Szhanghch05 
1106d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
1107d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1108d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1109828252d5SJiaqing Zhao }
111037cce918SMarri Devender Rao 
1111828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1112828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1113828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1114828252d5SJiaqing Zhao {
11153ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111645ca1b86SEd Tanous     {
111745ca1b86SEd Tanous         return;
111845ca1b86SEd Tanous     }
1119b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
112058eb238fSKowalski, Kamil 
1121b2896149SEd Tanous     if (certHttpBody.empty())
112258eb238fSKowalski, Kamil     {
112362598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1124a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
112558eb238fSKowalski, Kamil         return;
112658eb238fSKowalski, Kamil     }
112758eb238fSKowalski, Kamil 
112858eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
1129b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
113058eb238fSKowalski, Kamil 
113137cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
11325e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1133656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
113437cce918SMarri Devender Rao             if (ec)
113537cce918SMarri Devender Rao             {
113662598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
113737cce918SMarri Devender Rao                 messages::internalError(asyncResp->res);
113837cce918SMarri Devender Rao                 return;
113937cce918SMarri Devender Rao             }
1140717b9802SJiaqing Zhao 
1141717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
1142717b9802SJiaqing Zhao             std::string certId = path.filename();
1143ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
1144ef4c65b7SEd Tanous                 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
1145bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath,
1146bd79bce8SPatrick Williams                                      certs::ldapServiceName, certId, certURL,
1147bd79bce8SPatrick Williams                                      "LDAP Certificate");
114862598e31SEd Tanous             BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
114962598e31SEd Tanous                              certFile->getCertFilePath());
115037cce918SMarri Devender Rao         },
1151828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1152828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1153828252d5SJiaqing Zhao }
115437cce918SMarri Devender Rao 
1155828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1156828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1157828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
115837cce918SMarri Devender Rao {
11593ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
116045ca1b86SEd Tanous     {
116145ca1b86SEd Tanous         return;
116245ca1b86SEd Tanous     }
1163717b9802SJiaqing Zhao 
116462598e31SEd Tanous     BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
1165ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1166ef4c65b7SEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
1167717b9802SJiaqing Zhao     std::string objPath =
1168717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1169717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1170717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1171828252d5SJiaqing Zhao }
1172828252d5SJiaqing Zhao 
117399612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
117499612247SJiaqing Zhao     App& app, const crow::Request& req,
117599612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
117699612247SJiaqing Zhao {
117799612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
117899612247SJiaqing Zhao     {
117999612247SJiaqing Zhao         return;
118099612247SJiaqing Zhao     }
118199612247SJiaqing Zhao 
118262598e31SEd Tanous     BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
118399612247SJiaqing Zhao     std::string objPath =
118499612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
118599612247SJiaqing Zhao 
118699612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
118799612247SJiaqing Zhao }
118899612247SJiaqing Zhao 
1189828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1190cfcd5f6bSMarri Devender Rao {
1191828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1192828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1193828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1194828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1195828252d5SJiaqing Zhao 
1196828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1197828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1198828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1199828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1200828252d5SJiaqing Zhao 
1201828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1202ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1203002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1204828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
120599612247SJiaqing Zhao 
120699612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
120799612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
120899612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
120999612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1210828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1211828252d5SJiaqing Zhao 
1212828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1213828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1214253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1215253f11b8SEd Tanous     const std::string& managerId)
1216828252d5SJiaqing Zhao {
12173ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
121845ca1b86SEd Tanous     {
121945ca1b86SEd Tanous         return;
122045ca1b86SEd Tanous     }
12211476687dSEd Tanous 
1222253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1223253f11b8SEd Tanous     {
1224253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1225253f11b8SEd Tanous         return;
1226253f11b8SEd Tanous     }
1227253f11b8SEd Tanous 
12281476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
1229253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/",
1230253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
12311476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
12321476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1233002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
12341476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
12351476687dSEd Tanous         "A Collection of TrustStore certificate instances";
12368d1b46d7Szhanghch05 
1237d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1238d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1239d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1240828252d5SJiaqing Zhao }
1241cfcd5f6bSMarri Devender Rao 
1242828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1243828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1244253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1245253f11b8SEd Tanous     const std::string& managerId)
1246828252d5SJiaqing Zhao {
12473ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
124845ca1b86SEd Tanous     {
124945ca1b86SEd Tanous         return;
125045ca1b86SEd Tanous     }
1251253f11b8SEd Tanous 
1252253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1253253f11b8SEd Tanous     {
1254253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1255253f11b8SEd Tanous         return;
1256253f11b8SEd Tanous     }
1257253f11b8SEd Tanous 
1258b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
1259a08752f5SZbigniew Kurzynski 
1260b2896149SEd Tanous     if (certHttpBody.empty())
1261a08752f5SZbigniew Kurzynski     {
126262598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1263a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1264a08752f5SZbigniew Kurzynski         return;
1265a08752f5SZbigniew Kurzynski     }
1266a08752f5SZbigniew Kurzynski 
1267a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1268b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
1269cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
12705e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1271656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1272cfcd5f6bSMarri Devender Rao             if (ec)
1273cfcd5f6bSMarri Devender Rao             {
127462598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
1275cfcd5f6bSMarri Devender Rao                 messages::internalError(asyncResp->res);
1276cfcd5f6bSMarri Devender Rao                 return;
1277cfcd5f6bSMarri Devender Rao             }
1278656ec7e3SZbigniew Kurzynski 
1279717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
1280717b9802SJiaqing Zhao             std::string certId = path.filename();
1281ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
1282253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1283253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1284717b9802SJiaqing Zhao             getCertificateProperties(asyncResp, objectPath,
1285bd79bce8SPatrick Williams                                      certs::authorityServiceName, certId,
1286bd79bce8SPatrick Williams                                      certURL, "TrustStore Certificate");
128762598e31SEd Tanous             BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
128862598e31SEd Tanous                              certFile->getCertFilePath());
1289cfcd5f6bSMarri Devender Rao         },
1290cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
12910fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1292828252d5SJiaqing Zhao }
1293cfcd5f6bSMarri Devender Rao 
1294828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1295828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1296253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1297253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1298cfcd5f6bSMarri Devender Rao {
12993ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
130045ca1b86SEd Tanous     {
130145ca1b86SEd Tanous         return;
130245ca1b86SEd Tanous     }
1303717b9802SJiaqing Zhao 
1304253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1305253f11b8SEd Tanous     {
1306253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1307253f11b8SEd Tanous         return;
1308253f11b8SEd Tanous     }
1309253f11b8SEd Tanous 
1310253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId);
1311ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1312253f11b8SEd Tanous         "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1313253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1314717b9802SJiaqing Zhao     std::string objPath =
1315253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
1316828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1317253f11b8SEd Tanous                              certId, certURL, "TrustStore Certificate");
1318828252d5SJiaqing Zhao }
131907a60299SZbigniew Kurzynski 
1320828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1321828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1322253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1323253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1324828252d5SJiaqing Zhao {
13253ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
132645ca1b86SEd Tanous     {
132745ca1b86SEd Tanous         return;
132845ca1b86SEd Tanous     }
132907a60299SZbigniew Kurzynski 
1330253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1331253f11b8SEd Tanous     {
1332253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1333253f11b8SEd Tanous         return;
1334253f11b8SEd Tanous     }
1335253f11b8SEd Tanous 
1336253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId);
1337717b9802SJiaqing Zhao     std::string objPath =
1338253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
133907a60299SZbigniew Kurzynski 
13407a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1341828252d5SJiaqing Zhao }
1342828252d5SJiaqing Zhao 
1343828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1344828252d5SJiaqing Zhao {
1345253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1346828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1347828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1348828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1349828252d5SJiaqing Zhao 
1350253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1351828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1352828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1353828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1354828252d5SJiaqing Zhao 
1355253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1356253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1357828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1358828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1359828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1360828252d5SJiaqing Zhao 
1361253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1362253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1363828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1364828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1365828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
13667e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
13675968caeeSMarri Devender Rao } // namespace redfish
1368