xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 720487803a1890e8d4e5d91463e7ec62b4b23f74)
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>
61214b7e7SGunnar Mills 
75968caeeSMarri Devender Rao #include <variant>
85968caeeSMarri Devender Rao namespace redfish
95968caeeSMarri Devender Rao {
105968caeeSMarri Devender Rao namespace certs
115968caeeSMarri Devender Rao {
125968caeeSMarri Devender Rao constexpr char const* httpsObjectPath =
135968caeeSMarri Devender Rao     "/xyz/openbmc_project/certs/server/https";
145968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
155968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
1607a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
175968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
185968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
195968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
2037cce918SMarri Devender Rao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
2137cce918SMarri Devender Rao constexpr char const* httpsServiceName =
2237cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
2337cce918SMarri Devender Rao constexpr char const* ldapServiceName =
2437cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
25cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
26cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
27cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
28cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
295968caeeSMarri Devender Rao } // namespace certs
305968caeeSMarri Devender Rao 
315968caeeSMarri Devender Rao /**
325968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
335968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
345968caeeSMarri Devender Rao  * are installed.
355968caeeSMarri Devender Rao  */
367e860f15SJohn Edward Broadbent 
375968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate
384e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish
395968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF
405968caeeSMarri Devender Rao // publish Privilege details for certificate service
415968caeeSMarri Devender Rao 
427e860f15SJohn Edward Broadbent inline void requestRoutesCertificateService(App& app)
435968caeeSMarri Devender Rao {
447e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
45432a890cSEd Tanous         .privileges({{"Login"}})
46*72048780SAbhishek Patel         .methods(
47*72048780SAbhishek Patel             boost::beast::http::verb::
48*72048780SAbhishek Patel                 get)([](const crow::Request& req,
497e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
508d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
517e860f15SJohn Edward Broadbent                 {"@odata.type",
527e860f15SJohn Edward Broadbent                  "#CertificateService.v1_0_0.CertificateService"},
535968caeeSMarri Devender Rao                 {"@odata.id", "/redfish/v1/CertificateService"},
545968caeeSMarri Devender Rao                 {"Id", "CertificateService"},
555968caeeSMarri Devender Rao                 {"Name", "Certificate Service"},
56*72048780SAbhishek Patel                 {"Description", "Actions available to manage certificates"}};
57*72048780SAbhishek Patel             // /redfish/v1/CertificateService/CertificateLocations is something
58*72048780SAbhishek Patel             // only ConfigureManager can access then only display when the user
59*72048780SAbhishek Patel             // has permissions ConfigureManager
60*72048780SAbhishek Patel             Privileges effectiveUserPrivileges =
61*72048780SAbhishek Patel                 redfish::getUserPrivileges(req.userRole);
62*72048780SAbhishek Patel             if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
63*72048780SAbhishek Patel                                                  effectiveUserPrivileges))
64*72048780SAbhishek Patel             {
658d1b46d7Szhanghch05                 asyncResp->res.jsonValue["CertificateLocations"] = {
665968caeeSMarri Devender Rao                     {"@odata.id",
675968caeeSMarri Devender Rao                      "/redfish/v1/CertificateService/CertificateLocations"}};
68*72048780SAbhishek Patel             }
69*72048780SAbhishek Patel             asyncResp->res.jsonValue["Actions"]
70*72048780SAbhishek Patel                                     ["#CertificateService.ReplaceCertificate"] =
71*72048780SAbhishek Patel                 {{"target", "/redfish/v1/CertificateService/Actions/"
725968caeeSMarri Devender Rao                             "CertificateService.ReplaceCertificate"},
735968caeeSMarri Devender Rao                  {"CertificateType@Redfish.AllowableValues", {"PEM"}}};
747e860f15SJohn Edward Broadbent             asyncResp->res
757e860f15SJohn Edward Broadbent                 .jsonValue["Actions"]["#CertificateService.GenerateCSR"] = {
767e860f15SJohn Edward Broadbent                 {"target", "/redfish/v1/CertificateService/Actions/"
7730215816SMarri Devender Rao                            "CertificateService.GenerateCSR"}};
787e860f15SJohn Edward Broadbent         });
797e860f15SJohn Edward Broadbent } // requestRoutesCertificateService
8037cce918SMarri Devender Rao 
815968caeeSMarri Devender Rao /**
825968caeeSMarri Devender Rao  * @brief Find the ID specified in the URL
835968caeeSMarri Devender Rao  * Finds the numbers specified after the last "/" in the URL and returns.
845968caeeSMarri Devender Rao  * @param[in] path URL
855968caeeSMarri Devender Rao  * @return -1 on failure and number on success
865968caeeSMarri Devender Rao  */
8723a21a1cSEd Tanous inline long getIDFromURL(const std::string_view url)
885968caeeSMarri Devender Rao {
89f23b7296SEd Tanous     std::size_t found = url.rfind('/');
905968caeeSMarri Devender Rao     if (found == std::string::npos)
915968caeeSMarri Devender Rao     {
925968caeeSMarri Devender Rao         return -1;
935968caeeSMarri Devender Rao     }
94e6604b11SIwona Klimaszewska 
955968caeeSMarri Devender Rao     if ((found + 1) < url.length())
965968caeeSMarri Devender Rao     {
975968caeeSMarri Devender Rao         std::string_view str = url.substr(found + 1);
98e6604b11SIwona Klimaszewska 
99e6604b11SIwona Klimaszewska         return boost::convert<long>(str, boost::cnv::strtol()).value_or(-1);
1005968caeeSMarri Devender Rao     }
101e6604b11SIwona Klimaszewska 
1025968caeeSMarri Devender Rao     return -1;
1035968caeeSMarri Devender Rao }
1045968caeeSMarri Devender Rao 
1058d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
1068d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10758eb238fSKowalski, Kamil     const crow::Request& req)
10858eb238fSKowalski, Kamil {
10958eb238fSKowalski, Kamil     nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
11058eb238fSKowalski, Kamil 
11158eb238fSKowalski, Kamil     if (reqJson.is_discarded())
11258eb238fSKowalski, Kamil     {
11358eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
11458eb238fSKowalski, Kamil         return req.body;
11558eb238fSKowalski, Kamil     }
11658eb238fSKowalski, Kamil 
11758eb238fSKowalski, Kamil     std::string certificate;
11858eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
11958eb238fSKowalski, Kamil 
12058eb238fSKowalski, Kamil     if (!json_util::readJson(reqJson, asyncResp->res, "CertificateString",
12158eb238fSKowalski, Kamil                              certificate, "CertificateType", certificateType))
12258eb238fSKowalski, Kamil     {
12358eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
12458eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
12558eb238fSKowalski, Kamil         return std::string();
12658eb238fSKowalski, Kamil     }
12758eb238fSKowalski, Kamil 
12858eb238fSKowalski, Kamil     if (*certificateType != "PEM")
12958eb238fSKowalski, Kamil     {
13058eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
13158eb238fSKowalski, Kamil                                          "CertificateType");
13258eb238fSKowalski, Kamil         return std::string();
13358eb238fSKowalski, Kamil     }
13458eb238fSKowalski, Kamil 
13558eb238fSKowalski, Kamil     return certificate;
13658eb238fSKowalski, Kamil }
13758eb238fSKowalski, Kamil 
1385968caeeSMarri Devender Rao /**
1395968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
1405968caeeSMarri Devender Rao  */
1415968caeeSMarri Devender Rao class CertificateFile
1425968caeeSMarri Devender Rao {
1435968caeeSMarri Devender Rao   public:
1445968caeeSMarri Devender Rao     CertificateFile() = delete;
1455968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
1465968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
1475968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
1485968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
1495968caeeSMarri Devender Rao     CertificateFile(const std::string& certString)
1505968caeeSMarri Devender Rao     {
15172d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1525207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1535207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1545207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
1555968caeeSMarri Devender Rao         if (tempDirectory)
1565968caeeSMarri Devender Rao         {
1575968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1585968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1595968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1605968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1615968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1625968caeeSMarri Devender Rao             out << certString;
1635968caeeSMarri Devender Rao             out.close();
1645968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "Creating certificate file" << certificateFile;
1655968caeeSMarri Devender Rao         }
1665968caeeSMarri Devender Rao     }
1675968caeeSMarri Devender Rao     ~CertificateFile()
1685968caeeSMarri Devender Rao     {
1695968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1705968caeeSMarri Devender Rao         {
1715968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "Removing certificate file" << certificateFile;
17223a21a1cSEd Tanous             std::error_code ec;
17323a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
17423a21a1cSEd Tanous             if (ec)
1755968caeeSMarri Devender Rao             {
1765968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1775968caeeSMarri Devender Rao                                  << certDirectory;
1785968caeeSMarri Devender Rao             }
1795968caeeSMarri Devender Rao         }
1805968caeeSMarri Devender Rao     }
1815968caeeSMarri Devender Rao     std::string getCertFilePath()
1825968caeeSMarri Devender Rao     {
1835968caeeSMarri Devender Rao         return certificateFile;
1845968caeeSMarri Devender Rao     }
1855968caeeSMarri Devender Rao 
1865968caeeSMarri Devender Rao   private:
1875968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1885968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1895968caeeSMarri Devender Rao };
1905968caeeSMarri Devender Rao 
19130215816SMarri Devender Rao static std::unique_ptr<sdbusplus::bus::match::match> csrMatcher;
19230215816SMarri Devender Rao /**
19330215816SMarri Devender Rao  * @brief Read data from CSR D-bus object and set to response
19430215816SMarri Devender Rao  *
19530215816SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
19630215816SMarri Devender Rao  * @param[in] certURI Link to certifiate collection URI
19730215816SMarri Devender Rao  * @param[in] service D-Bus service name
19830215816SMarri Devender Rao  * @param[in] certObjPath certificate D-Bus object path
19930215816SMarri Devender Rao  * @param[in] csrObjPath CSR D-Bus object path
20030215816SMarri Devender Rao  * @return None
20130215816SMarri Devender Rao  */
2028d1b46d7Szhanghch05 static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
20330215816SMarri Devender Rao                    const std::string& certURI, const std::string& service,
20430215816SMarri Devender Rao                    const std::string& certObjPath,
20530215816SMarri Devender Rao                    const std::string& csrObjPath)
20630215816SMarri Devender Rao {
20730215816SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
20830215816SMarri Devender Rao                      << " CSRObjectPath=" << csrObjPath
20930215816SMarri Devender Rao                      << " service=" << service;
21030215816SMarri Devender Rao     crow::connections::systemBus->async_method_call(
21130215816SMarri Devender Rao         [asyncResp, certURI](const boost::system::error_code ec,
21230215816SMarri Devender Rao                              const std::string& csr) {
21330215816SMarri Devender Rao             if (ec)
21430215816SMarri Devender Rao             {
21530215816SMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
21630215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
21730215816SMarri Devender Rao                 return;
21830215816SMarri Devender Rao             }
21930215816SMarri Devender Rao             if (csr.empty())
22030215816SMarri Devender Rao             {
22130215816SMarri Devender Rao                 BMCWEB_LOG_ERROR << "CSR read is empty";
22230215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
22330215816SMarri Devender Rao                 return;
22430215816SMarri Devender Rao             }
22530215816SMarri Devender Rao             asyncResp->res.jsonValue["CSRString"] = csr;
22630215816SMarri Devender Rao             asyncResp->res.jsonValue["CertificateCollection"] = {
22730215816SMarri Devender Rao                 {"@odata.id", certURI}};
22830215816SMarri Devender Rao         },
22930215816SMarri Devender Rao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
23030215816SMarri Devender Rao }
23130215816SMarri Devender Rao 
23230215816SMarri Devender Rao /**
23330215816SMarri Devender Rao  * Action to Generate CSR
23430215816SMarri Devender Rao  */
2357e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionGenerateCSR(App& app)
23630215816SMarri Devender Rao {
2377e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/Actions/"
23830215816SMarri Devender Rao                       "CertificateService.GenerateCSR/")
239432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
2407e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
2417e860f15SJohn Edward Broadbent             [](const crow::Request& req,
2427e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2432c70f800SEd Tanous                 static const int rsaKeyBitLength = 2048;
2448d1b46d7Szhanghch05 
24530215816SMarri Devender Rao                 // Required parameters
24630215816SMarri Devender Rao                 std::string city;
24730215816SMarri Devender Rao                 std::string commonName;
24830215816SMarri Devender Rao                 std::string country;
24930215816SMarri Devender Rao                 std::string organization;
25030215816SMarri Devender Rao                 std::string organizationalUnit;
25130215816SMarri Devender Rao                 std::string state;
25230215816SMarri Devender Rao                 nlohmann::json certificateCollection;
25330215816SMarri Devender Rao 
25430215816SMarri Devender Rao                 // Optional parameters
25530215816SMarri Devender Rao                 std::optional<std::vector<std::string>> optAlternativeNames =
25630215816SMarri Devender Rao                     std::vector<std::string>();
25730215816SMarri Devender Rao                 std::optional<std::string> optContactPerson = "";
25830215816SMarri Devender Rao                 std::optional<std::string> optChallengePassword = "";
25930215816SMarri Devender Rao                 std::optional<std::string> optEmail = "";
26030215816SMarri Devender Rao                 std::optional<std::string> optGivenName = "";
26130215816SMarri Devender Rao                 std::optional<std::string> optInitials = "";
2622c70f800SEd Tanous                 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
263aaf3206fSVernon Mauery                 std::optional<std::string> optKeyCurveId = "secp384r1";
26430215816SMarri Devender Rao                 std::optional<std::string> optKeyPairAlgorithm = "EC";
26530215816SMarri Devender Rao                 std::optional<std::vector<std::string>> optKeyUsage =
26630215816SMarri Devender Rao                     std::vector<std::string>();
26730215816SMarri Devender Rao                 std::optional<std::string> optSurname = "";
26830215816SMarri Devender Rao                 std::optional<std::string> optUnstructuredName = "";
26930215816SMarri Devender Rao                 if (!json_util::readJson(
2707e860f15SJohn Edward Broadbent                         req, asyncResp->res, "City", city, "CommonName",
2717e860f15SJohn Edward Broadbent                         commonName, "ContactPerson", optContactPerson,
2727e860f15SJohn Edward Broadbent                         "Country", country, "Organization", organization,
2737e860f15SJohn Edward Broadbent                         "OrganizationalUnit", organizationalUnit, "State",
2747e860f15SJohn Edward Broadbent                         state, "CertificateCollection", certificateCollection,
2757e860f15SJohn Edward Broadbent                         "AlternativeNames", optAlternativeNames,
2767e860f15SJohn Edward Broadbent                         "ChallengePassword", optChallengePassword, "Email",
2777e860f15SJohn Edward Broadbent                         optEmail, "GivenName", optGivenName, "Initials",
2787e860f15SJohn Edward Broadbent                         optInitials, "KeyBitLength", optKeyBitLength,
2797e860f15SJohn Edward Broadbent                         "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
2807e860f15SJohn Edward Broadbent                         optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname",
2817e860f15SJohn Edward Broadbent                         optSurname, "UnstructuredName", optUnstructuredName))
28230215816SMarri Devender Rao                 {
28330215816SMarri Devender Rao                     return;
28430215816SMarri Devender Rao                 }
28530215816SMarri Devender Rao 
28630215816SMarri Devender Rao                 // bmcweb has no way to store or decode a private key challenge
2877e860f15SJohn Edward Broadbent                 // password, which will likely cause bmcweb to crash on startup
2887e860f15SJohn Edward Broadbent                 // if this is not set on a post so not allowing the user to set
2897e860f15SJohn Edward Broadbent                 // value
29030215816SMarri Devender Rao                 if (*optChallengePassword != "")
29130215816SMarri Devender Rao                 {
2927e860f15SJohn Edward Broadbent                     messages::actionParameterNotSupported(
2937e860f15SJohn Edward Broadbent                         asyncResp->res, "GenerateCSR", "ChallengePassword");
29430215816SMarri Devender Rao                     return;
29530215816SMarri Devender Rao                 }
29630215816SMarri Devender Rao 
29730215816SMarri Devender Rao                 std::string certURI;
2987e860f15SJohn Edward Broadbent                 if (!redfish::json_util::readJson(certificateCollection,
2997e860f15SJohn Edward Broadbent                                                   asyncResp->res, "@odata.id",
3007e860f15SJohn Edward Broadbent                                                   certURI))
30130215816SMarri Devender Rao                 {
30230215816SMarri Devender Rao                     return;
30330215816SMarri Devender Rao                 }
30430215816SMarri Devender Rao 
30530215816SMarri Devender Rao                 std::string objectPath;
30630215816SMarri Devender Rao                 std::string service;
3077e860f15SJohn Edward Broadbent                 if (boost::starts_with(certURI,
3087e860f15SJohn Edward Broadbent                                        "/redfish/v1/Managers/bmc/"
3097e860f15SJohn Edward Broadbent                                        "NetworkProtocol/HTTPS/Certificates"))
31030215816SMarri Devender Rao                 {
31130215816SMarri Devender Rao                     objectPath = certs::httpsObjectPath;
31230215816SMarri Devender Rao                     service = certs::httpsServiceName;
31330215816SMarri Devender Rao                 }
3143b7f0149SMarri Devender Rao                 else if (boost::starts_with(
3157e860f15SJohn Edward Broadbent                              certURI,
3167e860f15SJohn Edward Broadbent                              "/redfish/v1/AccountService/LDAP/Certificates"))
3173b7f0149SMarri Devender Rao                 {
3183b7f0149SMarri Devender Rao                     objectPath = certs::ldapObjectPath;
3193b7f0149SMarri Devender Rao                     service = certs::ldapServiceName;
3203b7f0149SMarri Devender Rao                 }
32130215816SMarri Devender Rao                 else
32230215816SMarri Devender Rao                 {
32330215816SMarri Devender Rao                     messages::actionParameterNotSupported(
32430215816SMarri Devender Rao                         asyncResp->res, "CertificateCollection", "GenerateCSR");
32530215816SMarri Devender Rao                     return;
32630215816SMarri Devender Rao                 }
32730215816SMarri Devender Rao 
32830215816SMarri Devender Rao                 // supporting only EC and RSA algorithm
3297e860f15SJohn Edward Broadbent                 if (*optKeyPairAlgorithm != "EC" &&
3307e860f15SJohn Edward Broadbent                     *optKeyPairAlgorithm != "RSA")
33130215816SMarri Devender Rao                 {
33230215816SMarri Devender Rao                     messages::actionParameterNotSupported(
33330215816SMarri Devender Rao                         asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
33430215816SMarri Devender Rao                     return;
33530215816SMarri Devender Rao                 }
33630215816SMarri Devender Rao 
3377e860f15SJohn Edward Broadbent                 // supporting only 2048 key bit length for RSA algorithm due to
3387e860f15SJohn Edward Broadbent                 // time consumed in generating private key
33930215816SMarri Devender Rao                 if (*optKeyPairAlgorithm == "RSA" &&
3402c70f800SEd Tanous                     *optKeyBitLength != rsaKeyBitLength)
34130215816SMarri Devender Rao                 {
3427e860f15SJohn Edward Broadbent                     messages::propertyValueNotInList(
3437e860f15SJohn Edward Broadbent                         asyncResp->res, std::to_string(*optKeyBitLength),
34430215816SMarri Devender Rao                         "KeyBitLength");
34530215816SMarri Devender Rao                     return;
34630215816SMarri Devender Rao                 }
34730215816SMarri Devender Rao 
34830215816SMarri Devender Rao                 // validate KeyUsage supporting only 1 type based on URL
3497e860f15SJohn Edward Broadbent                 if (boost::starts_with(certURI,
3507e860f15SJohn Edward Broadbent                                        "/redfish/v1/Managers/bmc/"
3517e860f15SJohn Edward Broadbent                                        "NetworkProtocol/HTTPS/Certificates"))
35230215816SMarri Devender Rao                 {
35330215816SMarri Devender Rao                     if (optKeyUsage->size() == 0)
35430215816SMarri Devender Rao                     {
35530215816SMarri Devender Rao                         optKeyUsage->push_back("ServerAuthentication");
35630215816SMarri Devender Rao                     }
35730215816SMarri Devender Rao                     else if (optKeyUsage->size() == 1)
35830215816SMarri Devender Rao                     {
35930215816SMarri Devender Rao                         if ((*optKeyUsage)[0] != "ServerAuthentication")
36030215816SMarri Devender Rao                         {
36130215816SMarri Devender Rao                             messages::propertyValueNotInList(
36230215816SMarri Devender Rao                                 asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
36330215816SMarri Devender Rao                             return;
36430215816SMarri Devender Rao                         }
36530215816SMarri Devender Rao                     }
36630215816SMarri Devender Rao                     else
36730215816SMarri Devender Rao                     {
36830215816SMarri Devender Rao                         messages::actionParameterNotSupported(
36930215816SMarri Devender Rao                             asyncResp->res, "KeyUsage", "GenerateCSR");
37030215816SMarri Devender Rao                         return;
37130215816SMarri Devender Rao                     }
37230215816SMarri Devender Rao                 }
3733b7f0149SMarri Devender Rao                 else if (boost::starts_with(
3747e860f15SJohn Edward Broadbent                              certURI,
3757e860f15SJohn Edward Broadbent                              "/redfish/v1/AccountService/LDAP/Certificates"))
3763b7f0149SMarri Devender Rao                 {
3773b7f0149SMarri Devender Rao                     if (optKeyUsage->size() == 0)
3783b7f0149SMarri Devender Rao                     {
3793b7f0149SMarri Devender Rao                         optKeyUsage->push_back("ClientAuthentication");
3803b7f0149SMarri Devender Rao                     }
3813b7f0149SMarri Devender Rao                     else if (optKeyUsage->size() == 1)
3823b7f0149SMarri Devender Rao                     {
3833b7f0149SMarri Devender Rao                         if ((*optKeyUsage)[0] != "ClientAuthentication")
3843b7f0149SMarri Devender Rao                         {
3853b7f0149SMarri Devender Rao                             messages::propertyValueNotInList(
3863b7f0149SMarri Devender Rao                                 asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
3873b7f0149SMarri Devender Rao                             return;
3883b7f0149SMarri Devender Rao                         }
3893b7f0149SMarri Devender Rao                     }
3903b7f0149SMarri Devender Rao                     else
3913b7f0149SMarri Devender Rao                     {
3923b7f0149SMarri Devender Rao                         messages::actionParameterNotSupported(
3933b7f0149SMarri Devender Rao                             asyncResp->res, "KeyUsage", "GenerateCSR");
3943b7f0149SMarri Devender Rao                         return;
3953b7f0149SMarri Devender Rao                     }
3963b7f0149SMarri Devender Rao                 }
39730215816SMarri Devender Rao 
3987e860f15SJohn Edward Broadbent                 // Only allow one CSR matcher at a time so setting retry
3997e860f15SJohn Edward Broadbent                 // time-out and timer expiry to 10 seconds for now.
4002c70f800SEd Tanous                 static const int timeOut = 10;
40130215816SMarri Devender Rao                 if (csrMatcher)
40230215816SMarri Devender Rao                 {
4037e860f15SJohn Edward Broadbent                     messages::serviceTemporarilyUnavailable(
4047e860f15SJohn Edward Broadbent                         asyncResp->res, std::to_string(timeOut));
40530215816SMarri Devender Rao                     return;
40630215816SMarri Devender Rao                 }
40730215816SMarri Devender Rao 
40830215816SMarri Devender Rao                 // Make this static so it survives outside this method
40930215816SMarri Devender Rao                 static boost::asio::steady_timer timeout(*req.ioService);
4102c70f800SEd Tanous                 timeout.expires_after(std::chrono::seconds(timeOut));
4117e860f15SJohn Edward Broadbent                 timeout.async_wait([asyncResp](
4127e860f15SJohn Edward Broadbent                                        const boost::system::error_code& ec) {
41330215816SMarri Devender Rao                     csrMatcher = nullptr;
41430215816SMarri Devender Rao                     if (ec)
41530215816SMarri Devender Rao                     {
4167e860f15SJohn Edward Broadbent                         // operation_aborted is expected if timer is canceled
4177e860f15SJohn Edward Broadbent                         // before completion.
41830215816SMarri Devender Rao                         if (ec != boost::asio::error::operation_aborted)
41930215816SMarri Devender Rao                         {
42030215816SMarri Devender Rao                             BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
42130215816SMarri Devender Rao                         }
42230215816SMarri Devender Rao                         return;
42330215816SMarri Devender Rao                     }
42430215816SMarri Devender Rao                     BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
42530215816SMarri Devender Rao                     messages::internalError(asyncResp->res);
42630215816SMarri Devender Rao                 });
42730215816SMarri Devender Rao 
42830215816SMarri Devender Rao                 // create a matcher to wait on CSR object
42930215816SMarri Devender Rao                 BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
4307e860f15SJohn Edward Broadbent                 std::string match(
4317e860f15SJohn Edward Broadbent                     "type='signal',"
43230215816SMarri Devender Rao                     "interface='org.freedesktop.DBus.ObjectManager',"
43330215816SMarri Devender Rao                     "path='" +
43430215816SMarri Devender Rao                     objectPath +
43530215816SMarri Devender Rao                     "',"
43630215816SMarri Devender Rao                     "member='InterfacesAdded'");
43730215816SMarri Devender Rao                 csrMatcher = std::make_unique<sdbusplus::bus::match::match>(
43830215816SMarri Devender Rao                     *crow::connections::systemBus, match,
43930215816SMarri Devender Rao                     [asyncResp, service, objectPath,
44030215816SMarri Devender Rao                      certURI](sdbusplus::message::message& m) {
441271584abSEd Tanous                         timeout.cancel();
44230215816SMarri Devender Rao                         if (m.is_method_error())
44330215816SMarri Devender Rao                         {
44430215816SMarri Devender Rao                             BMCWEB_LOG_ERROR << "Dbus method error!!!";
44530215816SMarri Devender Rao                             messages::internalError(asyncResp->res);
44630215816SMarri Devender Rao                             return;
44730215816SMarri Devender Rao                         }
44830215816SMarri Devender Rao                         std::vector<std::pair<
4497e860f15SJohn Edward Broadbent                             std::string,
4507e860f15SJohn Edward Broadbent                             std::vector<std::pair<std::string,
4517e860f15SJohn Edward Broadbent                                                   std::variant<std::string>>>>>
45230215816SMarri Devender Rao                             interfacesProperties;
45330215816SMarri Devender Rao                         sdbusplus::message::object_path csrObjectPath;
45430215816SMarri Devender Rao                         m.read(csrObjectPath, interfacesProperties);
4557e860f15SJohn Edward Broadbent                         BMCWEB_LOG_DEBUG << "CSR object added"
4567e860f15SJohn Edward Broadbent                                          << csrObjectPath.str;
45730215816SMarri Devender Rao                         for (auto& interface : interfacesProperties)
45830215816SMarri Devender Rao                         {
4597e860f15SJohn Edward Broadbent                             if (interface.first ==
4607e860f15SJohn Edward Broadbent                                 "xyz.openbmc_project.Certs.CSR")
46130215816SMarri Devender Rao                             {
46230215816SMarri Devender Rao                                 getCSR(asyncResp, certURI, service, objectPath,
46330215816SMarri Devender Rao                                        csrObjectPath.str);
46430215816SMarri Devender Rao                                 break;
46530215816SMarri Devender Rao                             }
46630215816SMarri Devender Rao                         }
46730215816SMarri Devender Rao                     });
46830215816SMarri Devender Rao                 crow::connections::systemBus->async_method_call(
469271584abSEd Tanous                     [asyncResp](const boost::system::error_code& ec,
470cb13a392SEd Tanous                                 const std::string&) {
47130215816SMarri Devender Rao                         if (ec)
47230215816SMarri Devender Rao                         {
4737e860f15SJohn Edward Broadbent                             BMCWEB_LOG_ERROR << "DBUS response error: "
4747e860f15SJohn Edward Broadbent                                              << ec.message();
47530215816SMarri Devender Rao                             messages::internalError(asyncResp->res);
47630215816SMarri Devender Rao                             return;
47730215816SMarri Devender Rao                         }
47830215816SMarri Devender Rao                     },
47930215816SMarri Devender Rao                     service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
4807e860f15SJohn Edward Broadbent                     "GenerateCSR", *optAlternativeNames, *optChallengePassword,
4817e860f15SJohn Edward Broadbent                     city, commonName, *optContactPerson, country, *optEmail,
4827e860f15SJohn Edward Broadbent                     *optGivenName, *optInitials, *optKeyBitLength,
4837e860f15SJohn Edward Broadbent                     *optKeyCurveId, *optKeyPairAlgorithm, *optKeyUsage,
4847e860f15SJohn Edward Broadbent                     organization, organizationalUnit, state, *optSurname,
4857e860f15SJohn Edward Broadbent                     *optUnstructuredName);
4867e860f15SJohn Edward Broadbent             });
4877e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionGenerateCSR
48830215816SMarri Devender Rao 
4895968caeeSMarri Devender Rao /**
4904e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
4915968caeeSMarri Devender Rao  *
4925968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
4935968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
4945968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
4955968caeeSMarri Devender Rao  * @return None
4965968caeeSMarri Devender Rao  */
4975968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
4985968caeeSMarri Devender Rao                                       const std::string_view value)
4995968caeeSMarri Devender Rao {
5005968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
5015968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
5025968caeeSMarri Devender Rao     while (i != value.end())
5035968caeeSMarri Devender Rao     {
5045968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
5055968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
5065968caeeSMarri Devender Rao         {
50717a897dfSManojkiran Eda             ++i;
5085968caeeSMarri Devender Rao         }
5095968caeeSMarri Devender Rao         if (i == value.end())
5105968caeeSMarri Devender Rao         {
5115968caeeSMarri Devender Rao             break;
5125968caeeSMarri Devender Rao         }
513271584abSEd Tanous         const std::string_view key(tokenBegin,
514271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
51517a897dfSManojkiran Eda         ++i;
5165968caeeSMarri Devender Rao         tokenBegin = i;
5175968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
5185968caeeSMarri Devender Rao         {
51917a897dfSManojkiran Eda             ++i;
5205968caeeSMarri Devender Rao         }
521271584abSEd Tanous         const std::string_view val(tokenBegin,
522271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
5235968caeeSMarri Devender Rao         if (key == "L")
5245968caeeSMarri Devender Rao         {
5255968caeeSMarri Devender Rao             out["City"] = val;
5265968caeeSMarri Devender Rao         }
5275968caeeSMarri Devender Rao         else if (key == "CN")
5285968caeeSMarri Devender Rao         {
5295968caeeSMarri Devender Rao             out["CommonName"] = val;
5305968caeeSMarri Devender Rao         }
5315968caeeSMarri Devender Rao         else if (key == "C")
5325968caeeSMarri Devender Rao         {
5335968caeeSMarri Devender Rao             out["Country"] = val;
5345968caeeSMarri Devender Rao         }
5355968caeeSMarri Devender Rao         else if (key == "O")
5365968caeeSMarri Devender Rao         {
5375968caeeSMarri Devender Rao             out["Organization"] = val;
5385968caeeSMarri Devender Rao         }
5395968caeeSMarri Devender Rao         else if (key == "OU")
5405968caeeSMarri Devender Rao         {
5415968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
5425968caeeSMarri Devender Rao         }
5435968caeeSMarri Devender Rao         else if (key == "ST")
5445968caeeSMarri Devender Rao         {
5455968caeeSMarri Devender Rao             out["State"] = val;
5465968caeeSMarri Devender Rao         }
5475968caeeSMarri Devender Rao         // skip comma character
5485968caeeSMarri Devender Rao         if (i != value.end())
5495968caeeSMarri Devender Rao         {
55017a897dfSManojkiran Eda             ++i;
5515968caeeSMarri Devender Rao         }
5525968caeeSMarri Devender Rao     }
5535968caeeSMarri Devender Rao }
5545968caeeSMarri Devender Rao 
5555968caeeSMarri Devender Rao /**
5565968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
5575968caeeSMarri Devender Rao  * message
5585968caeeSMarri Devender Rao  *
5595968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
5605968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
5615968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
5625968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
5635968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
5645968caeeSMarri Devender Rao  * @return None
5655968caeeSMarri Devender Rao  */
5665968caeeSMarri Devender Rao static void getCertificateProperties(
5678d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5688d1b46d7Szhanghch05     const std::string& objectPath, const std::string& service, long certId,
5698d1b46d7Szhanghch05     const std::string& certURL, const std::string& name)
5705968caeeSMarri Devender Rao {
5715968caeeSMarri Devender Rao     using PropertyType =
5725968caeeSMarri Devender Rao         std::variant<std::string, uint64_t, std::vector<std::string>>;
5735968caeeSMarri Devender Rao     using PropertiesMap = boost::container::flat_map<std::string, PropertyType>;
5745968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
5755968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
5765968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
57737cce918SMarri Devender Rao         [asyncResp, certURL, certId, name](const boost::system::error_code ec,
5785968caeeSMarri Devender Rao                                            const PropertiesMap& properties) {
5795968caeeSMarri Devender Rao             if (ec)
5805968caeeSMarri Devender Rao             {
5815968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
5828aae75adSMarri Devender Rao                 messages::resourceNotFound(asyncResp->res, name,
5838aae75adSMarri Devender Rao                                            std::to_string(certId));
5845968caeeSMarri Devender Rao                 return;
5855968caeeSMarri Devender Rao             }
5865968caeeSMarri Devender Rao             asyncResp->res.jsonValue = {
5875968caeeSMarri Devender Rao                 {"@odata.id", certURL},
5885968caeeSMarri Devender Rao                 {"@odata.type", "#Certificate.v1_0_0.Certificate"},
5895968caeeSMarri Devender Rao                 {"Id", std::to_string(certId)},
5905968caeeSMarri Devender Rao                 {"Name", name},
5915968caeeSMarri Devender Rao                 {"Description", name}};
5925968caeeSMarri Devender Rao             for (const auto& property : properties)
5935968caeeSMarri Devender Rao             {
5945968caeeSMarri Devender Rao                 if (property.first == "CertificateString")
5955968caeeSMarri Devender Rao                 {
5965968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["CertificateString"] = "";
5975968caeeSMarri Devender Rao                     const std::string* value =
5985968caeeSMarri Devender Rao                         std::get_if<std::string>(&property.second);
5995968caeeSMarri Devender Rao                     if (value)
6005968caeeSMarri Devender Rao                     {
60137cce918SMarri Devender Rao                         asyncResp->res.jsonValue["CertificateString"] = *value;
6025968caeeSMarri Devender Rao                     }
6035968caeeSMarri Devender Rao                 }
6045968caeeSMarri Devender Rao                 else if (property.first == "KeyUsage")
6055968caeeSMarri Devender Rao                 {
6065968caeeSMarri Devender Rao                     nlohmann::json& keyUsage =
6075968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["KeyUsage"];
6085968caeeSMarri Devender Rao                     keyUsage = nlohmann::json::array();
6095968caeeSMarri Devender Rao                     const std::vector<std::string>* value =
61037cce918SMarri Devender Rao                         std::get_if<std::vector<std::string>>(&property.second);
6115968caeeSMarri Devender Rao                     if (value)
6125968caeeSMarri Devender Rao                     {
6135968caeeSMarri Devender Rao                         for (const std::string& usage : *value)
6145968caeeSMarri Devender Rao                         {
6155968caeeSMarri Devender Rao                             keyUsage.push_back(usage);
6165968caeeSMarri Devender Rao                         }
6175968caeeSMarri Devender Rao                     }
6185968caeeSMarri Devender Rao                 }
6195968caeeSMarri Devender Rao                 else if (property.first == "Issuer")
6205968caeeSMarri Devender Rao                 {
6215968caeeSMarri Devender Rao                     const std::string* value =
6225968caeeSMarri Devender Rao                         std::get_if<std::string>(&property.second);
6235968caeeSMarri Devender Rao                     if (value)
6245968caeeSMarri Devender Rao                     {
6255968caeeSMarri Devender Rao                         updateCertIssuerOrSubject(
6265968caeeSMarri Devender Rao                             asyncResp->res.jsonValue["Issuer"], *value);
6275968caeeSMarri Devender Rao                     }
6285968caeeSMarri Devender Rao                 }
6295968caeeSMarri Devender Rao                 else if (property.first == "Subject")
6305968caeeSMarri Devender Rao                 {
6315968caeeSMarri Devender Rao                     const std::string* value =
6325968caeeSMarri Devender Rao                         std::get_if<std::string>(&property.second);
6335968caeeSMarri Devender Rao                     if (value)
6345968caeeSMarri Devender Rao                     {
6355968caeeSMarri Devender Rao                         updateCertIssuerOrSubject(
63637cce918SMarri Devender Rao                             asyncResp->res.jsonValue["Subject"], *value);
6375968caeeSMarri Devender Rao                     }
6385968caeeSMarri Devender Rao                 }
6395968caeeSMarri Devender Rao                 else if (property.first == "ValidNotAfter")
6405968caeeSMarri Devender Rao                 {
6415968caeeSMarri Devender Rao                     const uint64_t* value =
6425968caeeSMarri Devender Rao                         std::get_if<uint64_t>(&property.second);
6435968caeeSMarri Devender Rao                     if (value)
6445968caeeSMarri Devender Rao                     {
64537cce918SMarri Devender Rao                         std::time_t time = static_cast<std::time_t>(*value);
6465968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["ValidNotAfter"] =
6475968caeeSMarri Devender Rao                             crow::utility::getDateTime(time);
6485968caeeSMarri Devender Rao                     }
6495968caeeSMarri Devender Rao                 }
6505968caeeSMarri Devender Rao                 else if (property.first == "ValidNotBefore")
6515968caeeSMarri Devender Rao                 {
6525968caeeSMarri Devender Rao                     const uint64_t* value =
6535968caeeSMarri Devender Rao                         std::get_if<uint64_t>(&property.second);
6545968caeeSMarri Devender Rao                     if (value)
6555968caeeSMarri Devender Rao                     {
65637cce918SMarri Devender Rao                         std::time_t time = static_cast<std::time_t>(*value);
6575968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["ValidNotBefore"] =
6585968caeeSMarri Devender Rao                             crow::utility::getDateTime(time);
6595968caeeSMarri Devender Rao                     }
6605968caeeSMarri Devender Rao                 }
6615968caeeSMarri Devender Rao             }
6625968caeeSMarri Devender Rao             asyncResp->res.addHeader("Location", certURL);
6635968caeeSMarri Devender Rao         },
6645968caeeSMarri Devender Rao         service, objectPath, certs::dbusPropIntf, "GetAll",
6655968caeeSMarri Devender Rao         certs::certPropIntf);
6665968caeeSMarri Devender Rao }
6675968caeeSMarri Devender Rao 
6685968caeeSMarri Devender Rao using GetObjectType =
6695968caeeSMarri Devender Rao     std::vector<std::pair<std::string, std::vector<std::string>>>;
6705968caeeSMarri Devender Rao 
6715968caeeSMarri Devender Rao /**
6725968caeeSMarri Devender Rao  * Action to replace an existing certificate
6735968caeeSMarri Devender Rao  */
6747e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionsReplaceCertificate(App& app)
6755968caeeSMarri Devender Rao {
6767e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/Actions/"
6775968caeeSMarri Devender Rao                       "CertificateService.ReplaceCertificate/")
678*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
6797e860f15SJohn Edward Broadbent         .methods(
6807e860f15SJohn Edward Broadbent             boost::beast::http::verb::
6817e860f15SJohn Edward Broadbent                 post)([](const crow::Request& req,
6827e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
6835968caeeSMarri Devender Rao             std::string certificate;
6845968caeeSMarri Devender Rao             nlohmann::json certificateUri;
6855968caeeSMarri Devender Rao             std::optional<std::string> certificateType = "PEM";
6868d1b46d7Szhanghch05 
6875968caeeSMarri Devender Rao             if (!json_util::readJson(req, asyncResp->res, "CertificateString",
6887e860f15SJohn Edward Broadbent                                      certificate, "CertificateUri",
6897e860f15SJohn Edward Broadbent                                      certificateUri, "CertificateType",
6907e860f15SJohn Edward Broadbent                                      certificateType))
6915968caeeSMarri Devender Rao             {
6925968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Required parameters are missing";
6935968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
6945968caeeSMarri Devender Rao                 return;
6955968caeeSMarri Devender Rao             }
6965968caeeSMarri Devender Rao 
6975968caeeSMarri Devender Rao             if (!certificateType)
6985968caeeSMarri Devender Rao             {
6995968caeeSMarri Devender Rao                 // should never happen, but it never hurts to be paranoid.
7005968caeeSMarri Devender Rao                 return;
7015968caeeSMarri Devender Rao             }
7025968caeeSMarri Devender Rao             if (certificateType != "PEM")
7035968caeeSMarri Devender Rao             {
7045968caeeSMarri Devender Rao                 messages::actionParameterNotSupported(
7055968caeeSMarri Devender Rao                     asyncResp->res, "CertificateType", "ReplaceCertificate");
7065968caeeSMarri Devender Rao                 return;
7075968caeeSMarri Devender Rao             }
7085968caeeSMarri Devender Rao 
7095968caeeSMarri Devender Rao             std::string certURI;
7105968caeeSMarri Devender Rao             if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
7115968caeeSMarri Devender Rao                                               "@odata.id", certURI))
7125968caeeSMarri Devender Rao             {
7135968caeeSMarri Devender Rao                 messages::actionParameterMissing(
7145968caeeSMarri Devender Rao                     asyncResp->res, "ReplaceCertificate", "CertificateUri");
7155968caeeSMarri Devender Rao                 return;
7165968caeeSMarri Devender Rao             }
7175968caeeSMarri Devender Rao 
7185968caeeSMarri Devender Rao             BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI;
7195968caeeSMarri Devender Rao             long id = getIDFromURL(certURI);
7205968caeeSMarri Devender Rao             if (id < 0)
7215968caeeSMarri Devender Rao             {
7227e860f15SJohn Edward Broadbent                 messages::actionParameterValueFormatError(
7237e860f15SJohn Edward Broadbent                     asyncResp->res, certURI, "CertificateUri",
7245968caeeSMarri Devender Rao                     "ReplaceCertificate");
7255968caeeSMarri Devender Rao                 return;
7265968caeeSMarri Devender Rao             }
7275968caeeSMarri Devender Rao             std::string objectPath;
7285968caeeSMarri Devender Rao             std::string name;
72937cce918SMarri Devender Rao             std::string service;
7307e860f15SJohn Edward Broadbent             if (boost::starts_with(certURI,
7317e860f15SJohn Edward Broadbent                                    "/redfish/v1/Managers/bmc/NetworkProtocol/"
7327e860f15SJohn Edward Broadbent                                    "HTTPS/Certificates/"))
7335968caeeSMarri Devender Rao             {
7347e860f15SJohn Edward Broadbent                 objectPath = std::string(certs::httpsObjectPath) + "/" +
7357e860f15SJohn Edward Broadbent                              std::to_string(id);
7365968caeeSMarri Devender Rao                 name = "HTTPS certificate";
73737cce918SMarri Devender Rao                 service = certs::httpsServiceName;
73837cce918SMarri Devender Rao             }
73937cce918SMarri Devender Rao             else if (boost::starts_with(
7407e860f15SJohn Edward Broadbent                          certURI,
7417e860f15SJohn Edward Broadbent                          "/redfish/v1/AccountService/LDAP/Certificates/"))
74237cce918SMarri Devender Rao             {
7437e860f15SJohn Edward Broadbent                 objectPath = std::string(certs::ldapObjectPath) + "/" +
7447e860f15SJohn Edward Broadbent                              std::to_string(id);
74537cce918SMarri Devender Rao                 name = "LDAP certificate";
74637cce918SMarri Devender Rao                 service = certs::ldapServiceName;
7475968caeeSMarri Devender Rao             }
748cfcd5f6bSMarri Devender Rao             else if (boost::starts_with(
749cfcd5f6bSMarri Devender Rao                          certURI,
750cfcd5f6bSMarri Devender Rao                          "/redfish/v1/Managers/bmc/Truststore/Certificates/"))
751cfcd5f6bSMarri Devender Rao             {
752cfcd5f6bSMarri Devender Rao                 objectPath = std::string(certs::authorityObjectPath) + "/" +
753cfcd5f6bSMarri Devender Rao                              std::to_string(id);
754cfcd5f6bSMarri Devender Rao                 name = "TrustStore certificate";
755cfcd5f6bSMarri Devender Rao                 service = certs::authorityServiceName;
756cfcd5f6bSMarri Devender Rao             }
7575968caeeSMarri Devender Rao             else
7585968caeeSMarri Devender Rao             {
7595968caeeSMarri Devender Rao                 messages::actionParameterNotSupported(
7605968caeeSMarri Devender Rao                     asyncResp->res, "CertificateUri", "ReplaceCertificate");
7615968caeeSMarri Devender Rao                 return;
7625968caeeSMarri Devender Rao             }
7635968caeeSMarri Devender Rao 
7645968caeeSMarri Devender Rao             std::shared_ptr<CertificateFile> certFile =
7655968caeeSMarri Devender Rao                 std::make_shared<CertificateFile>(certificate);
7665968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
76737cce918SMarri Devender Rao                 [asyncResp, certFile, objectPath, service, certURI, id,
7685968caeeSMarri Devender Rao                  name](const boost::system::error_code ec) {
7695968caeeSMarri Devender Rao                     if (ec)
7705968caeeSMarri Devender Rao                     {
7715968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
7728aae75adSMarri Devender Rao                         messages::resourceNotFound(asyncResp->res, name,
7738aae75adSMarri Devender Rao                                                    std::to_string(id));
7745968caeeSMarri Devender Rao                         return;
7755968caeeSMarri Devender Rao                     }
77637cce918SMarri Devender Rao                     getCertificateProperties(asyncResp, objectPath, service, id,
7775968caeeSMarri Devender Rao                                              certURI, name);
7785968caeeSMarri Devender Rao                     BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
7795968caeeSMarri Devender Rao                                      << certFile->getCertFilePath();
7805968caeeSMarri Devender Rao                 },
7815968caeeSMarri Devender Rao                 service, objectPath, certs::certReplaceIntf, "Replace",
7825968caeeSMarri Devender Rao                 certFile->getCertFilePath());
7837e860f15SJohn Edward Broadbent         });
7847e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionsReplaceCertificate
7855968caeeSMarri Devender Rao 
7865968caeeSMarri Devender Rao /**
7875968caeeSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
7885968caeeSMarri Devender Rao  * of a component, account or service.
7895968caeeSMarri Devender Rao  */
7905968caeeSMarri Devender Rao 
7917e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificate(App& app)
7925968caeeSMarri Devender Rao {
7937e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
7947e860f15SJohn Edward Broadbent         app,
7957e860f15SJohn Edward Broadbent         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
796*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
7977e860f15SJohn Edward Broadbent         .methods(
7987e860f15SJohn Edward Broadbent             boost::beast::http::verb::
7997e860f15SJohn Edward Broadbent                 get)([](const crow::Request& req,
8007e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8017e860f15SJohn Edward Broadbent                         const std::string& param) -> void {
8027e860f15SJohn Edward Broadbent             if (param.empty())
8035968caeeSMarri Devender Rao             {
8045968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
8055968caeeSMarri Devender Rao                 return;
8065968caeeSMarri Devender Rao             }
8075968caeeSMarri Devender Rao             long id = getIDFromURL(req.url);
8085968caeeSMarri Devender Rao 
8097e860f15SJohn Edward Broadbent             BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID="
8107e860f15SJohn Edward Broadbent                              << std::to_string(id);
8115968caeeSMarri Devender Rao             std::string certURL =
8125968caeeSMarri Devender Rao                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8135968caeeSMarri Devender Rao                 std::to_string(id);
8145968caeeSMarri Devender Rao             std::string objectPath = certs::httpsObjectPath;
8155968caeeSMarri Devender Rao             objectPath += "/";
8165968caeeSMarri Devender Rao             objectPath += std::to_string(id);
8177e860f15SJohn Edward Broadbent             getCertificateProperties(asyncResp, objectPath,
8187e860f15SJohn Edward Broadbent                                      certs::httpsServiceName, id, certURL,
8197e860f15SJohn Edward Broadbent                                      "HTTPS Certificate");
8207e860f15SJohn Edward Broadbent         });
8215968caeeSMarri Devender Rao }
8225968caeeSMarri Devender Rao 
8235968caeeSMarri Devender Rao /**
8245968caeeSMarri Devender Rao  * Collection of HTTPS certificates
8255968caeeSMarri Devender Rao  */
8267e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificateCollection(App& app)
8275968caeeSMarri Devender Rao {
8287e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8295968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
830*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
8317e860f15SJohn Edward Broadbent         .methods(
8327e860f15SJohn Edward Broadbent             boost::beast::http::verb::
8337e860f15SJohn Edward Broadbent                 get)([](const crow::Request&,
8347e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8358d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
8365968caeeSMarri Devender Rao                 {"@odata.id",
8375968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"},
8385968caeeSMarri Devender Rao                 {"@odata.type", "#CertificateCollection.CertificateCollection"},
8395968caeeSMarri Devender Rao                 {"Name", "HTTPS Certificates Collection"},
8405968caeeSMarri Devender Rao                 {"Description", "A Collection of HTTPS certificate instances"}};
8418d1b46d7Szhanghch05 
8425968caeeSMarri Devender Rao             crow::connections::systemBus->async_method_call(
8435968caeeSMarri Devender Rao                 [asyncResp](const boost::system::error_code ec,
8445968caeeSMarri Devender Rao                             const ManagedObjectType& certs) {
8455968caeeSMarri Devender Rao                     if (ec)
8465968caeeSMarri Devender Rao                     {
8475968caeeSMarri Devender Rao                         BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
8485968caeeSMarri Devender Rao                         messages::internalError(asyncResp->res);
8495968caeeSMarri Devender Rao                         return;
8505968caeeSMarri Devender Rao                     }
8517e860f15SJohn Edward Broadbent                     nlohmann::json& members =
8527e860f15SJohn Edward Broadbent                         asyncResp->res.jsonValue["Members"];
8535968caeeSMarri Devender Rao                     members = nlohmann::json::array();
8545968caeeSMarri Devender Rao                     for (const auto& cert : certs)
8555968caeeSMarri Devender Rao                     {
8565968caeeSMarri Devender Rao                         long id = getIDFromURL(cert.first.str);
85737cce918SMarri Devender Rao                         if (id >= 0)
8585968caeeSMarri Devender Rao                         {
8595968caeeSMarri Devender Rao                             members.push_back(
8605968caeeSMarri Devender Rao                                 {{"@odata.id",
8615968caeeSMarri Devender Rao                                   "/redfish/v1/Managers/bmc/"
8625968caeeSMarri Devender Rao                                   "NetworkProtocol/HTTPS/Certificates/" +
8635968caeeSMarri Devender Rao                                       std::to_string(id)}});
8645968caeeSMarri Devender Rao                         }
8655968caeeSMarri Devender Rao                     }
8665968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["Members@odata.count"] =
8675968caeeSMarri Devender Rao                         members.size();
8685968caeeSMarri Devender Rao                 },
86937cce918SMarri Devender Rao                 certs::httpsServiceName, certs::httpsObjectPath,
87037cce918SMarri Devender Rao                 certs::dbusObjManagerIntf, "GetManagedObjects");
8717e860f15SJohn Edward Broadbent         });
8725968caeeSMarri Devender Rao 
8737e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8747e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
875*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
8767e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
8777e860f15SJohn Edward Broadbent             [](const crow::Request& req,
8787e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8795968caeeSMarri Devender Rao                 BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
8808d1b46d7Szhanghch05 
8817e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue = {
8827e860f15SJohn Edward Broadbent                     {"Name", "HTTPS Certificate"},
8835968caeeSMarri Devender Rao                     {"Description", "HTTPS Certificate"}};
8845968caeeSMarri Devender Rao 
8857e860f15SJohn Edward Broadbent                 std::string certFileBody =
8867e860f15SJohn Edward Broadbent                     getCertificateFromReqBody(asyncResp, req);
88758eb238fSKowalski, Kamil 
88858eb238fSKowalski, Kamil                 if (certFileBody.empty())
88958eb238fSKowalski, Kamil                 {
8907e860f15SJohn Edward Broadbent                     BMCWEB_LOG_ERROR
8917e860f15SJohn Edward Broadbent                         << "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 =
9175968caeeSMarri Devender Rao                             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/"
9185968caeeSMarri Devender Rao                             "Certificates/" +
9195968caeeSMarri Devender Rao                             std::to_string(certId);
9207e860f15SJohn Edward Broadbent                         getCertificateProperties(
9217e860f15SJohn Edward Broadbent                             asyncResp, objectPath, certs::httpsServiceName,
9227e860f15SJohn Edward Broadbent                             certId, certURL, "HTTPS Certificate");
9235968caeeSMarri Devender Rao                         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9245968caeeSMarri Devender Rao                                          << certFile->getCertFilePath();
9255968caeeSMarri Devender Rao                     },
92637cce918SMarri Devender Rao                     certs::httpsServiceName, certs::httpsObjectPath,
9277e860f15SJohn Edward Broadbent                     certs::certInstallIntf, "Install",
9287e860f15SJohn Edward Broadbent                     certFile->getCertFilePath());
9297e860f15SJohn Edward Broadbent             });
9307e860f15SJohn Edward Broadbent } // requestRoutesHTTPSCertificateCollection
9315968caeeSMarri Devender Rao 
9325968caeeSMarri Devender Rao /**
93337cce918SMarri Devender Rao  * @brief Retrieve the certificates installed list and append to the
93437cce918SMarri Devender Rao  * response
93537cce918SMarri Devender Rao  *
93637cce918SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
93737cce918SMarri Devender Rao  * @param[in] certURL  Path of the certificate object
93837cce918SMarri Devender Rao  * @param[in] path  Path of the D-Bus service object
93937cce918SMarri Devender Rao  * @return None
94037cce918SMarri Devender Rao  */
9418d1b46d7Szhanghch05 void getCertificateLocations(
9428d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9438d1b46d7Szhanghch05     const std::string& certURL, const std::string& path,
94437cce918SMarri Devender Rao     const std::string& service)
94537cce918SMarri Devender Rao {
94637cce918SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL
94737cce918SMarri Devender Rao                      << " Path=" << path << " service= " << service;
94837cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
94937cce918SMarri Devender Rao         [asyncResp, certURL](const boost::system::error_code ec,
95037cce918SMarri Devender Rao                              const ManagedObjectType& certs) {
95137cce918SMarri Devender Rao             if (ec)
95237cce918SMarri Devender Rao             {
9539c8e039eSJonathan Doman                 BMCWEB_LOG_WARNING
9549c8e039eSJonathan Doman                     << "Certificate collection query failed: " << ec
9559c8e039eSJonathan Doman                     << ", skipping " << certURL;
95637cce918SMarri Devender Rao                 return;
95737cce918SMarri Devender Rao             }
95837cce918SMarri Devender Rao             nlohmann::json& links =
95937cce918SMarri Devender Rao                 asyncResp->res.jsonValue["Links"]["Certificates"];
96037cce918SMarri Devender Rao             for (auto& cert : certs)
96137cce918SMarri Devender Rao             {
96237cce918SMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
96337cce918SMarri Devender Rao                 if (id >= 0)
96437cce918SMarri Devender Rao                 {
96537cce918SMarri Devender Rao                     links.push_back(
96637cce918SMarri Devender Rao                         {{"@odata.id", certURL + std::to_string(id)}});
96737cce918SMarri Devender Rao                 }
96837cce918SMarri Devender Rao             }
96937cce918SMarri Devender Rao             asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] =
97037cce918SMarri Devender Rao                 links.size();
97137cce918SMarri Devender Rao         },
97237cce918SMarri Devender Rao         service, path, certs::dbusObjManagerIntf, "GetManagedObjects");
9735968caeeSMarri Devender Rao }
9747e860f15SJohn Edward Broadbent 
9757e860f15SJohn Edward Broadbent /**
9767e860f15SJohn Edward Broadbent  * The certificate location schema defines a resource that an administrator
9777e860f15SJohn Edward Broadbent  * can use in order to locate all certificates installed on a given service.
9787e860f15SJohn Edward Broadbent  */
9797e860f15SJohn Edward Broadbent inline void requestRoutesCertificateLocations(App& app)
9807e860f15SJohn Edward Broadbent {
9817e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
982*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
9837e860f15SJohn Edward Broadbent         .methods(
9847e860f15SJohn Edward Broadbent             boost::beast::http::verb::
9857e860f15SJohn Edward Broadbent                 get)([](const crow::Request&,
9867e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
9877e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue = {
9887e860f15SJohn Edward Broadbent                 {"@odata.id",
9897e860f15SJohn Edward Broadbent                  "/redfish/v1/CertificateService/CertificateLocations"},
9907e860f15SJohn Edward Broadbent                 {"@odata.type",
9917e860f15SJohn Edward Broadbent                  "#CertificateLocations.v1_0_0.CertificateLocations"},
9927e860f15SJohn Edward Broadbent                 {"Name", "Certificate Locations"},
9937e860f15SJohn Edward Broadbent                 {"Id", "CertificateLocations"},
9947e860f15SJohn Edward Broadbent                 {"Description",
9957e860f15SJohn Edward Broadbent                  "Defines a resource that an administrator can use in order to "
9967e860f15SJohn Edward Broadbent                  "locate all certificates installed on a given service"}};
9977e860f15SJohn Edward Broadbent 
9987e860f15SJohn Edward Broadbent             nlohmann::json& links =
9997e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Links"]["Certificates"];
10007e860f15SJohn Edward Broadbent             links = nlohmann::json::array();
10017e860f15SJohn Edward Broadbent             getCertificateLocations(
10027e860f15SJohn Edward Broadbent                 asyncResp,
10037e860f15SJohn Edward Broadbent                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/",
10047e860f15SJohn Edward Broadbent                 certs::httpsObjectPath, certs::httpsServiceName);
10057e860f15SJohn Edward Broadbent             getCertificateLocations(
10067e860f15SJohn Edward Broadbent                 asyncResp, "/redfish/v1/AccountService/LDAP/Certificates/",
10077e860f15SJohn Edward Broadbent                 certs::ldapObjectPath, certs::ldapServiceName);
10087e860f15SJohn Edward Broadbent             getCertificateLocations(
10097e860f15SJohn Edward Broadbent                 asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/",
10107e860f15SJohn Edward Broadbent                 certs::authorityObjectPath, certs::authorityServiceName);
10117e860f15SJohn Edward Broadbent         });
10127e860f15SJohn Edward Broadbent }
10137e860f15SJohn Edward Broadbent // requestRoutesCertificateLocations
101437cce918SMarri Devender Rao 
101537cce918SMarri Devender Rao /**
101637cce918SMarri Devender Rao  * Collection of LDAP certificates
101737cce918SMarri Devender Rao  */
10187e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificateCollection(App& app)
101937cce918SMarri Devender Rao {
10207e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1021*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
10227e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
10237e860f15SJohn Edward Broadbent             [](const crow::Request&,
10247e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10258d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
10267e860f15SJohn Edward Broadbent                     {"@odata.id",
10277e860f15SJohn Edward Broadbent                      "/redfish/v1/AccountService/LDAP/Certificates"},
10287e860f15SJohn Edward Broadbent                     {"@odata.type",
10297e860f15SJohn Edward Broadbent                      "#CertificateCollection.CertificateCollection"},
103037cce918SMarri Devender Rao                     {"Name", "LDAP Certificates Collection"},
10317e860f15SJohn Edward Broadbent                     {"Description",
10327e860f15SJohn Edward Broadbent                      "A Collection of LDAP certificate instances"}};
10338d1b46d7Szhanghch05 
103437cce918SMarri Devender Rao                 crow::connections::systemBus->async_method_call(
103537cce918SMarri Devender Rao                     [asyncResp](const boost::system::error_code ec,
103637cce918SMarri Devender Rao                                 const ManagedObjectType& certs) {
10377e860f15SJohn Edward Broadbent                         nlohmann::json& members =
10387e860f15SJohn Edward Broadbent                             asyncResp->res.jsonValue["Members"];
10399c8e039eSJonathan Doman                         nlohmann::json& count =
10409c8e039eSJonathan Doman                             asyncResp->res.jsonValue["Members@odata.count"];
10419c8e039eSJonathan Doman                         members = nlohmann::json::array();
10429c8e039eSJonathan Doman                         count = 0;
104337cce918SMarri Devender Rao                         if (ec)
104437cce918SMarri Devender Rao                         {
10457e860f15SJohn Edward Broadbent                             BMCWEB_LOG_WARNING
10467e860f15SJohn Edward Broadbent                                 << "LDAP certificate query failed: " << ec;
104737cce918SMarri Devender Rao                             return;
104837cce918SMarri Devender Rao                         }
104937cce918SMarri Devender Rao                         for (const auto& cert : certs)
105037cce918SMarri Devender Rao                         {
105137cce918SMarri Devender Rao                             long id = getIDFromURL(cert.first.str);
105237cce918SMarri Devender Rao                             if (id >= 0)
105337cce918SMarri Devender Rao                             {
105437cce918SMarri Devender Rao                                 members.push_back(
105537cce918SMarri Devender Rao                                     {{"@odata.id", "/redfish/v1/AccountService/"
105637cce918SMarri Devender Rao                                                    "LDAP/Certificates/" +
105737cce918SMarri Devender Rao                                                        std::to_string(id)}});
105837cce918SMarri Devender Rao                             }
105937cce918SMarri Devender Rao                         }
10609c8e039eSJonathan Doman                         count = members.size();
106137cce918SMarri Devender Rao                     },
106237cce918SMarri Devender Rao                     certs::ldapServiceName, certs::ldapObjectPath,
106337cce918SMarri Devender Rao                     certs::dbusObjManagerIntf, "GetManagedObjects");
10647e860f15SJohn Edward Broadbent             });
106537cce918SMarri Devender Rao 
10667e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1067*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
10687e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
10697e860f15SJohn Edward Broadbent             [](const crow::Request& req,
10707e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10717e860f15SJohn Edward Broadbent                 std::string certFileBody =
10727e860f15SJohn Edward Broadbent                     getCertificateFromReqBody(asyncResp, req);
107358eb238fSKowalski, Kamil 
107458eb238fSKowalski, Kamil                 if (certFileBody.empty())
107558eb238fSKowalski, Kamil                 {
10767e860f15SJohn Edward Broadbent                     BMCWEB_LOG_ERROR
10777e860f15SJohn Edward Broadbent                         << "Cannot get certificate from request body.";
1078a08752f5SZbigniew Kurzynski                     messages::unrecognizedRequestBody(asyncResp->res);
107958eb238fSKowalski, Kamil                     return;
108058eb238fSKowalski, Kamil                 }
108158eb238fSKowalski, Kamil 
108258eb238fSKowalski, Kamil                 std::shared_ptr<CertificateFile> certFile =
108358eb238fSKowalski, Kamil                     std::make_shared<CertificateFile>(certFileBody);
108458eb238fSKowalski, Kamil 
108537cce918SMarri Devender Rao                 crow::connections::systemBus->async_method_call(
1086656ec7e3SZbigniew Kurzynski                     [asyncResp, certFile](const boost::system::error_code ec,
1087656ec7e3SZbigniew Kurzynski                                           const std::string& objectPath) {
108837cce918SMarri Devender Rao                         if (ec)
108937cce918SMarri Devender Rao                         {
109037cce918SMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
109137cce918SMarri Devender Rao                             messages::internalError(asyncResp->res);
109237cce918SMarri Devender Rao                             return;
109337cce918SMarri Devender Rao                         }
1094656ec7e3SZbigniew Kurzynski                         long certId = getIDFromURL(objectPath);
1095656ec7e3SZbigniew Kurzynski                         if (certId < 0)
1096656ec7e3SZbigniew Kurzynski                         {
1097656ec7e3SZbigniew Kurzynski                             BMCWEB_LOG_ERROR << "Invalid objectPath value"
1098656ec7e3SZbigniew Kurzynski                                              << objectPath;
1099656ec7e3SZbigniew Kurzynski                             messages::internalError(asyncResp->res);
1100656ec7e3SZbigniew Kurzynski                             return;
1101656ec7e3SZbigniew Kurzynski                         }
110237cce918SMarri Devender Rao                         std::string certURL =
110337cce918SMarri Devender Rao                             "/redfish/v1/AccountService/LDAP/Certificates/" +
110437cce918SMarri Devender Rao                             std::to_string(certId);
110537cce918SMarri Devender Rao                         getCertificateProperties(asyncResp, objectPath,
110637cce918SMarri Devender Rao                                                  certs::ldapServiceName, certId,
110737cce918SMarri Devender Rao                                                  certURL, "LDAP Certificate");
110837cce918SMarri Devender Rao                         BMCWEB_LOG_DEBUG << "LDAP certificate install file="
110937cce918SMarri Devender Rao                                          << certFile->getCertFilePath();
111037cce918SMarri Devender Rao                     },
111137cce918SMarri Devender Rao                     certs::ldapServiceName, certs::ldapObjectPath,
11127e860f15SJohn Edward Broadbent                     certs::certInstallIntf, "Install",
11137e860f15SJohn Edward Broadbent                     certFile->getCertFilePath());
11147e860f15SJohn Edward Broadbent             });
11157e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificateCollection
111637cce918SMarri Devender Rao 
111737cce918SMarri Devender Rao /**
111837cce918SMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
111937cce918SMarri Devender Rao  * of a component, account or service.
112037cce918SMarri Devender Rao  */
11217e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificate(App& app)
112237cce918SMarri Devender Rao {
11237e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1124*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
11257e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
11267e860f15SJohn Edward Broadbent             [](const crow::Request& req,
11277e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11287e860f15SJohn Edward Broadbent                const std::string&) {
112937cce918SMarri Devender Rao                 long id = getIDFromURL(req.url);
113037cce918SMarri Devender Rao                 if (id < 0)
113137cce918SMarri Devender Rao                 {
113237cce918SMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
113337cce918SMarri Devender Rao                     messages::internalError(asyncResp->res);
113437cce918SMarri Devender Rao                     return;
113537cce918SMarri Devender Rao                 }
11367e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG << "LDAP Certificate ID="
11377e860f15SJohn Edward Broadbent                                  << std::to_string(id);
11387e860f15SJohn Edward Broadbent                 std::string certURL =
11397e860f15SJohn Edward Broadbent                     "/redfish/v1/AccountService/LDAP/Certificates/" +
114037cce918SMarri Devender Rao                     std::to_string(id);
114137cce918SMarri Devender Rao                 std::string objectPath = certs::ldapObjectPath;
114237cce918SMarri Devender Rao                 objectPath += "/";
114337cce918SMarri Devender Rao                 objectPath += std::to_string(id);
11447e860f15SJohn Edward Broadbent                 getCertificateProperties(asyncResp, objectPath,
11457e860f15SJohn Edward Broadbent                                          certs::ldapServiceName, id, certURL,
11467e860f15SJohn Edward Broadbent                                          "LDAP Certificate");
11477e860f15SJohn Edward Broadbent             });
11487e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificate
1149cfcd5f6bSMarri Devender Rao /**
1150cfcd5f6bSMarri Devender Rao  * Collection of TrustStoreCertificate certificates
1151cfcd5f6bSMarri Devender Rao  */
11527e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificateCollection(App& app)
1153cfcd5f6bSMarri Devender Rao {
11547e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1155*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
11567e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
11577e860f15SJohn Edward Broadbent             [](const crow::Request&,
11587e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
11598d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
11607e860f15SJohn Edward Broadbent                     {"@odata.id",
11617e860f15SJohn Edward Broadbent                      "/redfish/v1/Managers/bmc/Truststore/Certificates/"},
11627e860f15SJohn Edward Broadbent                     {"@odata.type",
11637e860f15SJohn Edward Broadbent                      "#CertificateCollection.CertificateCollection"},
1164cfcd5f6bSMarri Devender Rao                     {"Name", "TrustStore Certificates Collection"},
1165cfcd5f6bSMarri Devender Rao                     {"Description",
1166cfcd5f6bSMarri Devender Rao                      "A Collection of TrustStore certificate instances"}};
11678d1b46d7Szhanghch05 
1168cfcd5f6bSMarri Devender Rao                 crow::connections::systemBus->async_method_call(
1169cfcd5f6bSMarri Devender Rao                     [asyncResp](const boost::system::error_code ec,
1170cfcd5f6bSMarri Devender Rao                                 const ManagedObjectType& certs) {
1171cfcd5f6bSMarri Devender Rao                         if (ec)
1172cfcd5f6bSMarri Devender Rao                         {
1173cfcd5f6bSMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1174cfcd5f6bSMarri Devender Rao                             messages::internalError(asyncResp->res);
1175cfcd5f6bSMarri Devender Rao                             return;
1176cfcd5f6bSMarri Devender Rao                         }
11777e860f15SJohn Edward Broadbent                         nlohmann::json& members =
11787e860f15SJohn Edward Broadbent                             asyncResp->res.jsonValue["Members"];
1179cfcd5f6bSMarri Devender Rao                         members = nlohmann::json::array();
1180cfcd5f6bSMarri Devender Rao                         for (const auto& cert : certs)
1181cfcd5f6bSMarri Devender Rao                         {
1182cfcd5f6bSMarri Devender Rao                             long id = getIDFromURL(cert.first.str);
1183cfcd5f6bSMarri Devender Rao                             if (id >= 0)
1184cfcd5f6bSMarri Devender Rao                             {
1185cfcd5f6bSMarri Devender Rao                                 members.push_back(
1186cfcd5f6bSMarri Devender Rao                                     {{"@odata.id", "/redfish/v1/Managers/bmc/"
1187cfcd5f6bSMarri Devender Rao                                                    "Truststore/Certificates/" +
1188cfcd5f6bSMarri Devender Rao                                                        std::to_string(id)}});
1189cfcd5f6bSMarri Devender Rao                             }
1190cfcd5f6bSMarri Devender Rao                         }
1191cfcd5f6bSMarri Devender Rao                         asyncResp->res.jsonValue["Members@odata.count"] =
1192cfcd5f6bSMarri Devender Rao                             members.size();
1193cfcd5f6bSMarri Devender Rao                     },
1194cfcd5f6bSMarri Devender Rao                     certs::authorityServiceName, certs::authorityObjectPath,
1195cfcd5f6bSMarri Devender Rao                     certs::dbusObjManagerIntf, "GetManagedObjects");
11967e860f15SJohn Edward Broadbent             });
1197cfcd5f6bSMarri Devender Rao 
11987e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1199*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
12007e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
12017e860f15SJohn Edward Broadbent             [](const crow::Request& req,
12027e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
12037e860f15SJohn Edward Broadbent                 std::string certFileBody =
12047e860f15SJohn Edward Broadbent                     getCertificateFromReqBody(asyncResp, req);
1205a08752f5SZbigniew Kurzynski 
1206a08752f5SZbigniew Kurzynski                 if (certFileBody.empty())
1207a08752f5SZbigniew Kurzynski                 {
12087e860f15SJohn Edward Broadbent                     BMCWEB_LOG_ERROR
12097e860f15SJohn Edward Broadbent                         << "Cannot get certificate from request body.";
1210a08752f5SZbigniew Kurzynski                     messages::unrecognizedRequestBody(asyncResp->res);
1211a08752f5SZbigniew Kurzynski                     return;
1212a08752f5SZbigniew Kurzynski                 }
1213a08752f5SZbigniew Kurzynski 
1214a08752f5SZbigniew Kurzynski                 std::shared_ptr<CertificateFile> certFile =
1215a08752f5SZbigniew Kurzynski                     std::make_shared<CertificateFile>(certFileBody);
1216cfcd5f6bSMarri Devender Rao                 crow::connections::systemBus->async_method_call(
1217656ec7e3SZbigniew Kurzynski                     [asyncResp, certFile](const boost::system::error_code ec,
1218656ec7e3SZbigniew Kurzynski                                           const std::string& objectPath) {
1219cfcd5f6bSMarri Devender Rao                         if (ec)
1220cfcd5f6bSMarri Devender Rao                         {
1221cfcd5f6bSMarri Devender Rao                             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1222cfcd5f6bSMarri Devender Rao                             messages::internalError(asyncResp->res);
1223cfcd5f6bSMarri Devender Rao                             return;
1224cfcd5f6bSMarri Devender Rao                         }
1225656ec7e3SZbigniew Kurzynski                         long certId = getIDFromURL(objectPath);
1226656ec7e3SZbigniew Kurzynski                         if (certId < 0)
1227656ec7e3SZbigniew Kurzynski                         {
1228656ec7e3SZbigniew Kurzynski                             BMCWEB_LOG_ERROR << "Invalid objectPath value"
1229656ec7e3SZbigniew Kurzynski                                              << objectPath;
1230656ec7e3SZbigniew Kurzynski                             messages::internalError(asyncResp->res);
1231656ec7e3SZbigniew Kurzynski                             return;
1232656ec7e3SZbigniew Kurzynski                         }
1233cfcd5f6bSMarri Devender Rao                         std::string certURL = "/redfish/v1/Managers/bmc/"
1234cfcd5f6bSMarri Devender Rao                                               "Truststore/Certificates/" +
1235cfcd5f6bSMarri Devender Rao                                               std::to_string(certId);
1236656ec7e3SZbigniew Kurzynski 
12377e860f15SJohn Edward Broadbent                         getCertificateProperties(
12387e860f15SJohn Edward Broadbent                             asyncResp, objectPath, certs::authorityServiceName,
12397e860f15SJohn Edward Broadbent                             certId, certURL, "TrustStore Certificate");
12407e860f15SJohn Edward Broadbent                         BMCWEB_LOG_DEBUG
12417e860f15SJohn Edward Broadbent                             << "TrustStore certificate install file="
1242cfcd5f6bSMarri Devender Rao                             << certFile->getCertFilePath();
1243cfcd5f6bSMarri Devender Rao                     },
1244cfcd5f6bSMarri Devender Rao                     certs::authorityServiceName, certs::authorityObjectPath,
12457e860f15SJohn Edward Broadbent                     certs::certInstallIntf, "Install",
12467e860f15SJohn Edward Broadbent                     certFile->getCertFilePath());
12477e860f15SJohn Edward Broadbent             });
12487e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificateCollection
1249cfcd5f6bSMarri Devender Rao 
1250cfcd5f6bSMarri Devender Rao /**
1251cfcd5f6bSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
1252cfcd5f6bSMarri Devender Rao  * of a component, account or service.
1253cfcd5f6bSMarri Devender Rao  */
12547e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificate(App& app)
1255cfcd5f6bSMarri Devender Rao {
12567e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1257*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
12587e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
12597e860f15SJohn Edward Broadbent             [](const crow::Request& req,
12607e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12617e860f15SJohn Edward Broadbent                const std::string&) {
1262cfcd5f6bSMarri Devender Rao                 long id = getIDFromURL(req.url);
1263cfcd5f6bSMarri Devender Rao                 if (id < 0)
1264cfcd5f6bSMarri Devender Rao                 {
1265cfcd5f6bSMarri Devender Rao                     BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
1266cfcd5f6bSMarri Devender Rao                     messages::internalError(asyncResp->res);
1267cfcd5f6bSMarri Devender Rao                     return;
1268cfcd5f6bSMarri Devender Rao                 }
1269cfcd5f6bSMarri Devender Rao                 BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID="
1270cfcd5f6bSMarri Devender Rao                                  << std::to_string(id);
1271cfcd5f6bSMarri Devender Rao                 std::string certURL =
1272cfcd5f6bSMarri Devender Rao                     "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1273cfcd5f6bSMarri Devender Rao                     std::to_string(id);
1274cfcd5f6bSMarri Devender Rao                 std::string objectPath = certs::authorityObjectPath;
1275cfcd5f6bSMarri Devender Rao                 objectPath += "/";
1276cfcd5f6bSMarri Devender Rao                 objectPath += std::to_string(id);
1277cfcd5f6bSMarri Devender Rao                 getCertificateProperties(asyncResp, objectPath,
12787e860f15SJohn Edward Broadbent                                          certs::authorityServiceName, id,
12797e860f15SJohn Edward Broadbent                                          certURL, "TrustStore Certificate");
12807e860f15SJohn Edward Broadbent             });
128107a60299SZbigniew Kurzynski 
12827e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1283*72048780SAbhishek Patel         .privileges({{"ConfigureManager"}})
12847e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
12857e860f15SJohn Edward Broadbent             [](const crow::Request& req,
12867e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12877e860f15SJohn Edward Broadbent                const std::string& param) {
12887e860f15SJohn Edward Broadbent                 if (param.empty())
128907a60299SZbigniew Kurzynski                 {
129007a60299SZbigniew Kurzynski                     messages::internalError(asyncResp->res);
129107a60299SZbigniew Kurzynski                     return;
129207a60299SZbigniew Kurzynski                 }
129307a60299SZbigniew Kurzynski 
129407a60299SZbigniew Kurzynski                 long id = getIDFromURL(req.url);
129507a60299SZbigniew Kurzynski                 if (id < 0)
129607a60299SZbigniew Kurzynski                 {
129707a60299SZbigniew Kurzynski                     BMCWEB_LOG_ERROR << "Invalid url value: " << req.url;
12987e860f15SJohn Edward Broadbent                     messages::resourceNotFound(asyncResp->res,
12997e860f15SJohn Edward Broadbent                                                "TrustStore Certificate",
130007a60299SZbigniew Kurzynski                                                std::string(req.url));
130107a60299SZbigniew Kurzynski                     return;
130207a60299SZbigniew Kurzynski                 }
130307a60299SZbigniew Kurzynski                 BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID="
130407a60299SZbigniew Kurzynski                                  << std::to_string(id);
130507a60299SZbigniew Kurzynski                 std::string certPath = certs::authorityObjectPath;
130607a60299SZbigniew Kurzynski                 certPath += "/";
130707a60299SZbigniew Kurzynski                 certPath += std::to_string(id);
130807a60299SZbigniew Kurzynski 
130907a60299SZbigniew Kurzynski                 crow::connections::systemBus->async_method_call(
131007a60299SZbigniew Kurzynski                     [asyncResp, id](const boost::system::error_code ec) {
131107a60299SZbigniew Kurzynski                         if (ec)
131207a60299SZbigniew Kurzynski                         {
131307a60299SZbigniew Kurzynski                             messages::resourceNotFound(asyncResp->res,
131407a60299SZbigniew Kurzynski                                                        "TrustStore Certificate",
131507a60299SZbigniew Kurzynski                                                        std::to_string(id));
131607a60299SZbigniew Kurzynski                             return;
131707a60299SZbigniew Kurzynski                         }
131807a60299SZbigniew Kurzynski                         BMCWEB_LOG_INFO << "Certificate deleted";
13197e860f15SJohn Edward Broadbent                         asyncResp->res.result(
13207e860f15SJohn Edward Broadbent                             boost::beast::http::status::no_content);
132107a60299SZbigniew Kurzynski                     },
132207a60299SZbigniew Kurzynski                     certs::authorityServiceName, certPath, certs::objDeleteIntf,
132307a60299SZbigniew Kurzynski                     "Delete");
13247e860f15SJohn Edward Broadbent             });
13257e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
13265968caeeSMarri Devender Rao } // namespace redfish
1327