xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 0fda0f12bb9ae0604a083dfae419be38a1418913)
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             }
70*0fda0f12SGeorge Liu             asyncResp->res
71*0fda0f12SGeorge Liu                 .jsonValue["Actions"]
72*0fda0f12SGeorge Liu                           ["#CertificateService.ReplaceCertificate"] = {
73*0fda0f12SGeorge Liu                 {"target",
74*0fda0f12SGeorge 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"] = {
78*0fda0f12SGeorge Liu                 {"target",
79*0fda0f12SGeorge 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 {
239*0fda0f12SGeorge Liu     BMCWEB_ROUTE(
240*0fda0f12SGeorge Liu         app,
241*0fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
242ed398213SEd Tanous         // Incorrect Privilege;  Should be ConfigureManager
243ed398213SEd Tanous         //.privileges(redfish::privileges::postCertificateService)
244432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
245*0fda0f12SGeorge Liu         .methods(
246*0fda0f12SGeorge Liu             boost::beast::http::verb::
247*0fda0f12SGeorge 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(
276*0fda0f12SGeorge Liu                     req, asyncResp->res, "City", city, "CommonName", commonName,
277*0fda0f12SGeorge Liu                     "ContactPerson", optContactPerson, "Country", country,
278*0fda0f12SGeorge Liu                     "Organization", organization, "OrganizationalUnit",
279*0fda0f12SGeorge Liu                     organizationalUnit, "State", state, "CertificateCollection",
280*0fda0f12SGeorge Liu                     certificateCollection, "AlternativeNames",
281*0fda0f12SGeorge Liu                     optAlternativeNames, "ChallengePassword",
282*0fda0f12SGeorge Liu                     optChallengePassword, "Email", optEmail, "GivenName",
283*0fda0f12SGeorge Liu                     optGivenName, "Initials", optInitials, "KeyBitLength",
284*0fda0f12SGeorge Liu                     optKeyBitLength, "KeyCurveId", optKeyCurveId,
285*0fda0f12SGeorge Liu                     "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
286*0fda0f12SGeorge Liu                     optKeyUsage, "Surname", optSurname, "UnstructuredName",
287*0fda0f12SGeorge 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;
313*0fda0f12SGeorge Liu             if (boost::starts_with(
314*0fda0f12SGeorge Liu                     certURI,
315*0fda0f12SGeorge 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
335*0fda0f12SGeorge 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
354*0fda0f12SGeorge Liu             if (boost::starts_with(
355*0fda0f12SGeorge Liu                     certURI,
356*0fda0f12SGeorge 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));
416*0fda0f12SGeorge Liu             timeout.async_wait(
417*0fda0f12SGeorge 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;
435*0fda0f12SGeorge 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                     }
452*0fda0f12SGeorge Liu                     std::vector<
453*0fda0f12SGeorge Liu                         std::pair<std::string,
45430215816SMarri Devender Rao                                   std::vector<std::pair<
455*0fda0f12SGeorge 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);
459*0fda0f12SGeorge Liu                     BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
46030215816SMarri Devender Rao                     for (auto& interface : interfacesProperties)
46130215816SMarri Devender Rao                     {
462*0fda0f12SGeorge 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,
484*0fda0f12SGeorge Liu                 *optGivenName, *optInitials, *optKeyBitLength, *optKeyCurveId,
485*0fda0f12SGeorge Liu                 *optKeyPairAlgorithm, *optKeyUsage, organization,
486*0fda0f12SGeorge 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                     {
64637cce918SMarri Devender Rao                         std::time_t time = static_cast<std::time_t>(*value);
6475968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["ValidNotAfter"] =
6485968caeeSMarri Devender Rao                             crow::utility::getDateTime(time);
6495968caeeSMarri Devender Rao                     }
6505968caeeSMarri Devender Rao                 }
6515968caeeSMarri Devender Rao                 else if (property.first == "ValidNotBefore")
6525968caeeSMarri Devender Rao                 {
6535968caeeSMarri Devender Rao                     const uint64_t* value =
6545968caeeSMarri Devender Rao                         std::get_if<uint64_t>(&property.second);
6555968caeeSMarri Devender Rao                     if (value)
6565968caeeSMarri Devender Rao                     {
65737cce918SMarri Devender Rao                         std::time_t time = static_cast<std::time_t>(*value);
6585968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["ValidNotBefore"] =
6595968caeeSMarri Devender Rao                             crow::utility::getDateTime(time);
6605968caeeSMarri Devender Rao                     }
6615968caeeSMarri Devender Rao                 }
6625968caeeSMarri Devender Rao             }
6635968caeeSMarri Devender Rao             asyncResp->res.addHeader("Location", certURL);
6645968caeeSMarri Devender Rao         },
6655968caeeSMarri Devender Rao         service, objectPath, certs::dbusPropIntf, "GetAll",
6665968caeeSMarri Devender Rao         certs::certPropIntf);
6675968caeeSMarri Devender Rao }
6685968caeeSMarri Devender Rao 
6695968caeeSMarri Devender Rao using GetObjectType =
6705968caeeSMarri Devender Rao     std::vector<std::pair<std::string, std::vector<std::string>>>;
6715968caeeSMarri Devender Rao 
6725968caeeSMarri Devender Rao /**
6735968caeeSMarri Devender Rao  * Action to replace an existing certificate
6745968caeeSMarri Devender Rao  */
6757e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionsReplaceCertificate(App& app)
6765968caeeSMarri Devender Rao {
677*0fda0f12SGeorge Liu     BMCWEB_ROUTE(
678*0fda0f12SGeorge Liu         app,
679*0fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
680ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateService)
6817e860f15SJohn Edward Broadbent         .methods(
6827e860f15SJohn Edward Broadbent             boost::beast::http::verb::
6837e860f15SJohn Edward Broadbent                 post)([](const crow::Request& req,
6847e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
6855968caeeSMarri Devender Rao             std::string certificate;
6865968caeeSMarri Devender Rao             nlohmann::json certificateUri;
6875968caeeSMarri Devender Rao             std::optional<std::string> certificateType = "PEM";
6888d1b46d7Szhanghch05 
6895968caeeSMarri Devender Rao             if (!json_util::readJson(req, asyncResp->res, "CertificateString",
6907e860f15SJohn Edward Broadbent                                      certificate, "CertificateUri",
6917e860f15SJohn Edward Broadbent                                      certificateUri, "CertificateType",
6927e860f15SJohn Edward Broadbent                                      certificateType))
6935968caeeSMarri Devender Rao             {
6945968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Required parameters are missing";
6955968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
6965968caeeSMarri Devender Rao                 return;
6975968caeeSMarri Devender Rao             }
6985968caeeSMarri Devender Rao 
6995968caeeSMarri Devender Rao             if (!certificateType)
7005968caeeSMarri Devender Rao             {
7015968caeeSMarri Devender Rao                 // should never happen, but it never hurts to be paranoid.
7025968caeeSMarri Devender Rao                 return;
7035968caeeSMarri Devender Rao             }
7045968caeeSMarri Devender Rao             if (certificateType != "PEM")
7055968caeeSMarri Devender Rao             {
7065968caeeSMarri Devender Rao                 messages::actionParameterNotSupported(
7075968caeeSMarri Devender Rao                     asyncResp->res, "CertificateType", "ReplaceCertificate");
7085968caeeSMarri Devender Rao                 return;
7095968caeeSMarri Devender Rao             }
7105968caeeSMarri Devender Rao 
7115968caeeSMarri Devender Rao             std::string certURI;
7125968caeeSMarri Devender Rao             if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
7135968caeeSMarri Devender Rao                                               "@odata.id", certURI))
7145968caeeSMarri Devender Rao             {
7155968caeeSMarri Devender Rao                 messages::actionParameterMissing(
7165968caeeSMarri Devender Rao                     asyncResp->res, "ReplaceCertificate", "CertificateUri");
7175968caeeSMarri Devender Rao                 return;
7185968caeeSMarri Devender Rao             }
7195968caeeSMarri Devender Rao 
7205968caeeSMarri Devender Rao             BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI;
7215968caeeSMarri Devender Rao             long id = getIDFromURL(certURI);
7225968caeeSMarri Devender Rao             if (id < 0)
7235968caeeSMarri Devender Rao             {
7247e860f15SJohn Edward Broadbent                 messages::actionParameterValueFormatError(
7257e860f15SJohn Edward Broadbent                     asyncResp->res, certURI, "CertificateUri",
7265968caeeSMarri Devender Rao                     "ReplaceCertificate");
7275968caeeSMarri Devender Rao                 return;
7285968caeeSMarri Devender Rao             }
7295968caeeSMarri Devender Rao             std::string objectPath;
7305968caeeSMarri Devender Rao             std::string name;
73137cce918SMarri Devender Rao             std::string service;
732*0fda0f12SGeorge Liu             if (boost::starts_with(
733*0fda0f12SGeorge Liu                     certURI,
734*0fda0f12SGeorge Liu                     "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"))
7355968caeeSMarri Devender Rao             {
7367e860f15SJohn Edward Broadbent                 objectPath = std::string(certs::httpsObjectPath) + "/" +
7377e860f15SJohn Edward Broadbent                              std::to_string(id);
7385968caeeSMarri Devender Rao                 name = "HTTPS certificate";
73937cce918SMarri Devender Rao                 service = certs::httpsServiceName;
74037cce918SMarri Devender Rao             }
74137cce918SMarri Devender Rao             else if (boost::starts_with(
7427e860f15SJohn Edward Broadbent                          certURI,
7437e860f15SJohn Edward Broadbent                          "/redfish/v1/AccountService/LDAP/Certificates/"))
74437cce918SMarri Devender Rao             {
7457e860f15SJohn Edward Broadbent                 objectPath = std::string(certs::ldapObjectPath) + "/" +
7467e860f15SJohn Edward Broadbent                              std::to_string(id);
74737cce918SMarri Devender Rao                 name = "LDAP certificate";
74837cce918SMarri Devender Rao                 service = certs::ldapServiceName;
7495968caeeSMarri Devender Rao             }
750cfcd5f6bSMarri Devender Rao             else if (boost::starts_with(
751cfcd5f6bSMarri Devender Rao                          certURI,
752cfcd5f6bSMarri Devender Rao                          "/redfish/v1/Managers/bmc/Truststore/Certificates/"))
753cfcd5f6bSMarri Devender Rao             {
754cfcd5f6bSMarri Devender Rao                 objectPath = std::string(certs::authorityObjectPath) + "/" +
755cfcd5f6bSMarri Devender Rao                              std::to_string(id);
756cfcd5f6bSMarri Devender Rao                 name = "TrustStore certificate";
757cfcd5f6bSMarri Devender Rao                 service = certs::authorityServiceName;
758cfcd5f6bSMarri Devender Rao             }
7595968caeeSMarri Devender Rao             else
7605968caeeSMarri Devender Rao             {
7615968caeeSMarri Devender Rao                 messages::actionParameterNotSupported(
7625968caeeSMarri Devender Rao                     asyncResp->res, "CertificateUri", "ReplaceCertificate");
7635968caeeSMarri Devender Rao                 return;
7645968caeeSMarri Devender Rao             }
7655968caeeSMarri Devender Rao 
7665968caeeSMarri Devender Rao             std::shared_ptr<CertificateFile> certFile =
7675968caeeSMarri Devender Rao                 std::make_shared<CertificateFile>(certificate);
7685968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
76937cce918SMarri Devender Rao                 [asyncResp, certFile, objectPath, service, certURI, id,
7705968caeeSMarri Devender Rao                  name](const boost::system::error_code ec) {
7715968caeeSMarri Devender Rao                     if (ec)
7725968caeeSMarri Devender Rao                     {
7735968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
7748aae75adSMarri Devender Rao                         messages::resourceNotFound(asyncResp->res, name,
7758aae75adSMarri Devender Rao                                                    std::to_string(id));
7765968caeeSMarri Devender Rao                         return;
7775968caeeSMarri Devender Rao                     }
77837cce918SMarri Devender Rao                     getCertificateProperties(asyncResp, objectPath, service, id,
7795968caeeSMarri Devender Rao                                              certURI, name);
7805968caeeSMarri Devender Rao                     BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
7815968caeeSMarri Devender Rao                                      << certFile->getCertFilePath();
7825968caeeSMarri Devender Rao                 },
7835968caeeSMarri Devender Rao                 service, objectPath, certs::certReplaceIntf, "Replace",
7845968caeeSMarri Devender Rao                 certFile->getCertFilePath());
7857e860f15SJohn Edward Broadbent         });
7867e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionsReplaceCertificate
7875968caeeSMarri Devender Rao 
7885968caeeSMarri Devender Rao /**
7895968caeeSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
7905968caeeSMarri Devender Rao  * of a component, account or service.
7915968caeeSMarri Devender Rao  */
7925968caeeSMarri Devender Rao 
7937e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificate(App& app)
7945968caeeSMarri Devender Rao {
7957e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
7967e860f15SJohn Edward Broadbent         app,
7977e860f15SJohn Edward Broadbent         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
798ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
7997e860f15SJohn Edward Broadbent         .methods(
8007e860f15SJohn Edward Broadbent             boost::beast::http::verb::
8017e860f15SJohn Edward Broadbent                 get)([](const crow::Request& req,
8027e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8037e860f15SJohn Edward Broadbent                         const std::string& param) -> void {
8047e860f15SJohn Edward Broadbent             if (param.empty())
8055968caeeSMarri Devender Rao             {
8065968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
8075968caeeSMarri Devender Rao                 return;
8085968caeeSMarri Devender Rao             }
8095968caeeSMarri Devender Rao             long id = getIDFromURL(req.url);
8105968caeeSMarri Devender Rao 
8117e860f15SJohn Edward Broadbent             BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID="
8127e860f15SJohn Edward Broadbent                              << std::to_string(id);
8135968caeeSMarri Devender Rao             std::string certURL =
8145968caeeSMarri Devender Rao                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8155968caeeSMarri Devender Rao                 std::to_string(id);
8165968caeeSMarri Devender Rao             std::string objectPath = certs::httpsObjectPath;
8175968caeeSMarri Devender Rao             objectPath += "/";
8185968caeeSMarri Devender Rao             objectPath += std::to_string(id);
8197e860f15SJohn Edward Broadbent             getCertificateProperties(asyncResp, objectPath,
8207e860f15SJohn Edward Broadbent                                      certs::httpsServiceName, id, certURL,
8217e860f15SJohn Edward Broadbent                                      "HTTPS Certificate");
8227e860f15SJohn Edward Broadbent         });
8235968caeeSMarri Devender Rao }
8245968caeeSMarri Devender Rao 
8255968caeeSMarri Devender Rao /**
8265968caeeSMarri Devender Rao  * Collection of HTTPS certificates
8275968caeeSMarri Devender Rao  */
8287e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificateCollection(App& app)
8295968caeeSMarri Devender Rao {
8307e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8315968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
832ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
8337e860f15SJohn Edward Broadbent         .methods(
8347e860f15SJohn Edward Broadbent             boost::beast::http::verb::
8357e860f15SJohn Edward Broadbent                 get)([](const crow::Request&,
8367e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8378d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
8385968caeeSMarri Devender Rao                 {"@odata.id",
8395968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"},
8405968caeeSMarri Devender Rao                 {"@odata.type", "#CertificateCollection.CertificateCollection"},
8415968caeeSMarri Devender Rao                 {"Name", "HTTPS Certificates Collection"},
8425968caeeSMarri Devender Rao                 {"Description", "A Collection of HTTPS certificate instances"}};
8438d1b46d7Szhanghch05 
8445968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
8455968caeeSMarri Devender Rao                 [asyncResp](const boost::system::error_code ec,
8465968caeeSMarri Devender Rao                             const ManagedObjectType& certs) {
8475968caeeSMarri Devender Rao                     if (ec)
8485968caeeSMarri Devender Rao                     {
8495968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
8505968caeeSMarri Devender Rao                         messages::internalError(asyncResp->res);
8515968caeeSMarri Devender Rao                         return;
8525968caeeSMarri Devender Rao                     }
8537e860f15SJohn Edward Broadbent                     nlohmann::json& members =
8547e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
8555968caeeSMarri Devender Rao                     members = nlohmann::json::array();
8565968caeeSMarri Devender Rao                     for (const auto& cert : certs)
8575968caeeSMarri Devender Rao                     {
8585968caeeSMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
85937cce918SMarri Devender Rao                         if (id >= 0)
8605968caeeSMarri Devender Rao                         {
8615968caeeSMarri Devender Rao                             members.push_back(
8625968caeeSMarri Devender Rao                                 {{"@odata.id",
863*0fda0f12SGeorge Liu                                   "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8645968caeeSMarri Devender Rao                                       std::to_string(id)}});
8655968caeeSMarri Devender Rao                         }
8665968caeeSMarri Devender Rao                     }
8675968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["Members@odata.count"] =
8685968caeeSMarri Devender Rao                         members.size();
8695968caeeSMarri Devender Rao                 },
87037cce918SMarri Devender Rao                 certs::httpsServiceName, certs::httpsObjectPath,
87137cce918SMarri Devender Rao                 certs::dbusObjManagerIntf, "GetManagedObjects");
8727e860f15SJohn Edward Broadbent         });
8735968caeeSMarri Devender Rao 
8747e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8757e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
876ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
877*0fda0f12SGeorge Liu         .methods(
878*0fda0f12SGeorge Liu             boost::beast::http::verb::
879*0fda0f12SGeorge Liu                 post)([](const crow::Request& req,
8807e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8815968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
8828d1b46d7Szhanghch05 
883*0fda0f12SGeorge Liu             asyncResp->res.jsonValue = {{"Name", "HTTPS Certificate"},
8845968caeeSMarri Devender Rao                                         {"Description", "HTTPS Certificate"}};
8855968caeeSMarri Devender Rao 
8867e860f15SJohn Edward Broadbent             std::string certFileBody =
8877e860f15SJohn Edward Broadbent                 getCertificateFromReqBody(asyncResp, req);
88858eb238fSKowalski, Kamil 
88958eb238fSKowalski, Kamil             if (certFileBody.empty())
89058eb238fSKowalski, Kamil             {
891*0fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
892a08752f5SZbigniew Kurzynski                 messages::unrecognizedRequestBody(asyncResp->res);
89358eb238fSKowalski, Kamil                 return;
89458eb238fSKowalski, Kamil             }
89558eb238fSKowalski, Kamil 
8965968caeeSMarri Devender Rao             std::shared_ptr<CertificateFile> certFile =
89758eb238fSKowalski, Kamil                 std::make_shared<CertificateFile>(certFileBody);
8985968caeeSMarri Devender Rao 
8995968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
900656ec7e3SZbigniew Kurzynski                 [asyncResp, certFile](const boost::system::error_code ec,
901656ec7e3SZbigniew Kurzynski                                       const std::string& objectPath) {
9025968caeeSMarri Devender Rao                     if (ec)
9035968caeeSMarri Devender Rao                     {
9045968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9055968caeeSMarri Devender Rao                         messages::internalError(asyncResp->res);
9065968caeeSMarri Devender Rao                         return;
9075968caeeSMarri Devender Rao                     }
908656ec7e3SZbigniew Kurzynski                     long certId = getIDFromURL(objectPath);
909656ec7e3SZbigniew Kurzynski                     if (certId < 0)
910656ec7e3SZbigniew Kurzynski                     {
911656ec7e3SZbigniew Kurzynski                         BMCWEB_LOG_ERROR << "Invalid objectPath value"
912656ec7e3SZbigniew Kurzynski                                          << objectPath;
913656ec7e3SZbigniew Kurzynski                         messages::internalError(asyncResp->res);
914656ec7e3SZbigniew Kurzynski                         return;
915656ec7e3SZbigniew Kurzynski                     }
9165968caeeSMarri Devender Rao                     std::string certURL =
917*0fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
9185968caeeSMarri Devender Rao                         std::to_string(certId);
919*0fda0f12SGeorge Liu                     getCertificateProperties(asyncResp, objectPath,
920*0fda0f12SGeorge Liu                                              certs::httpsServiceName, certId,
921*0fda0f12SGeorge Liu                                              certURL, "HTTPS Certificate");
9225968caeeSMarri Devender Rao                     BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9235968caeeSMarri Devender Rao                                      << certFile->getCertFilePath();
9245968caeeSMarri Devender Rao                 },
92537cce918SMarri Devender Rao                 certs::httpsServiceName, certs::httpsObjectPath,
926*0fda0f12SGeorge Liu                 certs::certInstallIntf, "Install", certFile->getCertFilePath());
9277e860f15SJohn Edward Broadbent         });
9287e860f15SJohn Edward Broadbent } // requestRoutesHTTPSCertificateCollection
9295968caeeSMarri Devender Rao 
9305968caeeSMarri Devender Rao /**
93137cce918SMarri Devender Rao  * @brief Retrieve the certificates installed list and append to the
93237cce918SMarri Devender Rao  * response
93337cce918SMarri Devender Rao  *
93437cce918SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
93537cce918SMarri Devender Rao  * @param[in] certURL  Path of the certificate object
93637cce918SMarri Devender Rao  * @param[in] path  Path of the D-Bus service object
93737cce918SMarri Devender Rao  * @return None
93837cce918SMarri Devender Rao  */
9394f48d5f6SEd Tanous inline void
9404f48d5f6SEd Tanous     getCertificateLocations(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9418d1b46d7Szhanghch05                             const std::string& certURL, const std::string& path,
94237cce918SMarri Devender Rao                             const std::string& service)
94337cce918SMarri Devender Rao {
94437cce918SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL
94537cce918SMarri Devender Rao                      << " Path=" << path << " service= " << service;
94637cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
94737cce918SMarri Devender Rao         [asyncResp, certURL](const boost::system::error_code ec,
94837cce918SMarri Devender Rao                              const ManagedObjectType& certs) {
94937cce918SMarri Devender Rao             if (ec)
95037cce918SMarri Devender Rao             {
9519c8e039eSJonathan Doman                 BMCWEB_LOG_WARNING
9529c8e039eSJonathan Doman                     << "Certificate collection query failed: " << ec
9539c8e039eSJonathan Doman                     << ", skipping " << certURL;
95437cce918SMarri Devender Rao                 return;
95537cce918SMarri Devender Rao             }
95637cce918SMarri Devender Rao             nlohmann::json& links =
95737cce918SMarri Devender Rao                 asyncResp->res.jsonValue["Links"]["Certificates"];
95837cce918SMarri Devender Rao             for (auto& cert : certs)
95937cce918SMarri Devender Rao             {
96037cce918SMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
96137cce918SMarri Devender Rao                 if (id >= 0)
96237cce918SMarri Devender Rao                 {
96337cce918SMarri Devender Rao                     links.push_back(
96437cce918SMarri Devender Rao                         {{"@odata.id", certURL + std::to_string(id)}});
96537cce918SMarri Devender Rao                 }
96637cce918SMarri Devender Rao             }
96737cce918SMarri Devender Rao             asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] =
96837cce918SMarri Devender Rao                 links.size();
96937cce918SMarri Devender Rao         },
97037cce918SMarri Devender Rao         service, path, certs::dbusObjManagerIntf, "GetManagedObjects");
9715968caeeSMarri Devender Rao }
9727e860f15SJohn Edward Broadbent 
9737e860f15SJohn Edward Broadbent /**
9747e860f15SJohn Edward Broadbent  * The certificate location schema defines a resource that an administrator
9757e860f15SJohn Edward Broadbent  * can use in order to locate all certificates installed on a given service.
9767e860f15SJohn Edward Broadbent  */
9777e860f15SJohn Edward Broadbent inline void requestRoutesCertificateLocations(App& app)
9787e860f15SJohn Edward Broadbent {
9797e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
980ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateLocations)
9817e860f15SJohn Edward Broadbent         .methods(
9827e860f15SJohn Edward Broadbent             boost::beast::http::verb::
9837e860f15SJohn Edward Broadbent                 get)([](const crow::Request&,
9847e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
9857e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue = {
9867e860f15SJohn Edward Broadbent                 {"@odata.id",
9877e860f15SJohn Edward Broadbent                  "/redfish/v1/CertificateService/CertificateLocations"},
9887e860f15SJohn Edward Broadbent                 {"@odata.type",
9897e860f15SJohn Edward Broadbent                  "#CertificateLocations.v1_0_0.CertificateLocations"},
9907e860f15SJohn Edward Broadbent                 {"Name", "Certificate Locations"},
9917e860f15SJohn Edward Broadbent                 {"Id", "CertificateLocations"},
9927e860f15SJohn Edward Broadbent                 {"Description",
9937e860f15SJohn Edward Broadbent                  "Defines a resource that an administrator can use in order to "
9947e860f15SJohn Edward Broadbent                  "locate all certificates installed on a given service"}};
9957e860f15SJohn Edward Broadbent 
9967e860f15SJohn Edward Broadbent             nlohmann::json& links =
9977e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Links"]["Certificates"];
9987e860f15SJohn Edward Broadbent             links = nlohmann::json::array();
9997e860f15SJohn Edward Broadbent             getCertificateLocations(
10007e860f15SJohn Edward Broadbent                 asyncResp,
10017e860f15SJohn Edward Broadbent                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/",
10027e860f15SJohn Edward Broadbent                 certs::httpsObjectPath, certs::httpsServiceName);
10037e860f15SJohn Edward Broadbent             getCertificateLocations(
10047e860f15SJohn Edward Broadbent                 asyncResp, "/redfish/v1/AccountService/LDAP/Certificates/",
10057e860f15SJohn Edward Broadbent                 certs::ldapObjectPath, certs::ldapServiceName);
10067e860f15SJohn Edward Broadbent             getCertificateLocations(
10077e860f15SJohn Edward Broadbent                 asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/",
10087e860f15SJohn Edward Broadbent                 certs::authorityObjectPath, certs::authorityServiceName);
10097e860f15SJohn Edward Broadbent         });
10107e860f15SJohn Edward Broadbent }
10117e860f15SJohn Edward Broadbent // requestRoutesCertificateLocations
101237cce918SMarri Devender Rao 
101337cce918SMarri Devender Rao /**
101437cce918SMarri Devender Rao  * Collection of LDAP certificates
101537cce918SMarri Devender Rao  */
10167e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificateCollection(App& app)
101737cce918SMarri Devender Rao {
10187e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1019ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
1020*0fda0f12SGeorge Liu         .methods(
1021*0fda0f12SGeorge Liu             boost::beast::http::verb::
1022*0fda0f12SGeorge Liu                 get)([](const crow::Request&,
10237e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10248d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
1025*0fda0f12SGeorge Liu                 {"@odata.id", "/redfish/v1/AccountService/LDAP/Certificates"},
1026*0fda0f12SGeorge Liu                 {"@odata.type", "#CertificateCollection.CertificateCollection"},
102737cce918SMarri Devender Rao                 {"Name", "LDAP Certificates Collection"},
1028*0fda0f12SGeorge Liu                 {"Description", "A Collection of LDAP certificate instances"}};
10298d1b46d7Szhanghch05 
103037cce918SMarri Devender Rao             crow::connections::systemBus->async_method_call(
103137cce918SMarri Devender Rao                 [asyncResp](const boost::system::error_code ec,
103237cce918SMarri Devender Rao                             const ManagedObjectType& certs) {
10337e860f15SJohn Edward Broadbent                     nlohmann::json& members =
10347e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
10359c8e039eSJonathan Doman                     nlohmann::json& count =
10369c8e039eSJonathan Doman                         asyncResp->res.jsonValue["Members@odata.count"];
10379c8e039eSJonathan Doman                     members = nlohmann::json::array();
10389c8e039eSJonathan Doman                     count = 0;
103937cce918SMarri Devender Rao                     if (ec)
104037cce918SMarri Devender Rao                     {
1041*0fda0f12SGeorge Liu                         BMCWEB_LOG_WARNING << "LDAP certificate query failed: "
1042*0fda0f12SGeorge Liu                                            << ec;
104337cce918SMarri Devender Rao                         return;
104437cce918SMarri Devender Rao                     }
104537cce918SMarri Devender Rao                     for (const auto& cert : certs)
104637cce918SMarri Devender Rao                     {
104737cce918SMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
104837cce918SMarri Devender Rao                         if (id >= 0)
104937cce918SMarri Devender Rao                         {
105037cce918SMarri Devender Rao                             members.push_back(
1051*0fda0f12SGeorge Liu                                 {{"@odata.id",
1052*0fda0f12SGeorge Liu                                   "/redfish/v1/AccountService/LDAP/Certificates/" +
105337cce918SMarri Devender Rao                                       std::to_string(id)}});
105437cce918SMarri Devender Rao                         }
105537cce918SMarri Devender Rao                     }
10569c8e039eSJonathan Doman                     count = members.size();
105737cce918SMarri Devender Rao                 },
105837cce918SMarri Devender Rao                 certs::ldapServiceName, certs::ldapObjectPath,
105937cce918SMarri Devender Rao                 certs::dbusObjManagerIntf, "GetManagedObjects");
10607e860f15SJohn Edward Broadbent         });
106137cce918SMarri Devender Rao 
10627e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1063ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
10647e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
10657e860f15SJohn Edward Broadbent             [](const crow::Request& req,
10667e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10677e860f15SJohn Edward Broadbent                 std::string certFileBody =
10687e860f15SJohn Edward Broadbent                     getCertificateFromReqBody(asyncResp, req);
106958eb238fSKowalski, Kamil 
107058eb238fSKowalski, Kamil                 if (certFileBody.empty())
107158eb238fSKowalski, Kamil                 {
10727e860f15SJohn Edward Broadbent                     BMCWEB_LOG_ERROR
10737e860f15SJohn Edward Broadbent                         << "Cannot get certificate from request body.";
1074a08752f5SZbigniew Kurzynski                     messages::unrecognizedRequestBody(asyncResp->res);
107558eb238fSKowalski, Kamil                     return;
107658eb238fSKowalski, Kamil                 }
107758eb238fSKowalski, Kamil 
107858eb238fSKowalski, Kamil                 std::shared_ptr<CertificateFile> certFile =
107958eb238fSKowalski, Kamil                     std::make_shared<CertificateFile>(certFileBody);
108058eb238fSKowalski, Kamil 
108137cce918SMarri Devender Rao                 crow::connections::systemBus->async_method_call(
1082656ec7e3SZbigniew Kurzynski                     [asyncResp, certFile](const boost::system::error_code ec,
1083656ec7e3SZbigniew Kurzynski                                           const std::string& objectPath) {
108437cce918SMarri Devender Rao                         if (ec)
108537cce918SMarri Devender Rao                         {
108637cce918SMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
108737cce918SMarri Devender Rao                             messages::internalError(asyncResp->res);
108837cce918SMarri Devender Rao                             return;
108937cce918SMarri Devender Rao                         }
1090656ec7e3SZbigniew Kurzynski                         long certId = getIDFromURL(objectPath);
1091656ec7e3SZbigniew Kurzynski                         if (certId < 0)
1092656ec7e3SZbigniew Kurzynski                         {
1093656ec7e3SZbigniew Kurzynski                             BMCWEB_LOG_ERROR << "Invalid objectPath value"
1094656ec7e3SZbigniew Kurzynski                                              << objectPath;
1095656ec7e3SZbigniew Kurzynski                             messages::internalError(asyncResp->res);
1096656ec7e3SZbigniew Kurzynski                             return;
1097656ec7e3SZbigniew Kurzynski                         }
109837cce918SMarri Devender Rao                         std::string certURL =
109937cce918SMarri Devender Rao                             "/redfish/v1/AccountService/LDAP/Certificates/" +
110037cce918SMarri Devender Rao                             std::to_string(certId);
110137cce918SMarri Devender Rao                         getCertificateProperties(asyncResp, objectPath,
110237cce918SMarri Devender Rao                                                  certs::ldapServiceName, certId,
110337cce918SMarri Devender Rao                                                  certURL, "LDAP Certificate");
110437cce918SMarri Devender Rao                         BMCWEB_LOG_DEBUG << "LDAP certificate install file="
110537cce918SMarri Devender Rao                                          << certFile->getCertFilePath();
110637cce918SMarri Devender Rao                     },
110737cce918SMarri Devender Rao                     certs::ldapServiceName, certs::ldapObjectPath,
11087e860f15SJohn Edward Broadbent                     certs::certInstallIntf, "Install",
11097e860f15SJohn Edward Broadbent                     certFile->getCertFilePath());
11107e860f15SJohn Edward Broadbent             });
11117e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificateCollection
111237cce918SMarri Devender Rao 
111337cce918SMarri Devender Rao /**
111437cce918SMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
111537cce918SMarri Devender Rao  * of a component, account or service.
111637cce918SMarri Devender Rao  */
11177e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificate(App& app)
111837cce918SMarri Devender Rao {
11197e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1120ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
11217e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
11227e860f15SJohn Edward Broadbent             [](const crow::Request& req,
11237e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11247e860f15SJohn Edward Broadbent                const std::string&) {
112537cce918SMarri Devender Rao                 long id = getIDFromURL(req.url);
112637cce918SMarri Devender Rao                 if (id < 0)
112737cce918SMarri Devender Rao                 {
112837cce918SMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
112937cce918SMarri Devender Rao                     messages::internalError(asyncResp->res);
113037cce918SMarri Devender Rao                     return;
113137cce918SMarri Devender Rao                 }
11327e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG << "LDAP Certificate ID="
11337e860f15SJohn Edward Broadbent                                  << std::to_string(id);
11347e860f15SJohn Edward Broadbent                 std::string certURL =
11357e860f15SJohn Edward Broadbent                     "/redfish/v1/AccountService/LDAP/Certificates/" +
113637cce918SMarri Devender Rao                     std::to_string(id);
113737cce918SMarri Devender Rao                 std::string objectPath = certs::ldapObjectPath;
113837cce918SMarri Devender Rao                 objectPath += "/";
113937cce918SMarri Devender Rao                 objectPath += std::to_string(id);
11407e860f15SJohn Edward Broadbent                 getCertificateProperties(asyncResp, objectPath,
11417e860f15SJohn Edward Broadbent                                          certs::ldapServiceName, id, certURL,
11427e860f15SJohn Edward Broadbent                                          "LDAP Certificate");
11437e860f15SJohn Edward Broadbent             });
11447e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificate
1145cfcd5f6bSMarri Devender Rao /**
1146cfcd5f6bSMarri Devender Rao  * Collection of TrustStoreCertificate certificates
1147cfcd5f6bSMarri Devender Rao  */
11487e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificateCollection(App& app)
1149cfcd5f6bSMarri Devender Rao {
11507e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1151ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1152*0fda0f12SGeorge Liu         .methods(
1153*0fda0f12SGeorge Liu             boost::beast::http::verb::
1154*0fda0f12SGeorge Liu                 get)([](const crow::Request&,
11557e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
11568d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
11577e860f15SJohn Edward Broadbent                 {"@odata.id",
11587e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/Truststore/Certificates/"},
1159*0fda0f12SGeorge Liu                 {"@odata.type", "#CertificateCollection.CertificateCollection"},
1160cfcd5f6bSMarri Devender Rao                 {"Name", "TrustStore Certificates Collection"},
1161cfcd5f6bSMarri Devender Rao                 {"Description",
1162cfcd5f6bSMarri Devender Rao                  "A Collection of TrustStore certificate instances"}};
11638d1b46d7Szhanghch05 
1164cfcd5f6bSMarri Devender Rao             crow::connections::systemBus->async_method_call(
1165cfcd5f6bSMarri Devender Rao                 [asyncResp](const boost::system::error_code ec,
1166cfcd5f6bSMarri Devender Rao                             const ManagedObjectType& certs) {
1167cfcd5f6bSMarri Devender Rao                     if (ec)
1168cfcd5f6bSMarri Devender Rao                     {
1169cfcd5f6bSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1170cfcd5f6bSMarri Devender Rao                         messages::internalError(asyncResp->res);
1171cfcd5f6bSMarri Devender Rao                         return;
1172cfcd5f6bSMarri Devender Rao                     }
11737e860f15SJohn Edward Broadbent                     nlohmann::json& members =
11747e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
1175cfcd5f6bSMarri Devender Rao                     members = nlohmann::json::array();
1176cfcd5f6bSMarri Devender Rao                     for (const auto& cert : certs)
1177cfcd5f6bSMarri Devender Rao                     {
1178cfcd5f6bSMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
1179cfcd5f6bSMarri Devender Rao                         if (id >= 0)
1180cfcd5f6bSMarri Devender Rao                         {
1181cfcd5f6bSMarri Devender Rao                             members.push_back(
1182*0fda0f12SGeorge Liu                                 {{"@odata.id",
1183*0fda0f12SGeorge Liu                                   "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1184cfcd5f6bSMarri Devender Rao                                       std::to_string(id)}});
1185cfcd5f6bSMarri Devender Rao                         }
1186cfcd5f6bSMarri Devender Rao                     }
1187cfcd5f6bSMarri Devender Rao                     asyncResp->res.jsonValue["Members@odata.count"] =
1188cfcd5f6bSMarri Devender Rao                         members.size();
1189cfcd5f6bSMarri Devender Rao                 },
1190cfcd5f6bSMarri Devender Rao                 certs::authorityServiceName, certs::authorityObjectPath,
1191cfcd5f6bSMarri Devender Rao                 certs::dbusObjManagerIntf, "GetManagedObjects");
11927e860f15SJohn Edward Broadbent         });
1193cfcd5f6bSMarri Devender Rao 
11947e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1195ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
1196*0fda0f12SGeorge Liu         .methods(
1197*0fda0f12SGeorge Liu             boost::beast::http::verb::
1198*0fda0f12SGeorge Liu                 post)([](const crow::Request& req,
11997e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
12007e860f15SJohn Edward Broadbent             std::string certFileBody =
12017e860f15SJohn Edward Broadbent                 getCertificateFromReqBody(asyncResp, req);
1202a08752f5SZbigniew Kurzynski 
1203a08752f5SZbigniew Kurzynski             if (certFileBody.empty())
1204a08752f5SZbigniew Kurzynski             {
1205*0fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1206a08752f5SZbigniew Kurzynski                 messages::unrecognizedRequestBody(asyncResp->res);
1207a08752f5SZbigniew Kurzynski                 return;
1208a08752f5SZbigniew Kurzynski             }
1209a08752f5SZbigniew Kurzynski 
1210a08752f5SZbigniew Kurzynski             std::shared_ptr<CertificateFile> certFile =
1211a08752f5SZbigniew Kurzynski                 std::make_shared<CertificateFile>(certFileBody);
1212cfcd5f6bSMarri Devender Rao             crow::connections::systemBus->async_method_call(
1213656ec7e3SZbigniew Kurzynski                 [asyncResp, certFile](const boost::system::error_code ec,
1214656ec7e3SZbigniew Kurzynski                                       const std::string& objectPath) {
1215cfcd5f6bSMarri Devender Rao                     if (ec)
1216cfcd5f6bSMarri Devender Rao                     {
1217cfcd5f6bSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1218cfcd5f6bSMarri Devender Rao                         messages::internalError(asyncResp->res);
1219cfcd5f6bSMarri Devender Rao                         return;
1220cfcd5f6bSMarri Devender Rao                     }
1221656ec7e3SZbigniew Kurzynski                     long certId = getIDFromURL(objectPath);
1222656ec7e3SZbigniew Kurzynski                     if (certId < 0)
1223656ec7e3SZbigniew Kurzynski                     {
1224656ec7e3SZbigniew Kurzynski                         BMCWEB_LOG_ERROR << "Invalid objectPath value"
1225656ec7e3SZbigniew Kurzynski                                          << objectPath;
1226656ec7e3SZbigniew Kurzynski                         messages::internalError(asyncResp->res);
1227656ec7e3SZbigniew Kurzynski                         return;
1228656ec7e3SZbigniew Kurzynski                     }
1229*0fda0f12SGeorge Liu                     std::string certURL =
1230*0fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1231cfcd5f6bSMarri Devender Rao                         std::to_string(certId);
1232656ec7e3SZbigniew Kurzynski 
12337e860f15SJohn Edward Broadbent                     getCertificateProperties(
12347e860f15SJohn Edward Broadbent                         asyncResp, objectPath, certs::authorityServiceName,
12357e860f15SJohn Edward Broadbent                         certId, certURL, "TrustStore Certificate");
1236*0fda0f12SGeorge Liu                     BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1237cfcd5f6bSMarri Devender Rao                                      << certFile->getCertFilePath();
1238cfcd5f6bSMarri Devender Rao                 },
1239cfcd5f6bSMarri Devender Rao                 certs::authorityServiceName, certs::authorityObjectPath,
1240*0fda0f12SGeorge Liu                 certs::certInstallIntf, "Install", certFile->getCertFilePath());
12417e860f15SJohn Edward Broadbent         });
12427e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificateCollection
1243cfcd5f6bSMarri Devender Rao 
1244cfcd5f6bSMarri Devender Rao /**
1245cfcd5f6bSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
1246cfcd5f6bSMarri Devender Rao  * of a component, account or service.
1247cfcd5f6bSMarri Devender Rao  */
12487e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificate(App& app)
1249cfcd5f6bSMarri Devender Rao {
12507e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1251ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
12527e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
12537e860f15SJohn Edward Broadbent             [](const crow::Request& req,
12547e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12557e860f15SJohn Edward Broadbent                const std::string&) {
1256cfcd5f6bSMarri Devender Rao                 long id = getIDFromURL(req.url);
1257cfcd5f6bSMarri Devender Rao                 if (id < 0)
1258cfcd5f6bSMarri Devender Rao                 {
1259cfcd5f6bSMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
1260cfcd5f6bSMarri Devender Rao                     messages::internalError(asyncResp->res);
1261cfcd5f6bSMarri Devender Rao                     return;
1262cfcd5f6bSMarri Devender Rao                 }
1263cfcd5f6bSMarri Devender Rao                 BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID="
1264cfcd5f6bSMarri Devender Rao                                  << std::to_string(id);
1265cfcd5f6bSMarri Devender Rao                 std::string certURL =
1266cfcd5f6bSMarri Devender Rao                     "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1267cfcd5f6bSMarri Devender Rao                     std::to_string(id);
1268cfcd5f6bSMarri Devender Rao                 std::string objectPath = certs::authorityObjectPath;
1269cfcd5f6bSMarri Devender Rao                 objectPath += "/";
1270cfcd5f6bSMarri Devender Rao                 objectPath += std::to_string(id);
1271cfcd5f6bSMarri Devender Rao                 getCertificateProperties(asyncResp, objectPath,
12727e860f15SJohn Edward Broadbent                                          certs::authorityServiceName, id,
12737e860f15SJohn Edward Broadbent                                          certURL, "TrustStore Certificate");
12747e860f15SJohn Edward Broadbent             });
127507a60299SZbigniew Kurzynski 
12767e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1277ed398213SEd Tanous         .privileges(redfish::privileges::deleteCertificate)
12787e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
12797e860f15SJohn Edward Broadbent             [](const crow::Request& req,
12807e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12817e860f15SJohn Edward Broadbent                const std::string& param) {
12827e860f15SJohn Edward Broadbent                 if (param.empty())
128307a60299SZbigniew Kurzynski                 {
128407a60299SZbigniew Kurzynski                     messages::internalError(asyncResp->res);
128507a60299SZbigniew Kurzynski                     return;
128607a60299SZbigniew Kurzynski                 }
128707a60299SZbigniew Kurzynski 
128807a60299SZbigniew Kurzynski                 long id = getIDFromURL(req.url);
128907a60299SZbigniew Kurzynski                 if (id < 0)
129007a60299SZbigniew Kurzynski                 {
129107a60299SZbigniew Kurzynski                     BMCWEB_LOG_ERROR << "Invalid url value: " << req.url;
12927e860f15SJohn Edward Broadbent                     messages::resourceNotFound(asyncResp->res,
12937e860f15SJohn Edward Broadbent                                                "TrustStore Certificate",
129407a60299SZbigniew Kurzynski                                                std::string(req.url));
129507a60299SZbigniew Kurzynski                     return;
129607a60299SZbigniew Kurzynski                 }
129707a60299SZbigniew Kurzynski                 BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID="
129807a60299SZbigniew Kurzynski                                  << std::to_string(id);
129907a60299SZbigniew Kurzynski                 std::string certPath = certs::authorityObjectPath;
130007a60299SZbigniew Kurzynski                 certPath += "/";
130107a60299SZbigniew Kurzynski                 certPath += std::to_string(id);
130207a60299SZbigniew Kurzynski 
130307a60299SZbigniew Kurzynski                 crow::connections::systemBus->async_method_call(
130407a60299SZbigniew Kurzynski                     [asyncResp, id](const boost::system::error_code ec) {
130507a60299SZbigniew Kurzynski                         if (ec)
130607a60299SZbigniew Kurzynski                         {
130707a60299SZbigniew Kurzynski                             messages::resourceNotFound(asyncResp->res,
130807a60299SZbigniew Kurzynski                                                        "TrustStore Certificate",
130907a60299SZbigniew Kurzynski                                                        std::to_string(id));
131007a60299SZbigniew Kurzynski                             return;
131107a60299SZbigniew Kurzynski                         }
131207a60299SZbigniew Kurzynski                         BMCWEB_LOG_INFO << "Certificate deleted";
13137e860f15SJohn Edward Broadbent                         asyncResp->res.result(
13147e860f15SJohn Edward Broadbent                             boost::beast::http::status::no_content);
131507a60299SZbigniew Kurzynski                     },
131607a60299SZbigniew Kurzynski                     certs::authorityServiceName, certPath, certs::objDeleteIntf,
131707a60299SZbigniew Kurzynski                     "Delete");
13187e860f15SJohn Edward Broadbent             });
13197e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
13205968caeeSMarri Devender Rao } // namespace redfish
1321