xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 1d8782e7a0ed98878bd82c24c7cf830bb8cdc46f)
15968caeeSMarri Devender Rao #pragma once
25968caeeSMarri Devender Rao 
37e860f15SJohn Edward Broadbent #include <app.hpp>
4e6604b11SIwona Klimaszewska #include <boost/convert.hpp>
5e6604b11SIwona Klimaszewska #include <boost/convert/strtol.hpp>
6ed398213SEd Tanous #include <registries/privilege_registry.hpp>
71214b7e7SGunnar Mills 
85968caeeSMarri Devender Rao #include <variant>
95968caeeSMarri Devender Rao namespace redfish
105968caeeSMarri Devender Rao {
115968caeeSMarri Devender Rao namespace certs
125968caeeSMarri Devender Rao {
135968caeeSMarri Devender Rao constexpr char const* httpsObjectPath =
145968caeeSMarri Devender Rao     "/xyz/openbmc_project/certs/server/https";
155968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
165968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
1707a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
185968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
195968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
205968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
2137cce918SMarri Devender Rao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
2237cce918SMarri Devender Rao constexpr char const* httpsServiceName =
2337cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
2437cce918SMarri Devender Rao constexpr char const* ldapServiceName =
2537cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
26cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
27cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
28cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
29cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
305968caeeSMarri Devender Rao } // namespace certs
315968caeeSMarri Devender Rao 
325968caeeSMarri Devender Rao /**
335968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
345968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
355968caeeSMarri Devender Rao  * are installed.
365968caeeSMarri Devender Rao  */
377e860f15SJohn Edward Broadbent 
385968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate
394e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish
405968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF
415968caeeSMarri Devender Rao // publish Privilege details for certificate service
425968caeeSMarri Devender Rao 
437e860f15SJohn Edward Broadbent inline void requestRoutesCertificateService(App& app)
445968caeeSMarri Devender Rao {
457e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
46ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateService)
4772048780SAbhishek Patel         .methods(
4872048780SAbhishek Patel             boost::beast::http::verb::
4972048780SAbhishek Patel                 get)([](const crow::Request& req,
507e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
518d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
527e860f15SJohn Edward Broadbent                 {"@odata.type",
537e860f15SJohn Edward Broadbent                  "#CertificateService.v1_0_0.CertificateService"},
545968caeeSMarri Devender Rao                 {"@odata.id", "/redfish/v1/CertificateService"},
555968caeeSMarri Devender Rao                 {"Id", "CertificateService"},
565968caeeSMarri Devender Rao                 {"Name", "Certificate Service"},
5772048780SAbhishek Patel                 {"Description", "Actions available to manage certificates"}};
5872048780SAbhishek Patel             // /redfish/v1/CertificateService/CertificateLocations is something
5972048780SAbhishek Patel             // only ConfigureManager can access then only display when the user
6072048780SAbhishek Patel             // has permissions ConfigureManager
6172048780SAbhishek Patel             Privileges effectiveUserPrivileges =
6272048780SAbhishek Patel                 redfish::getUserPrivileges(req.userRole);
6372048780SAbhishek Patel             if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
6472048780SAbhishek Patel                                                  effectiveUserPrivileges))
6572048780SAbhishek Patel             {
668d1b46d7Szhanghch05                 asyncResp->res.jsonValue["CertificateLocations"] = {
675968caeeSMarri Devender Rao                     {"@odata.id",
685968caeeSMarri Devender Rao                      "/redfish/v1/CertificateService/CertificateLocations"}};
6972048780SAbhishek Patel             }
700fda0f12SGeorge Liu             asyncResp->res
710fda0f12SGeorge Liu                 .jsonValue["Actions"]
720fda0f12SGeorge Liu                           ["#CertificateService.ReplaceCertificate"] = {
730fda0f12SGeorge Liu                 {"target",
740fda0f12SGeorge Liu                  "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"},
755968caeeSMarri Devender Rao                 {"CertificateType@Redfish.AllowableValues", {"PEM"}}};
767e860f15SJohn Edward Broadbent             asyncResp->res
777e860f15SJohn Edward Broadbent                 .jsonValue["Actions"]["#CertificateService.GenerateCSR"] = {
780fda0f12SGeorge Liu                 {"target",
790fda0f12SGeorge Liu                  "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"}};
807e860f15SJohn Edward Broadbent         });
817e860f15SJohn Edward Broadbent } // requestRoutesCertificateService
8237cce918SMarri Devender Rao 
835968caeeSMarri Devender Rao /**
845968caeeSMarri Devender Rao  * @brief Find the ID specified in the URL
855968caeeSMarri Devender Rao  * Finds the numbers specified after the last "/" in the URL and returns.
865968caeeSMarri Devender Rao  * @param[in] path URL
875968caeeSMarri Devender Rao  * @return -1 on failure and number on success
885968caeeSMarri Devender Rao  */
8923a21a1cSEd Tanous inline long getIDFromURL(const std::string_view url)
905968caeeSMarri Devender Rao {
91f23b7296SEd Tanous     std::size_t found = url.rfind('/');
925968caeeSMarri Devender Rao     if (found == std::string::npos)
935968caeeSMarri Devender Rao     {
945968caeeSMarri Devender Rao         return -1;
955968caeeSMarri Devender Rao     }
96e6604b11SIwona Klimaszewska 
975968caeeSMarri Devender Rao     if ((found + 1) < url.length())
985968caeeSMarri Devender Rao     {
995968caeeSMarri Devender Rao         std::string_view str = url.substr(found + 1);
100e6604b11SIwona Klimaszewska 
101e6604b11SIwona Klimaszewska         return boost::convert<long>(str, boost::cnv::strtol()).value_or(-1);
1025968caeeSMarri Devender Rao     }
103e6604b11SIwona Klimaszewska 
1045968caeeSMarri Devender Rao     return -1;
1055968caeeSMarri Devender Rao }
1065968caeeSMarri Devender Rao 
1078d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
1088d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10958eb238fSKowalski, Kamil     const crow::Request& req)
11058eb238fSKowalski, Kamil {
11158eb238fSKowalski, Kamil     nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
11258eb238fSKowalski, Kamil 
11358eb238fSKowalski, Kamil     if (reqJson.is_discarded())
11458eb238fSKowalski, Kamil     {
11558eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
11658eb238fSKowalski, Kamil         return req.body;
11758eb238fSKowalski, Kamil     }
11858eb238fSKowalski, Kamil 
11958eb238fSKowalski, Kamil     std::string certificate;
12058eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
12158eb238fSKowalski, Kamil 
12258eb238fSKowalski, Kamil     if (!json_util::readJson(reqJson, asyncResp->res, "CertificateString",
12358eb238fSKowalski, Kamil                              certificate, "CertificateType", certificateType))
12458eb238fSKowalski, Kamil     {
12558eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
12658eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
127abb93cddSEd Tanous         return {};
12858eb238fSKowalski, Kamil     }
12958eb238fSKowalski, Kamil 
13058eb238fSKowalski, Kamil     if (*certificateType != "PEM")
13158eb238fSKowalski, Kamil     {
13258eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
13358eb238fSKowalski, Kamil                                          "CertificateType");
134abb93cddSEd Tanous         return {};
13558eb238fSKowalski, Kamil     }
13658eb238fSKowalski, Kamil 
13758eb238fSKowalski, Kamil     return certificate;
13858eb238fSKowalski, Kamil }
13958eb238fSKowalski, Kamil 
1405968caeeSMarri Devender Rao /**
1415968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
1425968caeeSMarri Devender Rao  */
1435968caeeSMarri Devender Rao class CertificateFile
1445968caeeSMarri Devender Rao {
1455968caeeSMarri Devender Rao   public:
1465968caeeSMarri Devender Rao     CertificateFile() = delete;
1475968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
1485968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
1495968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
1505968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
1515968caeeSMarri Devender Rao     CertificateFile(const std::string& certString)
1525968caeeSMarri Devender Rao     {
15372d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1545207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1555207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1565207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
1575968caeeSMarri Devender Rao         if (tempDirectory)
1585968caeeSMarri Devender Rao         {
1595968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1605968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1615968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1625968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1635968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1645968caeeSMarri Devender Rao             out << certString;
1655968caeeSMarri Devender Rao             out.close();
1665968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "Creating certificate file" << certificateFile;
1675968caeeSMarri Devender Rao         }
1685968caeeSMarri Devender Rao     }
1695968caeeSMarri Devender Rao     ~CertificateFile()
1705968caeeSMarri Devender Rao     {
1715968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1725968caeeSMarri Devender Rao         {
1735968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "Removing certificate file" << certificateFile;
17423a21a1cSEd Tanous             std::error_code ec;
17523a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
17623a21a1cSEd Tanous             if (ec)
1775968caeeSMarri Devender Rao             {
1785968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1795968caeeSMarri Devender Rao                                  << certDirectory;
1805968caeeSMarri Devender Rao             }
1815968caeeSMarri Devender Rao         }
1825968caeeSMarri Devender Rao     }
1835968caeeSMarri Devender Rao     std::string getCertFilePath()
1845968caeeSMarri Devender Rao     {
1855968caeeSMarri Devender Rao         return certificateFile;
1865968caeeSMarri Devender Rao     }
1875968caeeSMarri Devender Rao 
1885968caeeSMarri Devender Rao   private:
1895968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1905968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1915968caeeSMarri Devender Rao };
1925968caeeSMarri Devender Rao 
19330215816SMarri Devender Rao static std::unique_ptr<sdbusplus::bus::match::match> csrMatcher;
19430215816SMarri Devender Rao /**
19530215816SMarri Devender Rao  * @brief Read data from CSR D-bus object and set to response
19630215816SMarri Devender Rao  *
19730215816SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
19830215816SMarri Devender Rao  * @param[in] certURI Link to certifiate collection URI
19930215816SMarri Devender Rao  * @param[in] service D-Bus service name
20030215816SMarri Devender Rao  * @param[in] certObjPath certificate D-Bus object path
20130215816SMarri Devender Rao  * @param[in] csrObjPath CSR D-Bus object path
20230215816SMarri Devender Rao  * @return None
20330215816SMarri Devender Rao  */
2048d1b46d7Szhanghch05 static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
20530215816SMarri Devender Rao                    const std::string& certURI, const std::string& service,
20630215816SMarri Devender Rao                    const std::string& certObjPath,
20730215816SMarri Devender Rao                    const std::string& csrObjPath)
20830215816SMarri Devender Rao {
20930215816SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
21030215816SMarri Devender Rao                      << " CSRObjectPath=" << csrObjPath
21130215816SMarri Devender Rao                      << " service=" << service;
21230215816SMarri Devender Rao     crow::connections::systemBus->async_method_call(
21330215816SMarri Devender Rao         [asyncResp, certURI](const boost::system::error_code ec,
21430215816SMarri Devender Rao                              const std::string& csr) {
21530215816SMarri Devender Rao             if (ec)
21630215816SMarri Devender Rao             {
21730215816SMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
21830215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
21930215816SMarri Devender Rao                 return;
22030215816SMarri Devender Rao             }
22130215816SMarri Devender Rao             if (csr.empty())
22230215816SMarri Devender Rao             {
22330215816SMarri Devender Rao                 BMCWEB_LOG_ERROR << "CSR read is empty";
22430215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
22530215816SMarri Devender Rao                 return;
22630215816SMarri Devender Rao             }
22730215816SMarri Devender Rao             asyncResp->res.jsonValue["CSRString"] = csr;
22830215816SMarri Devender Rao             asyncResp->res.jsonValue["CertificateCollection"] = {
22930215816SMarri Devender Rao                 {"@odata.id", certURI}};
23030215816SMarri Devender Rao         },
23130215816SMarri Devender Rao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
23230215816SMarri Devender Rao }
23330215816SMarri Devender Rao 
23430215816SMarri Devender Rao /**
23530215816SMarri Devender Rao  * Action to Generate CSR
23630215816SMarri Devender Rao  */
2377e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionGenerateCSR(App& app)
23830215816SMarri Devender Rao {
2390fda0f12SGeorge Liu     BMCWEB_ROUTE(
2400fda0f12SGeorge Liu         app,
2410fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
242ed398213SEd Tanous         // Incorrect Privilege;  Should be ConfigureManager
243ed398213SEd Tanous         //.privileges(redfish::privileges::postCertificateService)
244432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
2450fda0f12SGeorge Liu         .methods(
2460fda0f12SGeorge Liu             boost::beast::http::verb::
2470fda0f12SGeorge Liu                 post)([](const crow::Request& req,
2487e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2492c70f800SEd Tanous             static const int rsaKeyBitLength = 2048;
2508d1b46d7Szhanghch05 
25130215816SMarri Devender Rao             // Required parameters
25230215816SMarri Devender Rao             std::string city;
25330215816SMarri Devender Rao             std::string commonName;
25430215816SMarri Devender Rao             std::string country;
25530215816SMarri Devender Rao             std::string organization;
25630215816SMarri Devender Rao             std::string organizationalUnit;
25730215816SMarri Devender Rao             std::string state;
25830215816SMarri Devender Rao             nlohmann::json certificateCollection;
25930215816SMarri Devender Rao 
26030215816SMarri Devender Rao             // Optional parameters
26130215816SMarri Devender Rao             std::optional<std::vector<std::string>> optAlternativeNames =
26230215816SMarri Devender Rao                 std::vector<std::string>();
26330215816SMarri Devender Rao             std::optional<std::string> optContactPerson = "";
26430215816SMarri Devender Rao             std::optional<std::string> optChallengePassword = "";
26530215816SMarri Devender Rao             std::optional<std::string> optEmail = "";
26630215816SMarri Devender Rao             std::optional<std::string> optGivenName = "";
26730215816SMarri Devender Rao             std::optional<std::string> optInitials = "";
2682c70f800SEd Tanous             std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
269aaf3206fSVernon Mauery             std::optional<std::string> optKeyCurveId = "secp384r1";
27030215816SMarri Devender Rao             std::optional<std::string> optKeyPairAlgorithm = "EC";
27130215816SMarri Devender Rao             std::optional<std::vector<std::string>> optKeyUsage =
27230215816SMarri Devender Rao                 std::vector<std::string>();
27330215816SMarri Devender Rao             std::optional<std::string> optSurname = "";
27430215816SMarri Devender Rao             std::optional<std::string> optUnstructuredName = "";
27530215816SMarri Devender Rao             if (!json_util::readJson(
2760fda0f12SGeorge Liu                     req, asyncResp->res, "City", city, "CommonName", commonName,
2770fda0f12SGeorge Liu                     "ContactPerson", optContactPerson, "Country", country,
2780fda0f12SGeorge Liu                     "Organization", organization, "OrganizationalUnit",
2790fda0f12SGeorge Liu                     organizationalUnit, "State", state, "CertificateCollection",
2800fda0f12SGeorge Liu                     certificateCollection, "AlternativeNames",
2810fda0f12SGeorge Liu                     optAlternativeNames, "ChallengePassword",
2820fda0f12SGeorge Liu                     optChallengePassword, "Email", optEmail, "GivenName",
2830fda0f12SGeorge Liu                     optGivenName, "Initials", optInitials, "KeyBitLength",
2840fda0f12SGeorge Liu                     optKeyBitLength, "KeyCurveId", optKeyCurveId,
2850fda0f12SGeorge Liu                     "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
2860fda0f12SGeorge Liu                     optKeyUsage, "Surname", optSurname, "UnstructuredName",
2870fda0f12SGeorge Liu                     optUnstructuredName))
28830215816SMarri Devender Rao             {
28930215816SMarri Devender Rao                 return;
29030215816SMarri Devender Rao             }
29130215816SMarri Devender Rao 
29230215816SMarri Devender Rao             // bmcweb has no way to store or decode a private key challenge
2937e860f15SJohn Edward Broadbent             // password, which will likely cause bmcweb to crash on startup
2947e860f15SJohn Edward Broadbent             // if this is not set on a post so not allowing the user to set
2957e860f15SJohn Edward Broadbent             // value
29630215816SMarri Devender Rao             if (*optChallengePassword != "")
29730215816SMarri Devender Rao             {
2987e860f15SJohn Edward Broadbent                 messages::actionParameterNotSupported(
2997e860f15SJohn Edward Broadbent                     asyncResp->res, "GenerateCSR", "ChallengePassword");
30030215816SMarri Devender Rao                 return;
30130215816SMarri Devender Rao             }
30230215816SMarri Devender Rao 
30330215816SMarri Devender Rao             std::string certURI;
3047e860f15SJohn Edward Broadbent             if (!redfish::json_util::readJson(certificateCollection,
3057e860f15SJohn Edward Broadbent                                               asyncResp->res, "@odata.id",
3067e860f15SJohn Edward Broadbent                                               certURI))
30730215816SMarri Devender Rao             {
30830215816SMarri Devender Rao                 return;
30930215816SMarri Devender Rao             }
31030215816SMarri Devender Rao 
31130215816SMarri Devender Rao             std::string objectPath;
31230215816SMarri Devender Rao             std::string service;
3130fda0f12SGeorge Liu             if (boost::starts_with(
3140fda0f12SGeorge Liu                     certURI,
3150fda0f12SGeorge Liu                     "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
31630215816SMarri Devender Rao             {
31730215816SMarri Devender Rao                 objectPath = certs::httpsObjectPath;
31830215816SMarri Devender Rao                 service = certs::httpsServiceName;
31930215816SMarri Devender Rao             }
3203b7f0149SMarri Devender Rao             else if (boost::starts_with(
3217e860f15SJohn Edward Broadbent                          certURI,
3227e860f15SJohn Edward Broadbent                          "/redfish/v1/AccountService/LDAP/Certificates"))
3233b7f0149SMarri Devender Rao             {
3243b7f0149SMarri Devender Rao                 objectPath = certs::ldapObjectPath;
3253b7f0149SMarri Devender Rao                 service = certs::ldapServiceName;
3263b7f0149SMarri Devender Rao             }
32730215816SMarri Devender Rao             else
32830215816SMarri Devender Rao             {
32930215816SMarri Devender Rao                 messages::actionParameterNotSupported(
33030215816SMarri Devender Rao                     asyncResp->res, "CertificateCollection", "GenerateCSR");
33130215816SMarri Devender Rao                 return;
33230215816SMarri Devender Rao             }
33330215816SMarri Devender Rao 
33430215816SMarri Devender Rao             // supporting only EC and RSA algorithm
3350fda0f12SGeorge Liu             if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
33630215816SMarri Devender Rao             {
33730215816SMarri Devender Rao                 messages::actionParameterNotSupported(
33830215816SMarri Devender Rao                     asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
33930215816SMarri Devender Rao                 return;
34030215816SMarri Devender Rao             }
34130215816SMarri Devender Rao 
3427e860f15SJohn Edward Broadbent             // supporting only 2048 key bit length for RSA algorithm due to
3437e860f15SJohn Edward Broadbent             // time consumed in generating private key
34430215816SMarri Devender Rao             if (*optKeyPairAlgorithm == "RSA" &&
3452c70f800SEd Tanous                 *optKeyBitLength != rsaKeyBitLength)
34630215816SMarri Devender Rao             {
3477e860f15SJohn Edward Broadbent                 messages::propertyValueNotInList(
3487e860f15SJohn Edward Broadbent                     asyncResp->res, std::to_string(*optKeyBitLength),
34930215816SMarri Devender Rao                     "KeyBitLength");
35030215816SMarri Devender Rao                 return;
35130215816SMarri Devender Rao             }
35230215816SMarri Devender Rao 
35330215816SMarri Devender Rao             // validate KeyUsage supporting only 1 type based on URL
3540fda0f12SGeorge Liu             if (boost::starts_with(
3550fda0f12SGeorge Liu                     certURI,
3560fda0f12SGeorge Liu                     "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
35730215816SMarri Devender Rao             {
35830215816SMarri Devender Rao                 if (optKeyUsage->size() == 0)
35930215816SMarri Devender Rao                 {
36030215816SMarri Devender Rao                     optKeyUsage->push_back("ServerAuthentication");
36130215816SMarri Devender Rao                 }
36230215816SMarri Devender Rao                 else if (optKeyUsage->size() == 1)
36330215816SMarri Devender Rao                 {
36430215816SMarri Devender Rao                     if ((*optKeyUsage)[0] != "ServerAuthentication")
36530215816SMarri Devender Rao                     {
36630215816SMarri Devender Rao                         messages::propertyValueNotInList(
36730215816SMarri Devender Rao                             asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
36830215816SMarri Devender Rao                         return;
36930215816SMarri Devender Rao                     }
37030215816SMarri Devender Rao                 }
37130215816SMarri Devender Rao                 else
37230215816SMarri Devender Rao                 {
37330215816SMarri Devender Rao                     messages::actionParameterNotSupported(
37430215816SMarri Devender Rao                         asyncResp->res, "KeyUsage", "GenerateCSR");
37530215816SMarri Devender Rao                     return;
37630215816SMarri Devender Rao                 }
37730215816SMarri Devender Rao             }
3783b7f0149SMarri Devender Rao             else if (boost::starts_with(
3797e860f15SJohn Edward Broadbent                          certURI,
3807e860f15SJohn Edward Broadbent                          "/redfish/v1/AccountService/LDAP/Certificates"))
3813b7f0149SMarri Devender Rao             {
3823b7f0149SMarri Devender Rao                 if (optKeyUsage->size() == 0)
3833b7f0149SMarri Devender Rao                 {
3843b7f0149SMarri Devender Rao                     optKeyUsage->push_back("ClientAuthentication");
3853b7f0149SMarri Devender Rao                 }
3863b7f0149SMarri Devender Rao                 else if (optKeyUsage->size() == 1)
3873b7f0149SMarri Devender Rao                 {
3883b7f0149SMarri Devender Rao                     if ((*optKeyUsage)[0] != "ClientAuthentication")
3893b7f0149SMarri Devender Rao                     {
3903b7f0149SMarri Devender Rao                         messages::propertyValueNotInList(
3913b7f0149SMarri Devender Rao                             asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
3923b7f0149SMarri Devender Rao                         return;
3933b7f0149SMarri Devender Rao                     }
3943b7f0149SMarri Devender Rao                 }
3953b7f0149SMarri Devender Rao                 else
3963b7f0149SMarri Devender Rao                 {
3973b7f0149SMarri Devender Rao                     messages::actionParameterNotSupported(
3983b7f0149SMarri Devender Rao                         asyncResp->res, "KeyUsage", "GenerateCSR");
3993b7f0149SMarri Devender Rao                     return;
4003b7f0149SMarri Devender Rao                 }
4013b7f0149SMarri Devender Rao             }
40230215816SMarri Devender Rao 
4037e860f15SJohn Edward Broadbent             // Only allow one CSR matcher at a time so setting retry
4047e860f15SJohn Edward Broadbent             // time-out and timer expiry to 10 seconds for now.
4052c70f800SEd Tanous             static const int timeOut = 10;
40630215816SMarri Devender Rao             if (csrMatcher)
40730215816SMarri Devender Rao             {
4087e860f15SJohn Edward Broadbent                 messages::serviceTemporarilyUnavailable(
4097e860f15SJohn Edward Broadbent                     asyncResp->res, std::to_string(timeOut));
41030215816SMarri Devender Rao                 return;
41130215816SMarri Devender Rao             }
41230215816SMarri Devender Rao 
41330215816SMarri Devender Rao             // Make this static so it survives outside this method
41430215816SMarri Devender Rao             static boost::asio::steady_timer timeout(*req.ioService);
4152c70f800SEd Tanous             timeout.expires_after(std::chrono::seconds(timeOut));
4160fda0f12SGeorge Liu             timeout.async_wait(
4170fda0f12SGeorge Liu                 [asyncResp](const boost::system::error_code& ec) {
41830215816SMarri Devender Rao                     csrMatcher = nullptr;
41930215816SMarri Devender Rao                     if (ec)
42030215816SMarri Devender Rao                     {
4217e860f15SJohn Edward Broadbent                         // operation_aborted is expected if timer is canceled
4227e860f15SJohn Edward Broadbent                         // before completion.
42330215816SMarri Devender Rao                         if (ec != boost::asio::error::operation_aborted)
42430215816SMarri Devender Rao                         {
42530215816SMarri Devender Rao                             BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
42630215816SMarri Devender Rao                         }
42730215816SMarri Devender Rao                         return;
42830215816SMarri Devender Rao                     }
42930215816SMarri Devender Rao                     BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
43030215816SMarri Devender Rao                     messages::internalError(asyncResp->res);
43130215816SMarri Devender Rao                 });
43230215816SMarri Devender Rao 
43330215816SMarri Devender Rao             // create a matcher to wait on CSR object
43430215816SMarri Devender Rao             BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
4350fda0f12SGeorge Liu             std::string match("type='signal',"
43630215816SMarri Devender Rao                               "interface='org.freedesktop.DBus.ObjectManager',"
43730215816SMarri Devender Rao                               "path='" +
43830215816SMarri Devender Rao                               objectPath +
43930215816SMarri Devender Rao                               "',"
44030215816SMarri Devender Rao                               "member='InterfacesAdded'");
44130215816SMarri Devender Rao             csrMatcher = std::make_unique<sdbusplus::bus::match::match>(
44230215816SMarri Devender Rao                 *crow::connections::systemBus, match,
44330215816SMarri Devender Rao                 [asyncResp, service, objectPath,
44430215816SMarri Devender Rao                  certURI](sdbusplus::message::message& m) {
445271584abSEd Tanous                     timeout.cancel();
44630215816SMarri Devender Rao                     if (m.is_method_error())
44730215816SMarri Devender Rao                     {
44830215816SMarri Devender Rao                         BMCWEB_LOG_ERROR << "Dbus method error!!!";
44930215816SMarri Devender Rao                         messages::internalError(asyncResp->res);
45030215816SMarri Devender Rao                         return;
45130215816SMarri Devender Rao                     }
4520fda0f12SGeorge Liu                     std::vector<
4530fda0f12SGeorge Liu                         std::pair<std::string,
45430215816SMarri Devender Rao                                   std::vector<std::pair<
4550fda0f12SGeorge Liu                                       std::string, std::variant<std::string>>>>>
45630215816SMarri Devender Rao                         interfacesProperties;
45730215816SMarri Devender Rao                     sdbusplus::message::object_path csrObjectPath;
45830215816SMarri Devender Rao                     m.read(csrObjectPath, interfacesProperties);
4590fda0f12SGeorge Liu                     BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
46030215816SMarri Devender Rao                     for (auto& interface : interfacesProperties)
46130215816SMarri Devender Rao                     {
4620fda0f12SGeorge Liu                         if (interface.first == "xyz.openbmc_project.Certs.CSR")
46330215816SMarri Devender Rao                         {
46430215816SMarri Devender Rao                             getCSR(asyncResp, certURI, service, objectPath,
46530215816SMarri Devender Rao                                    csrObjectPath.str);
46630215816SMarri Devender Rao                             break;
46730215816SMarri Devender Rao                         }
46830215816SMarri Devender Rao                     }
46930215816SMarri Devender Rao                 });
47030215816SMarri Devender Rao             crow::connections::systemBus->async_method_call(
471271584abSEd Tanous                 [asyncResp](const boost::system::error_code& ec,
472cb13a392SEd Tanous                             const std::string&) {
47330215816SMarri Devender Rao                     if (ec)
47430215816SMarri Devender Rao                     {
4757e860f15SJohn Edward Broadbent                         BMCWEB_LOG_ERROR << "DBUS response error: "
4767e860f15SJohn Edward Broadbent                                          << ec.message();
47730215816SMarri Devender Rao                         messages::internalError(asyncResp->res);
47830215816SMarri Devender Rao                         return;
47930215816SMarri Devender Rao                     }
48030215816SMarri Devender Rao                 },
48130215816SMarri Devender Rao                 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
4827e860f15SJohn Edward Broadbent                 "GenerateCSR", *optAlternativeNames, *optChallengePassword,
4837e860f15SJohn Edward Broadbent                 city, commonName, *optContactPerson, country, *optEmail,
4840fda0f12SGeorge Liu                 *optGivenName, *optInitials, *optKeyBitLength, *optKeyCurveId,
4850fda0f12SGeorge Liu                 *optKeyPairAlgorithm, *optKeyUsage, organization,
4860fda0f12SGeorge Liu                 organizationalUnit, state, *optSurname, *optUnstructuredName);
4877e860f15SJohn Edward Broadbent         });
4887e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionGenerateCSR
48930215816SMarri Devender Rao 
4905968caeeSMarri Devender Rao /**
4914e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
4925968caeeSMarri Devender Rao  *
4935968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
4945968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
4955968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
4965968caeeSMarri Devender Rao  * @return None
4975968caeeSMarri Devender Rao  */
4985968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
4995968caeeSMarri Devender Rao                                       const std::string_view value)
5005968caeeSMarri Devender Rao {
5015968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
5025968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
5035968caeeSMarri Devender Rao     while (i != value.end())
5045968caeeSMarri Devender Rao     {
5055968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
5065968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
5075968caeeSMarri Devender Rao         {
50817a897dfSManojkiran Eda             ++i;
5095968caeeSMarri Devender Rao         }
5105968caeeSMarri Devender Rao         if (i == value.end())
5115968caeeSMarri Devender Rao         {
5125968caeeSMarri Devender Rao             break;
5135968caeeSMarri Devender Rao         }
514271584abSEd Tanous         const std::string_view key(tokenBegin,
515271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
51617a897dfSManojkiran Eda         ++i;
5175968caeeSMarri Devender Rao         tokenBegin = i;
5185968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
5195968caeeSMarri Devender Rao         {
52017a897dfSManojkiran Eda             ++i;
5215968caeeSMarri Devender Rao         }
522271584abSEd Tanous         const std::string_view val(tokenBegin,
523271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
5245968caeeSMarri Devender Rao         if (key == "L")
5255968caeeSMarri Devender Rao         {
5265968caeeSMarri Devender Rao             out["City"] = val;
5275968caeeSMarri Devender Rao         }
5285968caeeSMarri Devender Rao         else if (key == "CN")
5295968caeeSMarri Devender Rao         {
5305968caeeSMarri Devender Rao             out["CommonName"] = val;
5315968caeeSMarri Devender Rao         }
5325968caeeSMarri Devender Rao         else if (key == "C")
5335968caeeSMarri Devender Rao         {
5345968caeeSMarri Devender Rao             out["Country"] = val;
5355968caeeSMarri Devender Rao         }
5365968caeeSMarri Devender Rao         else if (key == "O")
5375968caeeSMarri Devender Rao         {
5385968caeeSMarri Devender Rao             out["Organization"] = val;
5395968caeeSMarri Devender Rao         }
5405968caeeSMarri Devender Rao         else if (key == "OU")
5415968caeeSMarri Devender Rao         {
5425968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
5435968caeeSMarri Devender Rao         }
5445968caeeSMarri Devender Rao         else if (key == "ST")
5455968caeeSMarri Devender Rao         {
5465968caeeSMarri Devender Rao             out["State"] = val;
5475968caeeSMarri Devender Rao         }
5485968caeeSMarri Devender Rao         // skip comma character
5495968caeeSMarri Devender Rao         if (i != value.end())
5505968caeeSMarri Devender Rao         {
55117a897dfSManojkiran Eda             ++i;
5525968caeeSMarri Devender Rao         }
5535968caeeSMarri Devender Rao     }
5545968caeeSMarri Devender Rao }
5555968caeeSMarri Devender Rao 
5565968caeeSMarri Devender Rao /**
5575968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
5585968caeeSMarri Devender Rao  * message
5595968caeeSMarri Devender Rao  *
5605968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
5615968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
5625968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
5635968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
5645968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
5655968caeeSMarri Devender Rao  * @return None
5665968caeeSMarri Devender Rao  */
5675968caeeSMarri Devender Rao static void getCertificateProperties(
5688d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5698d1b46d7Szhanghch05     const std::string& objectPath, const std::string& service, long certId,
5708d1b46d7Szhanghch05     const std::string& certURL, const std::string& name)
5715968caeeSMarri Devender Rao {
5725968caeeSMarri Devender Rao     using PropertyType =
5735968caeeSMarri Devender Rao         std::variant<std::string, uint64_t, std::vector<std::string>>;
5745968caeeSMarri Devender Rao     using PropertiesMap = boost::container::flat_map<std::string, PropertyType>;
5755968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
5765968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
5775968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
57837cce918SMarri Devender Rao         [asyncResp, certURL, certId, name](const boost::system::error_code ec,
5795968caeeSMarri Devender Rao                                            const PropertiesMap& properties) {
5805968caeeSMarri Devender Rao             if (ec)
5815968caeeSMarri Devender Rao             {
5825968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
5838aae75adSMarri Devender Rao                 messages::resourceNotFound(asyncResp->res, name,
5848aae75adSMarri Devender Rao                                            std::to_string(certId));
5855968caeeSMarri Devender Rao                 return;
5865968caeeSMarri Devender Rao             }
5875968caeeSMarri Devender Rao             asyncResp->res.jsonValue = {
5885968caeeSMarri Devender Rao                 {"@odata.id", certURL},
5895968caeeSMarri Devender Rao                 {"@odata.type", "#Certificate.v1_0_0.Certificate"},
5905968caeeSMarri Devender Rao                 {"Id", std::to_string(certId)},
5915968caeeSMarri Devender Rao                 {"Name", name},
5925968caeeSMarri Devender Rao                 {"Description", name}};
5935968caeeSMarri Devender Rao             for (const auto& property : properties)
5945968caeeSMarri Devender Rao             {
5955968caeeSMarri Devender Rao                 if (property.first == "CertificateString")
5965968caeeSMarri Devender Rao                 {
5975968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["CertificateString"] = "";
5985968caeeSMarri Devender Rao                     const std::string* value =
5995968caeeSMarri Devender Rao                         std::get_if<std::string>(&property.second);
6005968caeeSMarri Devender Rao                     if (value)
6015968caeeSMarri Devender Rao                     {
60237cce918SMarri Devender Rao                         asyncResp->res.jsonValue["CertificateString"] = *value;
6035968caeeSMarri Devender Rao                     }
6045968caeeSMarri Devender Rao                 }
6055968caeeSMarri Devender Rao                 else if (property.first == "KeyUsage")
6065968caeeSMarri Devender Rao                 {
6075968caeeSMarri Devender Rao                     nlohmann::json& keyUsage =
6085968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["KeyUsage"];
6095968caeeSMarri Devender Rao                     keyUsage = nlohmann::json::array();
6105968caeeSMarri Devender Rao                     const std::vector<std::string>* value =
61137cce918SMarri Devender Rao                         std::get_if<std::vector<std::string>>(&property.second);
6125968caeeSMarri Devender Rao                     if (value)
6135968caeeSMarri Devender Rao                     {
6145968caeeSMarri Devender Rao                         for (const std::string& usage : *value)
6155968caeeSMarri Devender Rao                         {
6165968caeeSMarri Devender Rao                             keyUsage.push_back(usage);
6175968caeeSMarri Devender Rao                         }
6185968caeeSMarri Devender Rao                     }
6195968caeeSMarri Devender Rao                 }
6205968caeeSMarri Devender Rao                 else if (property.first == "Issuer")
6215968caeeSMarri Devender Rao                 {
6225968caeeSMarri Devender Rao                     const std::string* value =
6235968caeeSMarri Devender Rao                         std::get_if<std::string>(&property.second);
6245968caeeSMarri Devender Rao                     if (value)
6255968caeeSMarri Devender Rao                     {
6265968caeeSMarri Devender Rao                         updateCertIssuerOrSubject(
6275968caeeSMarri Devender Rao                             asyncResp->res.jsonValue["Issuer"], *value);
6285968caeeSMarri Devender Rao                     }
6295968caeeSMarri Devender Rao                 }
6305968caeeSMarri Devender Rao                 else if (property.first == "Subject")
6315968caeeSMarri Devender Rao                 {
6325968caeeSMarri Devender Rao                     const std::string* value =
6335968caeeSMarri Devender Rao                         std::get_if<std::string>(&property.second);
6345968caeeSMarri Devender Rao                     if (value)
6355968caeeSMarri Devender Rao                     {
6365968caeeSMarri Devender Rao                         updateCertIssuerOrSubject(
63737cce918SMarri Devender Rao                             asyncResp->res.jsonValue["Subject"], *value);
6385968caeeSMarri Devender Rao                     }
6395968caeeSMarri Devender Rao                 }
6405968caeeSMarri Devender Rao                 else if (property.first == "ValidNotAfter")
6415968caeeSMarri Devender Rao                 {
6425968caeeSMarri Devender Rao                     const uint64_t* value =
6435968caeeSMarri Devender Rao                         std::get_if<uint64_t>(&property.second);
6445968caeeSMarri Devender Rao                     if (value)
6455968caeeSMarri Devender Rao                     {
6465968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["ValidNotAfter"] =
647*1d8782e7SNan Zhou                             crow::utility::getDateTimeUint(*value);
6485968caeeSMarri Devender Rao                     }
6495968caeeSMarri Devender Rao                 }
6505968caeeSMarri Devender Rao                 else if (property.first == "ValidNotBefore")
6515968caeeSMarri Devender Rao                 {
6525968caeeSMarri Devender Rao                     const uint64_t* value =
6535968caeeSMarri Devender Rao                         std::get_if<uint64_t>(&property.second);
6545968caeeSMarri Devender Rao                     if (value)
6555968caeeSMarri Devender Rao                     {
6565968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["ValidNotBefore"] =
657*1d8782e7SNan Zhou                             crow::utility::getDateTimeUint(*value);
6585968caeeSMarri Devender Rao                     }
6595968caeeSMarri Devender Rao                 }
6605968caeeSMarri Devender Rao             }
6615968caeeSMarri Devender Rao             asyncResp->res.addHeader("Location", certURL);
6625968caeeSMarri Devender Rao         },
6635968caeeSMarri Devender Rao         service, objectPath, certs::dbusPropIntf, "GetAll",
6645968caeeSMarri Devender Rao         certs::certPropIntf);
6655968caeeSMarri Devender Rao }
6665968caeeSMarri Devender Rao 
6675968caeeSMarri Devender Rao using GetObjectType =
6685968caeeSMarri Devender Rao     std::vector<std::pair<std::string, std::vector<std::string>>>;
6695968caeeSMarri Devender Rao 
6705968caeeSMarri Devender Rao /**
6715968caeeSMarri Devender Rao  * Action to replace an existing certificate
6725968caeeSMarri Devender Rao  */
6737e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionsReplaceCertificate(App& app)
6745968caeeSMarri Devender Rao {
6750fda0f12SGeorge Liu     BMCWEB_ROUTE(
6760fda0f12SGeorge Liu         app,
6770fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
678ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateService)
6797e860f15SJohn Edward Broadbent         .methods(
6807e860f15SJohn Edward Broadbent             boost::beast::http::verb::
6817e860f15SJohn Edward Broadbent                 post)([](const crow::Request& req,
6827e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
6835968caeeSMarri Devender Rao             std::string certificate;
6845968caeeSMarri Devender Rao             nlohmann::json certificateUri;
6855968caeeSMarri Devender Rao             std::optional<std::string> certificateType = "PEM";
6868d1b46d7Szhanghch05 
6875968caeeSMarri Devender Rao             if (!json_util::readJson(req, asyncResp->res, "CertificateString",
6887e860f15SJohn Edward Broadbent                                      certificate, "CertificateUri",
6897e860f15SJohn Edward Broadbent                                      certificateUri, "CertificateType",
6907e860f15SJohn Edward Broadbent                                      certificateType))
6915968caeeSMarri Devender Rao             {
6925968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Required parameters are missing";
6935968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
6945968caeeSMarri Devender Rao                 return;
6955968caeeSMarri Devender Rao             }
6965968caeeSMarri Devender Rao 
6975968caeeSMarri Devender Rao             if (!certificateType)
6985968caeeSMarri Devender Rao             {
6995968caeeSMarri Devender Rao                 // should never happen, but it never hurts to be paranoid.
7005968caeeSMarri Devender Rao                 return;
7015968caeeSMarri Devender Rao             }
7025968caeeSMarri Devender Rao             if (certificateType != "PEM")
7035968caeeSMarri Devender Rao             {
7045968caeeSMarri Devender Rao                 messages::actionParameterNotSupported(
7055968caeeSMarri Devender Rao                     asyncResp->res, "CertificateType", "ReplaceCertificate");
7065968caeeSMarri Devender Rao                 return;
7075968caeeSMarri Devender Rao             }
7085968caeeSMarri Devender Rao 
7095968caeeSMarri Devender Rao             std::string certURI;
7105968caeeSMarri Devender Rao             if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
7115968caeeSMarri Devender Rao                                               "@odata.id", certURI))
7125968caeeSMarri Devender Rao             {
7135968caeeSMarri Devender Rao                 messages::actionParameterMissing(
7145968caeeSMarri Devender Rao                     asyncResp->res, "ReplaceCertificate", "CertificateUri");
7155968caeeSMarri Devender Rao                 return;
7165968caeeSMarri Devender Rao             }
7175968caeeSMarri Devender Rao 
7185968caeeSMarri Devender Rao             BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI;
7195968caeeSMarri Devender Rao             long id = getIDFromURL(certURI);
7205968caeeSMarri Devender Rao             if (id < 0)
7215968caeeSMarri Devender Rao             {
7227e860f15SJohn Edward Broadbent                 messages::actionParameterValueFormatError(
7237e860f15SJohn Edward Broadbent                     asyncResp->res, certURI, "CertificateUri",
7245968caeeSMarri Devender Rao                     "ReplaceCertificate");
7255968caeeSMarri Devender Rao                 return;
7265968caeeSMarri Devender Rao             }
7275968caeeSMarri Devender Rao             std::string objectPath;
7285968caeeSMarri Devender Rao             std::string name;
72937cce918SMarri Devender Rao             std::string service;
7300fda0f12SGeorge Liu             if (boost::starts_with(
7310fda0f12SGeorge Liu                     certURI,
7320fda0f12SGeorge Liu                     "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"))
7335968caeeSMarri Devender Rao             {
7347e860f15SJohn Edward Broadbent                 objectPath = std::string(certs::httpsObjectPath) + "/" +
7357e860f15SJohn Edward Broadbent                              std::to_string(id);
7365968caeeSMarri Devender Rao                 name = "HTTPS certificate";
73737cce918SMarri Devender Rao                 service = certs::httpsServiceName;
73837cce918SMarri Devender Rao             }
73937cce918SMarri Devender Rao             else if (boost::starts_with(
7407e860f15SJohn Edward Broadbent                          certURI,
7417e860f15SJohn Edward Broadbent                          "/redfish/v1/AccountService/LDAP/Certificates/"))
74237cce918SMarri Devender Rao             {
7437e860f15SJohn Edward Broadbent                 objectPath = std::string(certs::ldapObjectPath) + "/" +
7447e860f15SJohn Edward Broadbent                              std::to_string(id);
74537cce918SMarri Devender Rao                 name = "LDAP certificate";
74637cce918SMarri Devender Rao                 service = certs::ldapServiceName;
7475968caeeSMarri Devender Rao             }
748cfcd5f6bSMarri Devender Rao             else if (boost::starts_with(
749cfcd5f6bSMarri Devender Rao                          certURI,
750cfcd5f6bSMarri Devender Rao                          "/redfish/v1/Managers/bmc/Truststore/Certificates/"))
751cfcd5f6bSMarri Devender Rao             {
752cfcd5f6bSMarri Devender Rao                 objectPath = std::string(certs::authorityObjectPath) + "/" +
753cfcd5f6bSMarri Devender Rao                              std::to_string(id);
754cfcd5f6bSMarri Devender Rao                 name = "TrustStore certificate";
755cfcd5f6bSMarri Devender Rao                 service = certs::authorityServiceName;
756cfcd5f6bSMarri Devender Rao             }
7575968caeeSMarri Devender Rao             else
7585968caeeSMarri Devender Rao             {
7595968caeeSMarri Devender Rao                 messages::actionParameterNotSupported(
7605968caeeSMarri Devender Rao                     asyncResp->res, "CertificateUri", "ReplaceCertificate");
7615968caeeSMarri Devender Rao                 return;
7625968caeeSMarri Devender Rao             }
7635968caeeSMarri Devender Rao 
7645968caeeSMarri Devender Rao             std::shared_ptr<CertificateFile> certFile =
7655968caeeSMarri Devender Rao                 std::make_shared<CertificateFile>(certificate);
7665968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
76737cce918SMarri Devender Rao                 [asyncResp, certFile, objectPath, service, certURI, id,
7685968caeeSMarri Devender Rao                  name](const boost::system::error_code ec) {
7695968caeeSMarri Devender Rao                     if (ec)
7705968caeeSMarri Devender Rao                     {
7715968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
7728aae75adSMarri Devender Rao                         messages::resourceNotFound(asyncResp->res, name,
7738aae75adSMarri Devender Rao                                                    std::to_string(id));
7745968caeeSMarri Devender Rao                         return;
7755968caeeSMarri Devender Rao                     }
77637cce918SMarri Devender Rao                     getCertificateProperties(asyncResp, objectPath, service, id,
7775968caeeSMarri Devender Rao                                              certURI, name);
7785968caeeSMarri Devender Rao                     BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
7795968caeeSMarri Devender Rao                                      << certFile->getCertFilePath();
7805968caeeSMarri Devender Rao                 },
7815968caeeSMarri Devender Rao                 service, objectPath, certs::certReplaceIntf, "Replace",
7825968caeeSMarri Devender Rao                 certFile->getCertFilePath());
7837e860f15SJohn Edward Broadbent         });
7847e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionsReplaceCertificate
7855968caeeSMarri Devender Rao 
7865968caeeSMarri Devender Rao /**
7875968caeeSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
7885968caeeSMarri Devender Rao  * of a component, account or service.
7895968caeeSMarri Devender Rao  */
7905968caeeSMarri Devender Rao 
7917e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificate(App& app)
7925968caeeSMarri Devender Rao {
7937e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
7947e860f15SJohn Edward Broadbent         app,
7957e860f15SJohn Edward Broadbent         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
796ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
7977e860f15SJohn Edward Broadbent         .methods(
7987e860f15SJohn Edward Broadbent             boost::beast::http::verb::
7997e860f15SJohn Edward Broadbent                 get)([](const crow::Request& req,
8007e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8017e860f15SJohn Edward Broadbent                         const std::string& param) -> void {
8027e860f15SJohn Edward Broadbent             if (param.empty())
8035968caeeSMarri Devender Rao             {
8045968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
8055968caeeSMarri Devender Rao                 return;
8065968caeeSMarri Devender Rao             }
8075968caeeSMarri Devender Rao             long id = getIDFromURL(req.url);
8085968caeeSMarri Devender Rao 
8097e860f15SJohn Edward Broadbent             BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID="
8107e860f15SJohn Edward Broadbent                              << std::to_string(id);
8115968caeeSMarri Devender Rao             std::string certURL =
8125968caeeSMarri Devender Rao                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8135968caeeSMarri Devender Rao                 std::to_string(id);
8145968caeeSMarri Devender Rao             std::string objectPath = certs::httpsObjectPath;
8155968caeeSMarri Devender Rao             objectPath += "/";
8165968caeeSMarri Devender Rao             objectPath += std::to_string(id);
8177e860f15SJohn Edward Broadbent             getCertificateProperties(asyncResp, objectPath,
8187e860f15SJohn Edward Broadbent                                      certs::httpsServiceName, id, certURL,
8197e860f15SJohn Edward Broadbent                                      "HTTPS Certificate");
8207e860f15SJohn Edward Broadbent         });
8215968caeeSMarri Devender Rao }
8225968caeeSMarri Devender Rao 
8235968caeeSMarri Devender Rao /**
8245968caeeSMarri Devender Rao  * Collection of HTTPS certificates
8255968caeeSMarri Devender Rao  */
8267e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificateCollection(App& app)
8275968caeeSMarri Devender Rao {
8287e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8295968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
830ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
8317e860f15SJohn Edward Broadbent         .methods(
8327e860f15SJohn Edward Broadbent             boost::beast::http::verb::
8337e860f15SJohn Edward Broadbent                 get)([](const crow::Request&,
8347e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8358d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
8365968caeeSMarri Devender Rao                 {"@odata.id",
8375968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"},
8385968caeeSMarri Devender Rao                 {"@odata.type", "#CertificateCollection.CertificateCollection"},
8395968caeeSMarri Devender Rao                 {"Name", "HTTPS Certificates Collection"},
8405968caeeSMarri Devender Rao                 {"Description", "A Collection of HTTPS certificate instances"}};
8418d1b46d7Szhanghch05 
8425968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
8435968caeeSMarri Devender Rao                 [asyncResp](const boost::system::error_code ec,
8445968caeeSMarri Devender Rao                             const ManagedObjectType& certs) {
8455968caeeSMarri Devender Rao                     if (ec)
8465968caeeSMarri Devender Rao                     {
8475968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
8485968caeeSMarri Devender Rao                         messages::internalError(asyncResp->res);
8495968caeeSMarri Devender Rao                         return;
8505968caeeSMarri Devender Rao                     }
8517e860f15SJohn Edward Broadbent                     nlohmann::json& members =
8527e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
8535968caeeSMarri Devender Rao                     members = nlohmann::json::array();
8545968caeeSMarri Devender Rao                     for (const auto& cert : certs)
8555968caeeSMarri Devender Rao                     {
8565968caeeSMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
85737cce918SMarri Devender Rao                         if (id >= 0)
8585968caeeSMarri Devender Rao                         {
8595968caeeSMarri Devender Rao                             members.push_back(
8605968caeeSMarri Devender Rao                                 {{"@odata.id",
8610fda0f12SGeorge Liu                                   "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8625968caeeSMarri Devender Rao                                       std::to_string(id)}});
8635968caeeSMarri Devender Rao                         }
8645968caeeSMarri Devender Rao                     }
8655968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["Members@odata.count"] =
8665968caeeSMarri Devender Rao                         members.size();
8675968caeeSMarri Devender Rao                 },
86837cce918SMarri Devender Rao                 certs::httpsServiceName, certs::httpsObjectPath,
86937cce918SMarri Devender Rao                 certs::dbusObjManagerIntf, "GetManagedObjects");
8707e860f15SJohn Edward Broadbent         });
8715968caeeSMarri Devender Rao 
8727e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8737e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
874ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
8750fda0f12SGeorge Liu         .methods(
8760fda0f12SGeorge Liu             boost::beast::http::verb::
8770fda0f12SGeorge Liu                 post)([](const crow::Request& req,
8787e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8795968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
8808d1b46d7Szhanghch05 
8810fda0f12SGeorge Liu             asyncResp->res.jsonValue = {{"Name", "HTTPS Certificate"},
8825968caeeSMarri Devender Rao                                         {"Description", "HTTPS Certificate"}};
8835968caeeSMarri Devender Rao 
8847e860f15SJohn Edward Broadbent             std::string certFileBody =
8857e860f15SJohn Edward Broadbent                 getCertificateFromReqBody(asyncResp, req);
88658eb238fSKowalski, Kamil 
88758eb238fSKowalski, Kamil             if (certFileBody.empty())
88858eb238fSKowalski, Kamil             {
8890fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
890a08752f5SZbigniew Kurzynski                 messages::unrecognizedRequestBody(asyncResp->res);
89158eb238fSKowalski, Kamil                 return;
89258eb238fSKowalski, Kamil             }
89358eb238fSKowalski, Kamil 
8945968caeeSMarri Devender Rao             std::shared_ptr<CertificateFile> certFile =
89558eb238fSKowalski, Kamil                 std::make_shared<CertificateFile>(certFileBody);
8965968caeeSMarri Devender Rao 
8975968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
898656ec7e3SZbigniew Kurzynski                 [asyncResp, certFile](const boost::system::error_code ec,
899656ec7e3SZbigniew Kurzynski                                       const std::string& objectPath) {
9005968caeeSMarri Devender Rao                     if (ec)
9015968caeeSMarri Devender Rao                     {
9025968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9035968caeeSMarri Devender Rao                         messages::internalError(asyncResp->res);
9045968caeeSMarri Devender Rao                         return;
9055968caeeSMarri Devender Rao                     }
906656ec7e3SZbigniew Kurzynski                     long certId = getIDFromURL(objectPath);
907656ec7e3SZbigniew Kurzynski                     if (certId < 0)
908656ec7e3SZbigniew Kurzynski                     {
909656ec7e3SZbigniew Kurzynski                         BMCWEB_LOG_ERROR << "Invalid objectPath value"
910656ec7e3SZbigniew Kurzynski                                          << objectPath;
911656ec7e3SZbigniew Kurzynski                         messages::internalError(asyncResp->res);
912656ec7e3SZbigniew Kurzynski                         return;
913656ec7e3SZbigniew Kurzynski                     }
9145968caeeSMarri Devender Rao                     std::string certURL =
9150fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
9165968caeeSMarri Devender Rao                         std::to_string(certId);
9170fda0f12SGeorge Liu                     getCertificateProperties(asyncResp, objectPath,
9180fda0f12SGeorge Liu                                              certs::httpsServiceName, certId,
9190fda0f12SGeorge Liu                                              certURL, "HTTPS Certificate");
9205968caeeSMarri Devender Rao                     BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9215968caeeSMarri Devender Rao                                      << certFile->getCertFilePath();
9225968caeeSMarri Devender Rao                 },
92337cce918SMarri Devender Rao                 certs::httpsServiceName, certs::httpsObjectPath,
9240fda0f12SGeorge Liu                 certs::certInstallIntf, "Install", certFile->getCertFilePath());
9257e860f15SJohn Edward Broadbent         });
9267e860f15SJohn Edward Broadbent } // requestRoutesHTTPSCertificateCollection
9275968caeeSMarri Devender Rao 
9285968caeeSMarri Devender Rao /**
92937cce918SMarri Devender Rao  * @brief Retrieve the certificates installed list and append to the
93037cce918SMarri Devender Rao  * response
93137cce918SMarri Devender Rao  *
93237cce918SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
93337cce918SMarri Devender Rao  * @param[in] certURL  Path of the certificate object
93437cce918SMarri Devender Rao  * @param[in] path  Path of the D-Bus service object
93537cce918SMarri Devender Rao  * @return None
93637cce918SMarri Devender Rao  */
9374f48d5f6SEd Tanous inline void
9384f48d5f6SEd Tanous     getCertificateLocations(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9398d1b46d7Szhanghch05                             const std::string& certURL, const std::string& path,
94037cce918SMarri Devender Rao                             const std::string& service)
94137cce918SMarri Devender Rao {
94237cce918SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL
94337cce918SMarri Devender Rao                      << " Path=" << path << " service= " << service;
94437cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
94537cce918SMarri Devender Rao         [asyncResp, certURL](const boost::system::error_code ec,
94637cce918SMarri Devender Rao                              const ManagedObjectType& certs) {
94737cce918SMarri Devender Rao             if (ec)
94837cce918SMarri Devender Rao             {
9499c8e039eSJonathan Doman                 BMCWEB_LOG_WARNING
9509c8e039eSJonathan Doman                     << "Certificate collection query failed: " << ec
9519c8e039eSJonathan Doman                     << ", skipping " << certURL;
95237cce918SMarri Devender Rao                 return;
95337cce918SMarri Devender Rao             }
95437cce918SMarri Devender Rao             nlohmann::json& links =
95537cce918SMarri Devender Rao                 asyncResp->res.jsonValue["Links"]["Certificates"];
95637cce918SMarri Devender Rao             for (auto& cert : certs)
95737cce918SMarri Devender Rao             {
95837cce918SMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
95937cce918SMarri Devender Rao                 if (id >= 0)
96037cce918SMarri Devender Rao                 {
96137cce918SMarri Devender Rao                     links.push_back(
96237cce918SMarri Devender Rao                         {{"@odata.id", certURL + std::to_string(id)}});
96337cce918SMarri Devender Rao                 }
96437cce918SMarri Devender Rao             }
96537cce918SMarri Devender Rao             asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] =
96637cce918SMarri Devender Rao                 links.size();
96737cce918SMarri Devender Rao         },
96837cce918SMarri Devender Rao         service, path, certs::dbusObjManagerIntf, "GetManagedObjects");
9695968caeeSMarri Devender Rao }
9707e860f15SJohn Edward Broadbent 
9717e860f15SJohn Edward Broadbent /**
9727e860f15SJohn Edward Broadbent  * The certificate location schema defines a resource that an administrator
9737e860f15SJohn Edward Broadbent  * can use in order to locate all certificates installed on a given service.
9747e860f15SJohn Edward Broadbent  */
9757e860f15SJohn Edward Broadbent inline void requestRoutesCertificateLocations(App& app)
9767e860f15SJohn Edward Broadbent {
9777e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
978ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateLocations)
9797e860f15SJohn Edward Broadbent         .methods(
9807e860f15SJohn Edward Broadbent             boost::beast::http::verb::
9817e860f15SJohn Edward Broadbent                 get)([](const crow::Request&,
9827e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
9837e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue = {
9847e860f15SJohn Edward Broadbent                 {"@odata.id",
9857e860f15SJohn Edward Broadbent                  "/redfish/v1/CertificateService/CertificateLocations"},
9867e860f15SJohn Edward Broadbent                 {"@odata.type",
9877e860f15SJohn Edward Broadbent                  "#CertificateLocations.v1_0_0.CertificateLocations"},
9887e860f15SJohn Edward Broadbent                 {"Name", "Certificate Locations"},
9897e860f15SJohn Edward Broadbent                 {"Id", "CertificateLocations"},
9907e860f15SJohn Edward Broadbent                 {"Description",
9917e860f15SJohn Edward Broadbent                  "Defines a resource that an administrator can use in order to "
9927e860f15SJohn Edward Broadbent                  "locate all certificates installed on a given service"}};
9937e860f15SJohn Edward Broadbent 
9947e860f15SJohn Edward Broadbent             nlohmann::json& links =
9957e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Links"]["Certificates"];
9967e860f15SJohn Edward Broadbent             links = nlohmann::json::array();
9977e860f15SJohn Edward Broadbent             getCertificateLocations(
9987e860f15SJohn Edward Broadbent                 asyncResp,
9997e860f15SJohn Edward Broadbent                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/",
10007e860f15SJohn Edward Broadbent                 certs::httpsObjectPath, certs::httpsServiceName);
10017e860f15SJohn Edward Broadbent             getCertificateLocations(
10027e860f15SJohn Edward Broadbent                 asyncResp, "/redfish/v1/AccountService/LDAP/Certificates/",
10037e860f15SJohn Edward Broadbent                 certs::ldapObjectPath, certs::ldapServiceName);
10047e860f15SJohn Edward Broadbent             getCertificateLocations(
10057e860f15SJohn Edward Broadbent                 asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/",
10067e860f15SJohn Edward Broadbent                 certs::authorityObjectPath, certs::authorityServiceName);
10077e860f15SJohn Edward Broadbent         });
10087e860f15SJohn Edward Broadbent }
10097e860f15SJohn Edward Broadbent // requestRoutesCertificateLocations
101037cce918SMarri Devender Rao 
101137cce918SMarri Devender Rao /**
101237cce918SMarri Devender Rao  * Collection of LDAP certificates
101337cce918SMarri Devender Rao  */
10147e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificateCollection(App& app)
101537cce918SMarri Devender Rao {
10167e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1017ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
10180fda0f12SGeorge Liu         .methods(
10190fda0f12SGeorge Liu             boost::beast::http::verb::
10200fda0f12SGeorge Liu                 get)([](const crow::Request&,
10217e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10228d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
10230fda0f12SGeorge Liu                 {"@odata.id", "/redfish/v1/AccountService/LDAP/Certificates"},
10240fda0f12SGeorge Liu                 {"@odata.type", "#CertificateCollection.CertificateCollection"},
102537cce918SMarri Devender Rao                 {"Name", "LDAP Certificates Collection"},
10260fda0f12SGeorge Liu                 {"Description", "A Collection of LDAP certificate instances"}};
10278d1b46d7Szhanghch05 
102837cce918SMarri Devender Rao             crow::connections::systemBus->async_method_call(
102937cce918SMarri Devender Rao                 [asyncResp](const boost::system::error_code ec,
103037cce918SMarri Devender Rao                             const ManagedObjectType& certs) {
10317e860f15SJohn Edward Broadbent                     nlohmann::json& members =
10327e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
10339c8e039eSJonathan Doman                     nlohmann::json& count =
10349c8e039eSJonathan Doman                         asyncResp->res.jsonValue["Members@odata.count"];
10359c8e039eSJonathan Doman                     members = nlohmann::json::array();
10369c8e039eSJonathan Doman                     count = 0;
103737cce918SMarri Devender Rao                     if (ec)
103837cce918SMarri Devender Rao                     {
10390fda0f12SGeorge Liu                         BMCWEB_LOG_WARNING << "LDAP certificate query failed: "
10400fda0f12SGeorge Liu                                            << ec;
104137cce918SMarri Devender Rao                         return;
104237cce918SMarri Devender Rao                     }
104337cce918SMarri Devender Rao                     for (const auto& cert : certs)
104437cce918SMarri Devender Rao                     {
104537cce918SMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
104637cce918SMarri Devender Rao                         if (id >= 0)
104737cce918SMarri Devender Rao                         {
104837cce918SMarri Devender Rao                             members.push_back(
10490fda0f12SGeorge Liu                                 {{"@odata.id",
10500fda0f12SGeorge Liu                                   "/redfish/v1/AccountService/LDAP/Certificates/" +
105137cce918SMarri Devender Rao                                       std::to_string(id)}});
105237cce918SMarri Devender Rao                         }
105337cce918SMarri Devender Rao                     }
10549c8e039eSJonathan Doman                     count = members.size();
105537cce918SMarri Devender Rao                 },
105637cce918SMarri Devender Rao                 certs::ldapServiceName, certs::ldapObjectPath,
105737cce918SMarri Devender Rao                 certs::dbusObjManagerIntf, "GetManagedObjects");
10587e860f15SJohn Edward Broadbent         });
105937cce918SMarri Devender Rao 
10607e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1061ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
10627e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
10637e860f15SJohn Edward Broadbent             [](const crow::Request& req,
10647e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10657e860f15SJohn Edward Broadbent                 std::string certFileBody =
10667e860f15SJohn Edward Broadbent                     getCertificateFromReqBody(asyncResp, req);
106758eb238fSKowalski, Kamil 
106858eb238fSKowalski, Kamil                 if (certFileBody.empty())
106958eb238fSKowalski, Kamil                 {
10707e860f15SJohn Edward Broadbent                     BMCWEB_LOG_ERROR
10717e860f15SJohn Edward Broadbent                         << "Cannot get certificate from request body.";
1072a08752f5SZbigniew Kurzynski                     messages::unrecognizedRequestBody(asyncResp->res);
107358eb238fSKowalski, Kamil                     return;
107458eb238fSKowalski, Kamil                 }
107558eb238fSKowalski, Kamil 
107658eb238fSKowalski, Kamil                 std::shared_ptr<CertificateFile> certFile =
107758eb238fSKowalski, Kamil                     std::make_shared<CertificateFile>(certFileBody);
107858eb238fSKowalski, Kamil 
107937cce918SMarri Devender Rao                 crow::connections::systemBus->async_method_call(
1080656ec7e3SZbigniew Kurzynski                     [asyncResp, certFile](const boost::system::error_code ec,
1081656ec7e3SZbigniew Kurzynski                                           const std::string& objectPath) {
108237cce918SMarri Devender Rao                         if (ec)
108337cce918SMarri Devender Rao                         {
108437cce918SMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
108537cce918SMarri Devender Rao                             messages::internalError(asyncResp->res);
108637cce918SMarri Devender Rao                             return;
108737cce918SMarri Devender Rao                         }
1088656ec7e3SZbigniew Kurzynski                         long certId = getIDFromURL(objectPath);
1089656ec7e3SZbigniew Kurzynski                         if (certId < 0)
1090656ec7e3SZbigniew Kurzynski                         {
1091656ec7e3SZbigniew Kurzynski                             BMCWEB_LOG_ERROR << "Invalid objectPath value"
1092656ec7e3SZbigniew Kurzynski                                              << objectPath;
1093656ec7e3SZbigniew Kurzynski                             messages::internalError(asyncResp->res);
1094656ec7e3SZbigniew Kurzynski                             return;
1095656ec7e3SZbigniew Kurzynski                         }
109637cce918SMarri Devender Rao                         std::string certURL =
109737cce918SMarri Devender Rao                             "/redfish/v1/AccountService/LDAP/Certificates/" +
109837cce918SMarri Devender Rao                             std::to_string(certId);
109937cce918SMarri Devender Rao                         getCertificateProperties(asyncResp, objectPath,
110037cce918SMarri Devender Rao                                                  certs::ldapServiceName, certId,
110137cce918SMarri Devender Rao                                                  certURL, "LDAP Certificate");
110237cce918SMarri Devender Rao                         BMCWEB_LOG_DEBUG << "LDAP certificate install file="
110337cce918SMarri Devender Rao                                          << certFile->getCertFilePath();
110437cce918SMarri Devender Rao                     },
110537cce918SMarri Devender Rao                     certs::ldapServiceName, certs::ldapObjectPath,
11067e860f15SJohn Edward Broadbent                     certs::certInstallIntf, "Install",
11077e860f15SJohn Edward Broadbent                     certFile->getCertFilePath());
11087e860f15SJohn Edward Broadbent             });
11097e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificateCollection
111037cce918SMarri Devender Rao 
111137cce918SMarri Devender Rao /**
111237cce918SMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
111337cce918SMarri Devender Rao  * of a component, account or service.
111437cce918SMarri Devender Rao  */
11157e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificate(App& app)
111637cce918SMarri Devender Rao {
11177e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1118ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
11197e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
11207e860f15SJohn Edward Broadbent             [](const crow::Request& req,
11217e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11227e860f15SJohn Edward Broadbent                const std::string&) {
112337cce918SMarri Devender Rao                 long id = getIDFromURL(req.url);
112437cce918SMarri Devender Rao                 if (id < 0)
112537cce918SMarri Devender Rao                 {
112637cce918SMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
112737cce918SMarri Devender Rao                     messages::internalError(asyncResp->res);
112837cce918SMarri Devender Rao                     return;
112937cce918SMarri Devender Rao                 }
11307e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG << "LDAP Certificate ID="
11317e860f15SJohn Edward Broadbent                                  << std::to_string(id);
11327e860f15SJohn Edward Broadbent                 std::string certURL =
11337e860f15SJohn Edward Broadbent                     "/redfish/v1/AccountService/LDAP/Certificates/" +
113437cce918SMarri Devender Rao                     std::to_string(id);
113537cce918SMarri Devender Rao                 std::string objectPath = certs::ldapObjectPath;
113637cce918SMarri Devender Rao                 objectPath += "/";
113737cce918SMarri Devender Rao                 objectPath += std::to_string(id);
11387e860f15SJohn Edward Broadbent                 getCertificateProperties(asyncResp, objectPath,
11397e860f15SJohn Edward Broadbent                                          certs::ldapServiceName, id, certURL,
11407e860f15SJohn Edward Broadbent                                          "LDAP Certificate");
11417e860f15SJohn Edward Broadbent             });
11427e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificate
1143cfcd5f6bSMarri Devender Rao /**
1144cfcd5f6bSMarri Devender Rao  * Collection of TrustStoreCertificate certificates
1145cfcd5f6bSMarri Devender Rao  */
11467e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificateCollection(App& app)
1147cfcd5f6bSMarri Devender Rao {
11487e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1149ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
11500fda0f12SGeorge Liu         .methods(
11510fda0f12SGeorge Liu             boost::beast::http::verb::
11520fda0f12SGeorge Liu                 get)([](const crow::Request&,
11537e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
11548d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
11557e860f15SJohn Edward Broadbent                 {"@odata.id",
11567e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/Truststore/Certificates/"},
11570fda0f12SGeorge Liu                 {"@odata.type", "#CertificateCollection.CertificateCollection"},
1158cfcd5f6bSMarri Devender Rao                 {"Name", "TrustStore Certificates Collection"},
1159cfcd5f6bSMarri Devender Rao                 {"Description",
1160cfcd5f6bSMarri Devender Rao                  "A Collection of TrustStore certificate instances"}};
11618d1b46d7Szhanghch05 
1162cfcd5f6bSMarri Devender Rao             crow::connections::systemBus->async_method_call(
1163cfcd5f6bSMarri Devender Rao                 [asyncResp](const boost::system::error_code ec,
1164cfcd5f6bSMarri Devender Rao                             const ManagedObjectType& certs) {
1165cfcd5f6bSMarri Devender Rao                     if (ec)
1166cfcd5f6bSMarri Devender Rao                     {
1167cfcd5f6bSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1168cfcd5f6bSMarri Devender Rao                         messages::internalError(asyncResp->res);
1169cfcd5f6bSMarri Devender Rao                         return;
1170cfcd5f6bSMarri Devender Rao                     }
11717e860f15SJohn Edward Broadbent                     nlohmann::json& members =
11727e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
1173cfcd5f6bSMarri Devender Rao                     members = nlohmann::json::array();
1174cfcd5f6bSMarri Devender Rao                     for (const auto& cert : certs)
1175cfcd5f6bSMarri Devender Rao                     {
1176cfcd5f6bSMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
1177cfcd5f6bSMarri Devender Rao                         if (id >= 0)
1178cfcd5f6bSMarri Devender Rao                         {
1179cfcd5f6bSMarri Devender Rao                             members.push_back(
11800fda0f12SGeorge Liu                                 {{"@odata.id",
11810fda0f12SGeorge Liu                                   "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1182cfcd5f6bSMarri Devender Rao                                       std::to_string(id)}});
1183cfcd5f6bSMarri Devender Rao                         }
1184cfcd5f6bSMarri Devender Rao                     }
1185cfcd5f6bSMarri Devender Rao                     asyncResp->res.jsonValue["Members@odata.count"] =
1186cfcd5f6bSMarri Devender Rao                         members.size();
1187cfcd5f6bSMarri Devender Rao                 },
1188cfcd5f6bSMarri Devender Rao                 certs::authorityServiceName, certs::authorityObjectPath,
1189cfcd5f6bSMarri Devender Rao                 certs::dbusObjManagerIntf, "GetManagedObjects");
11907e860f15SJohn Edward Broadbent         });
1191cfcd5f6bSMarri Devender Rao 
11927e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1193ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
11940fda0f12SGeorge Liu         .methods(
11950fda0f12SGeorge Liu             boost::beast::http::verb::
11960fda0f12SGeorge Liu                 post)([](const crow::Request& req,
11977e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
11987e860f15SJohn Edward Broadbent             std::string certFileBody =
11997e860f15SJohn Edward Broadbent                 getCertificateFromReqBody(asyncResp, req);
1200a08752f5SZbigniew Kurzynski 
1201a08752f5SZbigniew Kurzynski             if (certFileBody.empty())
1202a08752f5SZbigniew Kurzynski             {
12030fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1204a08752f5SZbigniew Kurzynski                 messages::unrecognizedRequestBody(asyncResp->res);
1205a08752f5SZbigniew Kurzynski                 return;
1206a08752f5SZbigniew Kurzynski             }
1207a08752f5SZbigniew Kurzynski 
1208a08752f5SZbigniew Kurzynski             std::shared_ptr<CertificateFile> certFile =
1209a08752f5SZbigniew Kurzynski                 std::make_shared<CertificateFile>(certFileBody);
1210cfcd5f6bSMarri Devender Rao             crow::connections::systemBus->async_method_call(
1211656ec7e3SZbigniew Kurzynski                 [asyncResp, certFile](const boost::system::error_code ec,
1212656ec7e3SZbigniew Kurzynski                                       const std::string& objectPath) {
1213cfcd5f6bSMarri Devender Rao                     if (ec)
1214cfcd5f6bSMarri Devender Rao                     {
1215cfcd5f6bSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1216cfcd5f6bSMarri Devender Rao                         messages::internalError(asyncResp->res);
1217cfcd5f6bSMarri Devender Rao                         return;
1218cfcd5f6bSMarri Devender Rao                     }
1219656ec7e3SZbigniew Kurzynski                     long certId = getIDFromURL(objectPath);
1220656ec7e3SZbigniew Kurzynski                     if (certId < 0)
1221656ec7e3SZbigniew Kurzynski                     {
1222656ec7e3SZbigniew Kurzynski                         BMCWEB_LOG_ERROR << "Invalid objectPath value"
1223656ec7e3SZbigniew Kurzynski                                          << objectPath;
1224656ec7e3SZbigniew Kurzynski                         messages::internalError(asyncResp->res);
1225656ec7e3SZbigniew Kurzynski                         return;
1226656ec7e3SZbigniew Kurzynski                     }
12270fda0f12SGeorge Liu                     std::string certURL =
12280fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1229cfcd5f6bSMarri Devender Rao                         std::to_string(certId);
1230656ec7e3SZbigniew Kurzynski 
12317e860f15SJohn Edward Broadbent                     getCertificateProperties(
12327e860f15SJohn Edward Broadbent                         asyncResp, objectPath, certs::authorityServiceName,
12337e860f15SJohn Edward Broadbent                         certId, certURL, "TrustStore Certificate");
12340fda0f12SGeorge Liu                     BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1235cfcd5f6bSMarri Devender Rao                                      << certFile->getCertFilePath();
1236cfcd5f6bSMarri Devender Rao                 },
1237cfcd5f6bSMarri Devender Rao                 certs::authorityServiceName, certs::authorityObjectPath,
12380fda0f12SGeorge Liu                 certs::certInstallIntf, "Install", certFile->getCertFilePath());
12397e860f15SJohn Edward Broadbent         });
12407e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificateCollection
1241cfcd5f6bSMarri Devender Rao 
1242cfcd5f6bSMarri Devender Rao /**
1243cfcd5f6bSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
1244cfcd5f6bSMarri Devender Rao  * of a component, account or service.
1245cfcd5f6bSMarri Devender Rao  */
12467e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificate(App& app)
1247cfcd5f6bSMarri Devender Rao {
12487e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1249ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
12507e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
12517e860f15SJohn Edward Broadbent             [](const crow::Request& req,
12527e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12537e860f15SJohn Edward Broadbent                const std::string&) {
1254cfcd5f6bSMarri Devender Rao                 long id = getIDFromURL(req.url);
1255cfcd5f6bSMarri Devender Rao                 if (id < 0)
1256cfcd5f6bSMarri Devender Rao                 {
1257cfcd5f6bSMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
1258cfcd5f6bSMarri Devender Rao                     messages::internalError(asyncResp->res);
1259cfcd5f6bSMarri Devender Rao                     return;
1260cfcd5f6bSMarri Devender Rao                 }
1261cfcd5f6bSMarri Devender Rao                 BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID="
1262cfcd5f6bSMarri Devender Rao                                  << std::to_string(id);
1263cfcd5f6bSMarri Devender Rao                 std::string certURL =
1264cfcd5f6bSMarri Devender Rao                     "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1265cfcd5f6bSMarri Devender Rao                     std::to_string(id);
1266cfcd5f6bSMarri Devender Rao                 std::string objectPath = certs::authorityObjectPath;
1267cfcd5f6bSMarri Devender Rao                 objectPath += "/";
1268cfcd5f6bSMarri Devender Rao                 objectPath += std::to_string(id);
1269cfcd5f6bSMarri Devender Rao                 getCertificateProperties(asyncResp, objectPath,
12707e860f15SJohn Edward Broadbent                                          certs::authorityServiceName, id,
12717e860f15SJohn Edward Broadbent                                          certURL, "TrustStore Certificate");
12727e860f15SJohn Edward Broadbent             });
127307a60299SZbigniew Kurzynski 
12747e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1275ed398213SEd Tanous         .privileges(redfish::privileges::deleteCertificate)
12767e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
12777e860f15SJohn Edward Broadbent             [](const crow::Request& req,
12787e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12797e860f15SJohn Edward Broadbent                const std::string& param) {
12807e860f15SJohn Edward Broadbent                 if (param.empty())
128107a60299SZbigniew Kurzynski                 {
128207a60299SZbigniew Kurzynski                     messages::internalError(asyncResp->res);
128307a60299SZbigniew Kurzynski                     return;
128407a60299SZbigniew Kurzynski                 }
128507a60299SZbigniew Kurzynski 
128607a60299SZbigniew Kurzynski                 long id = getIDFromURL(req.url);
128707a60299SZbigniew Kurzynski                 if (id < 0)
128807a60299SZbigniew Kurzynski                 {
128907a60299SZbigniew Kurzynski                     BMCWEB_LOG_ERROR << "Invalid url value: " << req.url;
12907e860f15SJohn Edward Broadbent                     messages::resourceNotFound(asyncResp->res,
12917e860f15SJohn Edward Broadbent                                                "TrustStore Certificate",
129207a60299SZbigniew Kurzynski                                                std::string(req.url));
129307a60299SZbigniew Kurzynski                     return;
129407a60299SZbigniew Kurzynski                 }
129507a60299SZbigniew Kurzynski                 BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID="
129607a60299SZbigniew Kurzynski                                  << std::to_string(id);
129707a60299SZbigniew Kurzynski                 std::string certPath = certs::authorityObjectPath;
129807a60299SZbigniew Kurzynski                 certPath += "/";
129907a60299SZbigniew Kurzynski                 certPath += std::to_string(id);
130007a60299SZbigniew Kurzynski 
130107a60299SZbigniew Kurzynski                 crow::connections::systemBus->async_method_call(
130207a60299SZbigniew Kurzynski                     [asyncResp, id](const boost::system::error_code ec) {
130307a60299SZbigniew Kurzynski                         if (ec)
130407a60299SZbigniew Kurzynski                         {
130507a60299SZbigniew Kurzynski                             messages::resourceNotFound(asyncResp->res,
130607a60299SZbigniew Kurzynski                                                        "TrustStore Certificate",
130707a60299SZbigniew Kurzynski                                                        std::to_string(id));
130807a60299SZbigniew Kurzynski                             return;
130907a60299SZbigniew Kurzynski                         }
131007a60299SZbigniew Kurzynski                         BMCWEB_LOG_INFO << "Certificate deleted";
13117e860f15SJohn Edward Broadbent                         asyncResp->res.result(
13127e860f15SJohn Edward Broadbent                             boost::beast::http::status::no_content);
131307a60299SZbigniew Kurzynski                     },
131407a60299SZbigniew Kurzynski                     certs::authorityServiceName, certPath, certs::objDeleteIntf,
131507a60299SZbigniew Kurzynski                     "Delete");
13167e860f15SJohn Edward Broadbent             });
13177e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
13185968caeeSMarri Devender Rao } // namespace redfish
1319