xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 002d39b4a7a5ed7166e2acad84e0943c3def9492)
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>
690d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp>
7168e20c1SEd Tanous #include <dbus_utility.hpp>
845ca1b86SEd Tanous #include <query.hpp>
9ed398213SEd Tanous #include <registries/privilege_registry.hpp>
101214b7e7SGunnar Mills 
115968caeeSMarri Devender Rao namespace redfish
125968caeeSMarri Devender Rao {
135968caeeSMarri Devender Rao namespace certs
145968caeeSMarri Devender Rao {
155968caeeSMarri Devender Rao constexpr char const* httpsObjectPath =
165968caeeSMarri Devender Rao     "/xyz/openbmc_project/certs/server/https";
175968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
185968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
1907a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
205968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
215968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
225968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
2337cce918SMarri Devender Rao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
2437cce918SMarri Devender Rao constexpr char const* httpsServiceName =
2537cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
2637cce918SMarri Devender Rao constexpr char const* ldapServiceName =
2737cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
28cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
29cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
30cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
31cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
325968caeeSMarri Devender Rao } // namespace certs
335968caeeSMarri Devender Rao 
345968caeeSMarri Devender Rao /**
355968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
365968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
375968caeeSMarri Devender Rao  * are installed.
385968caeeSMarri Devender Rao  */
397e860f15SJohn Edward Broadbent 
405968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate
414e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish
425968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF
435968caeeSMarri Devender Rao // publish Privilege details for certificate service
445968caeeSMarri Devender Rao 
457e860f15SJohn Edward Broadbent inline void requestRoutesCertificateService(App& app)
465968caeeSMarri Devender Rao {
477e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
48ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateService)
49*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
50*002d39b4SEd Tanous             [&app](const crow::Request& req,
51*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
5245ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
5345ca1b86SEd Tanous         {
5445ca1b86SEd Tanous             return;
5545ca1b86SEd Tanous         }
561476687dSEd Tanous 
571476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
581476687dSEd Tanous             "#CertificateService.v1_0_0.CertificateService";
591476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
601476687dSEd Tanous             "/redfish/v1/CertificateService";
611476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "CertificateService";
621476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "Certificate Service";
631476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
641476687dSEd Tanous             "Actions available to manage certificates";
6572048780SAbhishek Patel         // /redfish/v1/CertificateService/CertificateLocations is something
6672048780SAbhishek Patel         // only ConfigureManager can access then only display when the user
6772048780SAbhishek Patel         // has permissions ConfigureManager
6872048780SAbhishek Patel         Privileges effectiveUserPrivileges =
6972048780SAbhishek Patel             redfish::getUserPrivileges(req.userRole);
7072048780SAbhishek Patel         if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
7172048780SAbhishek Patel                                              effectiveUserPrivileges))
7272048780SAbhishek Patel         {
731476687dSEd Tanous             asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
741476687dSEd Tanous                 "/redfish/v1/CertificateService/CertificateLocations";
7572048780SAbhishek Patel         }
760fda0f12SGeorge Liu         asyncResp->res
77*002d39b4SEd Tanous             .jsonValue["Actions"]["#CertificateService.ReplaceCertificate"] = {
780fda0f12SGeorge Liu             {"target",
790fda0f12SGeorge Liu              "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"},
805968caeeSMarri Devender Rao             {"CertificateType@Redfish.AllowableValues", {"PEM"}}};
817e860f15SJohn Edward Broadbent         asyncResp->res
827e860f15SJohn Edward Broadbent             .jsonValue["Actions"]["#CertificateService.GenerateCSR"] = {
830fda0f12SGeorge Liu             {"target",
840fda0f12SGeorge Liu              "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"}};
857e860f15SJohn Edward Broadbent         });
867e860f15SJohn Edward Broadbent } // requestRoutesCertificateService
8737cce918SMarri Devender Rao 
885968caeeSMarri Devender Rao /**
895968caeeSMarri Devender Rao  * @brief Find the ID specified in the URL
905968caeeSMarri Devender Rao  * Finds the numbers specified after the last "/" in the URL and returns.
915968caeeSMarri Devender Rao  * @param[in] path URL
925968caeeSMarri Devender Rao  * @return -1 on failure and number on success
935968caeeSMarri Devender Rao  */
9423a21a1cSEd Tanous inline long getIDFromURL(const std::string_view url)
955968caeeSMarri Devender Rao {
96f23b7296SEd Tanous     std::size_t found = url.rfind('/');
975968caeeSMarri Devender Rao     if (found == std::string::npos)
985968caeeSMarri Devender Rao     {
995968caeeSMarri Devender Rao         return -1;
1005968caeeSMarri Devender Rao     }
101e6604b11SIwona Klimaszewska 
1025968caeeSMarri Devender Rao     if ((found + 1) < url.length())
1035968caeeSMarri Devender Rao     {
1045968caeeSMarri Devender Rao         std::string_view str = url.substr(found + 1);
105e6604b11SIwona Klimaszewska 
106e6604b11SIwona Klimaszewska         return boost::convert<long>(str, boost::cnv::strtol()).value_or(-1);
1075968caeeSMarri Devender Rao     }
108e6604b11SIwona Klimaszewska 
1095968caeeSMarri Devender Rao     return -1;
1105968caeeSMarri Devender Rao }
1115968caeeSMarri Devender Rao 
1128d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
1138d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11458eb238fSKowalski, Kamil     const crow::Request& req)
11558eb238fSKowalski, Kamil {
11658eb238fSKowalski, Kamil     nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
11758eb238fSKowalski, Kamil 
11858eb238fSKowalski, Kamil     if (reqJson.is_discarded())
11958eb238fSKowalski, Kamil     {
12058eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
12158eb238fSKowalski, Kamil         return req.body;
12258eb238fSKowalski, Kamil     }
12358eb238fSKowalski, Kamil 
12458eb238fSKowalski, Kamil     std::string certificate;
12558eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
12658eb238fSKowalski, Kamil 
12715ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
12815ed6780SWilly Tu                                   certificate, "CertificateType",
12915ed6780SWilly Tu                                   certificateType))
13058eb238fSKowalski, Kamil     {
13158eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
13258eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
133abb93cddSEd Tanous         return {};
13458eb238fSKowalski, Kamil     }
13558eb238fSKowalski, Kamil 
13658eb238fSKowalski, Kamil     if (*certificateType != "PEM")
13758eb238fSKowalski, Kamil     {
13858eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
13958eb238fSKowalski, Kamil                                          "CertificateType");
140abb93cddSEd Tanous         return {};
14158eb238fSKowalski, Kamil     }
14258eb238fSKowalski, Kamil 
14358eb238fSKowalski, Kamil     return certificate;
14458eb238fSKowalski, Kamil }
14558eb238fSKowalski, Kamil 
1465968caeeSMarri Devender Rao /**
1475968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
1485968caeeSMarri Devender Rao  */
1495968caeeSMarri Devender Rao class CertificateFile
1505968caeeSMarri Devender Rao {
1515968caeeSMarri Devender Rao   public:
1525968caeeSMarri Devender Rao     CertificateFile() = delete;
1535968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
1545968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
1555968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
1565968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
1575968caeeSMarri Devender Rao     CertificateFile(const std::string& certString)
1585968caeeSMarri Devender Rao     {
15972d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1605207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1615207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1625207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
163e662eae8SEd Tanous         if (tempDirectory != nullptr)
1645968caeeSMarri Devender Rao         {
1655968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1665968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1675968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1685968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1695968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1705968caeeSMarri Devender Rao             out << certString;
1715968caeeSMarri Devender Rao             out.close();
1728cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Creating certificate file"
1738cc8edecSEd Tanous                              << certificateFile.string();
1745968caeeSMarri Devender Rao         }
1755968caeeSMarri Devender Rao     }
1765968caeeSMarri Devender Rao     ~CertificateFile()
1775968caeeSMarri Devender Rao     {
1785968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1795968caeeSMarri Devender Rao         {
1808cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Removing certificate file"
1818cc8edecSEd Tanous                              << certificateFile.string();
18223a21a1cSEd Tanous             std::error_code ec;
18323a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
18423a21a1cSEd Tanous             if (ec)
1855968caeeSMarri Devender Rao             {
1865968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1878cc8edecSEd Tanous                                  << certDirectory.string();
1885968caeeSMarri Devender Rao             }
1895968caeeSMarri Devender Rao         }
1905968caeeSMarri Devender Rao     }
1915968caeeSMarri Devender Rao     std::string getCertFilePath()
1925968caeeSMarri Devender Rao     {
1935968caeeSMarri Devender Rao         return certificateFile;
1945968caeeSMarri Devender Rao     }
1955968caeeSMarri Devender Rao 
1965968caeeSMarri Devender Rao   private:
1975968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1985968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1995968caeeSMarri Devender Rao };
2005968caeeSMarri Devender Rao 
20130215816SMarri Devender Rao static std::unique_ptr<sdbusplus::bus::match::match> csrMatcher;
20230215816SMarri Devender Rao /**
20330215816SMarri Devender Rao  * @brief Read data from CSR D-bus object and set to response
20430215816SMarri Devender Rao  *
20530215816SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
20630215816SMarri Devender Rao  * @param[in] certURI Link to certifiate collection URI
20730215816SMarri Devender Rao  * @param[in] service D-Bus service name
20830215816SMarri Devender Rao  * @param[in] certObjPath certificate D-Bus object path
20930215816SMarri Devender Rao  * @param[in] csrObjPath CSR D-Bus object path
21030215816SMarri Devender Rao  * @return None
21130215816SMarri Devender Rao  */
2128d1b46d7Szhanghch05 static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21330215816SMarri Devender Rao                    const std::string& certURI, const std::string& service,
21430215816SMarri Devender Rao                    const std::string& certObjPath,
21530215816SMarri Devender Rao                    const std::string& csrObjPath)
21630215816SMarri Devender Rao {
21730215816SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
21830215816SMarri Devender Rao                      << " CSRObjectPath=" << csrObjPath
21930215816SMarri Devender Rao                      << " service=" << service;
22030215816SMarri Devender Rao     crow::connections::systemBus->async_method_call(
22130215816SMarri Devender Rao         [asyncResp, certURI](const boost::system::error_code ec,
22230215816SMarri Devender Rao                              const std::string& csr) {
22330215816SMarri Devender Rao         if (ec)
22430215816SMarri Devender Rao         {
22530215816SMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
22630215816SMarri Devender Rao             messages::internalError(asyncResp->res);
22730215816SMarri Devender Rao             return;
22830215816SMarri Devender Rao         }
22930215816SMarri Devender Rao         if (csr.empty())
23030215816SMarri Devender Rao         {
23130215816SMarri Devender Rao             BMCWEB_LOG_ERROR << "CSR read is empty";
23230215816SMarri Devender Rao             messages::internalError(asyncResp->res);
23330215816SMarri Devender Rao             return;
23430215816SMarri Devender Rao         }
23530215816SMarri Devender Rao         asyncResp->res.jsonValue["CSRString"] = csr;
2361476687dSEd Tanous         asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
2371476687dSEd Tanous             certURI;
23830215816SMarri Devender Rao         },
23930215816SMarri Devender Rao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
24030215816SMarri Devender Rao }
24130215816SMarri Devender Rao 
24230215816SMarri Devender Rao /**
24330215816SMarri Devender Rao  * Action to Generate CSR
24430215816SMarri Devender Rao  */
2457e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionGenerateCSR(App& app)
24630215816SMarri Devender Rao {
2470fda0f12SGeorge Liu     BMCWEB_ROUTE(
2480fda0f12SGeorge Liu         app,
2490fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
2505344ab8eSAbhishek Patel         .privileges(redfish::privileges::postCertificateService)
251*002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
252*002d39b4SEd Tanous             [&app](const crow::Request& req,
2537e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
25445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
25545ca1b86SEd Tanous         {
25645ca1b86SEd Tanous             return;
25745ca1b86SEd Tanous         }
2582c70f800SEd Tanous         static const int rsaKeyBitLength = 2048;
2598d1b46d7Szhanghch05 
26030215816SMarri Devender Rao         // Required parameters
26130215816SMarri Devender Rao         std::string city;
26230215816SMarri Devender Rao         std::string commonName;
26330215816SMarri Devender Rao         std::string country;
26430215816SMarri Devender Rao         std::string organization;
26530215816SMarri Devender Rao         std::string organizationalUnit;
26630215816SMarri Devender Rao         std::string state;
26730215816SMarri Devender Rao         nlohmann::json certificateCollection;
26830215816SMarri Devender Rao 
26930215816SMarri Devender Rao         // Optional parameters
27030215816SMarri Devender Rao         std::optional<std::vector<std::string>> optAlternativeNames =
27130215816SMarri Devender Rao             std::vector<std::string>();
27230215816SMarri Devender Rao         std::optional<std::string> optContactPerson = "";
27330215816SMarri Devender Rao         std::optional<std::string> optChallengePassword = "";
27430215816SMarri Devender Rao         std::optional<std::string> optEmail = "";
27530215816SMarri Devender Rao         std::optional<std::string> optGivenName = "";
27630215816SMarri Devender Rao         std::optional<std::string> optInitials = "";
2772c70f800SEd Tanous         std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
278aaf3206fSVernon Mauery         std::optional<std::string> optKeyCurveId = "secp384r1";
27930215816SMarri Devender Rao         std::optional<std::string> optKeyPairAlgorithm = "EC";
28030215816SMarri Devender Rao         std::optional<std::vector<std::string>> optKeyUsage =
28130215816SMarri Devender Rao             std::vector<std::string>();
28230215816SMarri Devender Rao         std::optional<std::string> optSurname = "";
28330215816SMarri Devender Rao         std::optional<std::string> optUnstructuredName = "";
28415ed6780SWilly Tu         if (!json_util::readJsonAction(
2850fda0f12SGeorge Liu                 req, asyncResp->res, "City", city, "CommonName", commonName,
2860fda0f12SGeorge Liu                 "ContactPerson", optContactPerson, "Country", country,
2870fda0f12SGeorge Liu                 "Organization", organization, "OrganizationalUnit",
2880fda0f12SGeorge Liu                 organizationalUnit, "State", state, "CertificateCollection",
289*002d39b4SEd Tanous                 certificateCollection, "AlternativeNames", optAlternativeNames,
290*002d39b4SEd Tanous                 "ChallengePassword", optChallengePassword, "Email", optEmail,
291*002d39b4SEd Tanous                 "GivenName", optGivenName, "Initials", optInitials,
292*002d39b4SEd Tanous                 "KeyBitLength", optKeyBitLength, "KeyCurveId", optKeyCurveId,
2930fda0f12SGeorge Liu                 "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
2940fda0f12SGeorge Liu                 optKeyUsage, "Surname", optSurname, "UnstructuredName",
2950fda0f12SGeorge Liu                 optUnstructuredName))
29630215816SMarri Devender Rao         {
29730215816SMarri Devender Rao             return;
29830215816SMarri Devender Rao         }
29930215816SMarri Devender Rao 
30030215816SMarri Devender Rao         // bmcweb has no way to store or decode a private key challenge
3017e860f15SJohn Edward Broadbent         // password, which will likely cause bmcweb to crash on startup
3027e860f15SJohn Edward Broadbent         // if this is not set on a post so not allowing the user to set
3037e860f15SJohn Edward Broadbent         // value
30426f6976fSEd Tanous         if (!optChallengePassword->empty())
30530215816SMarri Devender Rao         {
306*002d39b4SEd Tanous             messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
307*002d39b4SEd Tanous                                                   "ChallengePassword");
30830215816SMarri Devender Rao             return;
30930215816SMarri Devender Rao         }
31030215816SMarri Devender Rao 
31130215816SMarri Devender Rao         std::string certURI;
312*002d39b4SEd Tanous         if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
313*002d39b4SEd Tanous                                           "@odata.id", certURI))
31430215816SMarri Devender Rao         {
31530215816SMarri Devender Rao             return;
31630215816SMarri Devender Rao         }
31730215816SMarri Devender Rao 
31830215816SMarri Devender Rao         std::string objectPath;
31930215816SMarri Devender Rao         std::string service;
3200fda0f12SGeorge Liu         if (boost::starts_with(
3210fda0f12SGeorge Liu                 certURI,
3220fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
32330215816SMarri Devender Rao         {
32430215816SMarri Devender Rao             objectPath = certs::httpsObjectPath;
32530215816SMarri Devender Rao             service = certs::httpsServiceName;
32630215816SMarri Devender Rao         }
3273b7f0149SMarri Devender Rao         else if (boost::starts_with(
328*002d39b4SEd Tanous                      certURI, "/redfish/v1/AccountService/LDAP/Certificates"))
3293b7f0149SMarri Devender Rao         {
3303b7f0149SMarri Devender Rao             objectPath = certs::ldapObjectPath;
3313b7f0149SMarri Devender Rao             service = certs::ldapServiceName;
3323b7f0149SMarri Devender Rao         }
33330215816SMarri Devender Rao         else
33430215816SMarri Devender Rao         {
33530215816SMarri Devender Rao             messages::actionParameterNotSupported(
33630215816SMarri Devender Rao                 asyncResp->res, "CertificateCollection", "GenerateCSR");
33730215816SMarri Devender Rao             return;
33830215816SMarri Devender Rao         }
33930215816SMarri Devender Rao 
34030215816SMarri Devender Rao         // supporting only EC and RSA algorithm
3410fda0f12SGeorge Liu         if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
34230215816SMarri Devender Rao         {
34330215816SMarri Devender Rao             messages::actionParameterNotSupported(
34430215816SMarri Devender Rao                 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
34530215816SMarri Devender Rao             return;
34630215816SMarri Devender Rao         }
34730215816SMarri Devender Rao 
3487e860f15SJohn Edward Broadbent         // supporting only 2048 key bit length for RSA algorithm due to
3497e860f15SJohn Edward Broadbent         // time consumed in generating private key
35030215816SMarri Devender Rao         if (*optKeyPairAlgorithm == "RSA" &&
3512c70f800SEd Tanous             *optKeyBitLength != rsaKeyBitLength)
35230215816SMarri Devender Rao         {
353*002d39b4SEd Tanous             messages::propertyValueNotInList(asyncResp->res,
354*002d39b4SEd Tanous                                              std::to_string(*optKeyBitLength),
35530215816SMarri Devender Rao                                              "KeyBitLength");
35630215816SMarri Devender Rao             return;
35730215816SMarri Devender Rao         }
35830215816SMarri Devender Rao 
35930215816SMarri Devender Rao         // validate KeyUsage supporting only 1 type based on URL
3600fda0f12SGeorge Liu         if (boost::starts_with(
3610fda0f12SGeorge Liu                 certURI,
3620fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
36330215816SMarri Devender Rao         {
36426f6976fSEd Tanous             if (optKeyUsage->empty())
36530215816SMarri Devender Rao             {
36630215816SMarri Devender Rao                 optKeyUsage->push_back("ServerAuthentication");
36730215816SMarri Devender Rao             }
36830215816SMarri Devender Rao             else if (optKeyUsage->size() == 1)
36930215816SMarri Devender Rao             {
37030215816SMarri Devender Rao                 if ((*optKeyUsage)[0] != "ServerAuthentication")
37130215816SMarri Devender Rao                 {
37230215816SMarri Devender Rao                     messages::propertyValueNotInList(
37330215816SMarri Devender Rao                         asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
37430215816SMarri Devender Rao                     return;
37530215816SMarri Devender Rao                 }
37630215816SMarri Devender Rao             }
37730215816SMarri Devender Rao             else
37830215816SMarri Devender Rao             {
37930215816SMarri Devender Rao                 messages::actionParameterNotSupported(
38030215816SMarri Devender Rao                     asyncResp->res, "KeyUsage", "GenerateCSR");
38130215816SMarri Devender Rao                 return;
38230215816SMarri Devender Rao             }
38330215816SMarri Devender Rao         }
3843b7f0149SMarri Devender Rao         else if (boost::starts_with(
385*002d39b4SEd Tanous                      certURI, "/redfish/v1/AccountService/LDAP/Certificates"))
3863b7f0149SMarri Devender Rao         {
38726f6976fSEd Tanous             if (optKeyUsage->empty())
3883b7f0149SMarri Devender Rao             {
3893b7f0149SMarri Devender Rao                 optKeyUsage->push_back("ClientAuthentication");
3903b7f0149SMarri Devender Rao             }
3913b7f0149SMarri Devender Rao             else if (optKeyUsage->size() == 1)
3923b7f0149SMarri Devender Rao             {
3933b7f0149SMarri Devender Rao                 if ((*optKeyUsage)[0] != "ClientAuthentication")
3943b7f0149SMarri Devender Rao                 {
3953b7f0149SMarri Devender Rao                     messages::propertyValueNotInList(
3963b7f0149SMarri Devender Rao                         asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
3973b7f0149SMarri Devender Rao                     return;
3983b7f0149SMarri Devender Rao                 }
3993b7f0149SMarri Devender Rao             }
4003b7f0149SMarri Devender Rao             else
4013b7f0149SMarri Devender Rao             {
4023b7f0149SMarri Devender Rao                 messages::actionParameterNotSupported(
4033b7f0149SMarri Devender Rao                     asyncResp->res, "KeyUsage", "GenerateCSR");
4043b7f0149SMarri Devender Rao                 return;
4053b7f0149SMarri Devender Rao             }
4063b7f0149SMarri Devender Rao         }
40730215816SMarri Devender Rao 
4087e860f15SJohn Edward Broadbent         // Only allow one CSR matcher at a time so setting retry
4097e860f15SJohn Edward Broadbent         // time-out and timer expiry to 10 seconds for now.
4102c70f800SEd Tanous         static const int timeOut = 10;
41130215816SMarri Devender Rao         if (csrMatcher)
41230215816SMarri Devender Rao         {
413*002d39b4SEd Tanous             messages::serviceTemporarilyUnavailable(asyncResp->res,
414*002d39b4SEd Tanous                                                     std::to_string(timeOut));
41530215816SMarri Devender Rao             return;
41630215816SMarri Devender Rao         }
41730215816SMarri Devender Rao 
41830215816SMarri Devender Rao         // Make this static so it survives outside this method
41930215816SMarri Devender Rao         static boost::asio::steady_timer timeout(*req.ioService);
4202c70f800SEd Tanous         timeout.expires_after(std::chrono::seconds(timeOut));
421*002d39b4SEd Tanous         timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
42230215816SMarri Devender Rao             csrMatcher = nullptr;
42330215816SMarri Devender Rao             if (ec)
42430215816SMarri Devender Rao             {
4257e860f15SJohn Edward Broadbent                 // operation_aborted is expected if timer is canceled
4267e860f15SJohn Edward Broadbent                 // before completion.
42730215816SMarri Devender Rao                 if (ec != boost::asio::error::operation_aborted)
42830215816SMarri Devender Rao                 {
42930215816SMarri Devender Rao                     BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
43030215816SMarri Devender Rao                 }
43130215816SMarri Devender Rao                 return;
43230215816SMarri Devender Rao             }
43330215816SMarri Devender Rao             BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
43430215816SMarri Devender Rao             messages::internalError(asyncResp->res);
43530215816SMarri Devender Rao         });
43630215816SMarri Devender Rao 
43730215816SMarri Devender Rao         // create a matcher to wait on CSR object
43830215816SMarri Devender Rao         BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
4390fda0f12SGeorge Liu         std::string match("type='signal',"
44030215816SMarri Devender Rao                           "interface='org.freedesktop.DBus.ObjectManager',"
44130215816SMarri Devender Rao                           "path='" +
44230215816SMarri Devender Rao                           objectPath +
44330215816SMarri Devender Rao                           "',"
44430215816SMarri Devender Rao                           "member='InterfacesAdded'");
44530215816SMarri Devender Rao         csrMatcher = std::make_unique<sdbusplus::bus::match::match>(
44630215816SMarri Devender Rao             *crow::connections::systemBus, match,
44730215816SMarri Devender Rao             [asyncResp, service, objectPath,
44830215816SMarri Devender Rao              certURI](sdbusplus::message::message& m) {
449271584abSEd Tanous             timeout.cancel();
45030215816SMarri Devender Rao             if (m.is_method_error())
45130215816SMarri Devender Rao             {
45230215816SMarri Devender Rao                 BMCWEB_LOG_ERROR << "Dbus method error!!!";
45330215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
45430215816SMarri Devender Rao                 return;
45530215816SMarri Devender Rao             }
456b9d36b47SEd Tanous 
457b9d36b47SEd Tanous             dbus::utility::DBusInteracesMap interfacesProperties;
458b9d36b47SEd Tanous 
45930215816SMarri Devender Rao             sdbusplus::message::object_path csrObjectPath;
46030215816SMarri Devender Rao             m.read(csrObjectPath, interfacesProperties);
4610fda0f12SGeorge Liu             BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
46230215816SMarri Devender Rao             for (auto& interface : interfacesProperties)
46330215816SMarri Devender Rao             {
4640fda0f12SGeorge Liu                 if (interface.first == "xyz.openbmc_project.Certs.CSR")
46530215816SMarri Devender Rao                 {
46630215816SMarri Devender Rao                     getCSR(asyncResp, certURI, service, objectPath,
46730215816SMarri Devender Rao                            csrObjectPath.str);
46830215816SMarri Devender Rao                     break;
46930215816SMarri Devender Rao                 }
47030215816SMarri Devender Rao             }
47130215816SMarri Devender Rao             });
47230215816SMarri Devender Rao         crow::connections::systemBus->async_method_call(
473914e2d5dSEd Tanous             [asyncResp](const boost::system::error_code ec,
474cb13a392SEd Tanous                         const std::string&) {
47530215816SMarri Devender Rao             if (ec)
47630215816SMarri Devender Rao             {
477*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
47830215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
47930215816SMarri Devender Rao                 return;
48030215816SMarri Devender Rao             }
48130215816SMarri Devender Rao             },
48230215816SMarri Devender Rao             service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
483*002d39b4SEd Tanous             "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
484*002d39b4SEd Tanous             commonName, *optContactPerson, country, *optEmail, *optGivenName,
485*002d39b4SEd Tanous             *optInitials, *optKeyBitLength, *optKeyCurveId,
4860fda0f12SGeorge Liu             *optKeyPairAlgorithm, *optKeyUsage, organization,
4870fda0f12SGeorge Liu             organizationalUnit, state, *optSurname, *optUnstructuredName);
4887e860f15SJohn Edward Broadbent         });
4897e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionGenerateCSR
49030215816SMarri Devender Rao 
4915968caeeSMarri Devender Rao /**
4924e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
4935968caeeSMarri Devender Rao  *
4945968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
4955968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
4965968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
4975968caeeSMarri Devender Rao  * @return None
4985968caeeSMarri Devender Rao  */
4995968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
5005968caeeSMarri Devender Rao                                       const std::string_view value)
5015968caeeSMarri Devender Rao {
5025968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
5035968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
5045968caeeSMarri Devender Rao     while (i != value.end())
5055968caeeSMarri Devender Rao     {
5065968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
5075968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
5085968caeeSMarri Devender Rao         {
50917a897dfSManojkiran Eda             ++i;
5105968caeeSMarri Devender Rao         }
5115968caeeSMarri Devender Rao         if (i == value.end())
5125968caeeSMarri Devender Rao         {
5135968caeeSMarri Devender Rao             break;
5145968caeeSMarri Devender Rao         }
515271584abSEd Tanous         const std::string_view key(tokenBegin,
516271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
51717a897dfSManojkiran Eda         ++i;
5185968caeeSMarri Devender Rao         tokenBegin = i;
5195968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
5205968caeeSMarri Devender Rao         {
52117a897dfSManojkiran Eda             ++i;
5225968caeeSMarri Devender Rao         }
523271584abSEd Tanous         const std::string_view val(tokenBegin,
524271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
5255968caeeSMarri Devender Rao         if (key == "L")
5265968caeeSMarri Devender Rao         {
5275968caeeSMarri Devender Rao             out["City"] = val;
5285968caeeSMarri Devender Rao         }
5295968caeeSMarri Devender Rao         else if (key == "CN")
5305968caeeSMarri Devender Rao         {
5315968caeeSMarri Devender Rao             out["CommonName"] = val;
5325968caeeSMarri Devender Rao         }
5335968caeeSMarri Devender Rao         else if (key == "C")
5345968caeeSMarri Devender Rao         {
5355968caeeSMarri Devender Rao             out["Country"] = val;
5365968caeeSMarri Devender Rao         }
5375968caeeSMarri Devender Rao         else if (key == "O")
5385968caeeSMarri Devender Rao         {
5395968caeeSMarri Devender Rao             out["Organization"] = val;
5405968caeeSMarri Devender Rao         }
5415968caeeSMarri Devender Rao         else if (key == "OU")
5425968caeeSMarri Devender Rao         {
5435968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
5445968caeeSMarri Devender Rao         }
5455968caeeSMarri Devender Rao         else if (key == "ST")
5465968caeeSMarri Devender Rao         {
5475968caeeSMarri Devender Rao             out["State"] = val;
5485968caeeSMarri Devender Rao         }
5495968caeeSMarri Devender Rao         // skip comma character
5505968caeeSMarri Devender Rao         if (i != value.end())
5515968caeeSMarri Devender Rao         {
55217a897dfSManojkiran Eda             ++i;
5535968caeeSMarri Devender Rao         }
5545968caeeSMarri Devender Rao     }
5555968caeeSMarri Devender Rao }
5565968caeeSMarri Devender Rao 
5575968caeeSMarri Devender Rao /**
5585968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
5595968caeeSMarri Devender Rao  * message
5605968caeeSMarri Devender Rao  *
5615968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
5625968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
5635968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
5645968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
5655968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
5665968caeeSMarri Devender Rao  * @return None
5675968caeeSMarri Devender Rao  */
5685968caeeSMarri Devender Rao static void getCertificateProperties(
5698d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5708d1b46d7Szhanghch05     const std::string& objectPath, const std::string& service, long certId,
5718d1b46d7Szhanghch05     const std::string& certURL, const std::string& name)
5725968caeeSMarri Devender Rao {
5735968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
5745968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
5755968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
576b9d36b47SEd Tanous         [asyncResp, certURL, certId,
577b9d36b47SEd Tanous          name](const boost::system::error_code ec,
578b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& 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         }
5861476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = certURL;
5871476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
5881476687dSEd Tanous             "#Certificate.v1_0_0.Certificate";
5891476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = std::to_string(certId);
5901476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = name;
5911476687dSEd Tanous         asyncResp->res.jsonValue["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);
599e662eae8SEd Tanous                 if (value != nullptr)
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             {
606*002d39b4SEd Tanous                 nlohmann::json& keyUsage = asyncResp->res.jsonValue["KeyUsage"];
6075968caeeSMarri Devender Rao                 keyUsage = nlohmann::json::array();
6085968caeeSMarri Devender Rao                 const std::vector<std::string>* value =
60937cce918SMarri Devender Rao                     std::get_if<std::vector<std::string>>(&property.second);
610e662eae8SEd Tanous                 if (value != nullptr)
6115968caeeSMarri Devender Rao                 {
6125968caeeSMarri Devender Rao                     for (const std::string& usage : *value)
6135968caeeSMarri Devender Rao                     {
6145968caeeSMarri Devender Rao                         keyUsage.push_back(usage);
6155968caeeSMarri Devender Rao                     }
6165968caeeSMarri Devender Rao                 }
6175968caeeSMarri Devender Rao             }
6185968caeeSMarri Devender Rao             else if (property.first == "Issuer")
6195968caeeSMarri Devender Rao             {
6205968caeeSMarri Devender Rao                 const std::string* value =
6215968caeeSMarri Devender Rao                     std::get_if<std::string>(&property.second);
622e662eae8SEd Tanous                 if (value != nullptr)
6235968caeeSMarri Devender Rao                 {
6245968caeeSMarri Devender Rao                     updateCertIssuerOrSubject(
6255968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["Issuer"], *value);
6265968caeeSMarri Devender Rao                 }
6275968caeeSMarri Devender Rao             }
6285968caeeSMarri Devender Rao             else if (property.first == "Subject")
6295968caeeSMarri Devender Rao             {
6305968caeeSMarri Devender Rao                 const std::string* value =
6315968caeeSMarri Devender Rao                     std::get_if<std::string>(&property.second);
632e662eae8SEd Tanous                 if (value != nullptr)
6335968caeeSMarri Devender Rao                 {
6345968caeeSMarri Devender Rao                     updateCertIssuerOrSubject(
63537cce918SMarri Devender Rao                         asyncResp->res.jsonValue["Subject"], *value);
6365968caeeSMarri Devender Rao                 }
6375968caeeSMarri Devender Rao             }
6385968caeeSMarri Devender Rao             else if (property.first == "ValidNotAfter")
6395968caeeSMarri Devender Rao             {
640*002d39b4SEd Tanous                 const uint64_t* value = std::get_if<uint64_t>(&property.second);
641e662eae8SEd Tanous                 if (value != nullptr)
6425968caeeSMarri Devender Rao                 {
6435968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["ValidNotAfter"] =
6441d8782e7SNan Zhou                         crow::utility::getDateTimeUint(*value);
6455968caeeSMarri Devender Rao                 }
6465968caeeSMarri Devender Rao             }
6475968caeeSMarri Devender Rao             else if (property.first == "ValidNotBefore")
6485968caeeSMarri Devender Rao             {
649*002d39b4SEd Tanous                 const uint64_t* value = std::get_if<uint64_t>(&property.second);
650e662eae8SEd Tanous                 if (value != nullptr)
6515968caeeSMarri Devender Rao                 {
6525968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["ValidNotBefore"] =
6531d8782e7SNan Zhou                         crow::utility::getDateTimeUint(*value);
6545968caeeSMarri Devender Rao                 }
6555968caeeSMarri Devender Rao             }
6565968caeeSMarri Devender Rao         }
6575968caeeSMarri Devender Rao         asyncResp->res.addHeader("Location", certURL);
6585968caeeSMarri Devender Rao         },
6595968caeeSMarri Devender Rao         service, objectPath, certs::dbusPropIntf, "GetAll",
6605968caeeSMarri Devender Rao         certs::certPropIntf);
6615968caeeSMarri Devender Rao }
6625968caeeSMarri Devender Rao 
6635968caeeSMarri Devender Rao /**
6645968caeeSMarri Devender Rao  * Action to replace an existing certificate
6655968caeeSMarri Devender Rao  */
6667e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionsReplaceCertificate(App& app)
6675968caeeSMarri Devender Rao {
6680fda0f12SGeorge Liu     BMCWEB_ROUTE(
6690fda0f12SGeorge Liu         app,
6700fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
671ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateService)
672*002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
673*002d39b4SEd Tanous             [&app](const crow::Request& req,
6747e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
67545ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
67645ca1b86SEd Tanous         {
67745ca1b86SEd Tanous             return;
67845ca1b86SEd Tanous         }
6795968caeeSMarri Devender Rao         std::string certificate;
6805968caeeSMarri Devender Rao         nlohmann::json certificateUri;
6815968caeeSMarri Devender Rao         std::optional<std::string> certificateType = "PEM";
6828d1b46d7Szhanghch05 
683*002d39b4SEd Tanous         if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
684*002d39b4SEd Tanous                                        certificate, "CertificateUri",
685*002d39b4SEd Tanous                                        certificateUri, "CertificateType",
686*002d39b4SEd Tanous                                        certificateType))
6875968caeeSMarri Devender Rao         {
6885968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "Required parameters are missing";
6895968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
6905968caeeSMarri Devender Rao             return;
6915968caeeSMarri Devender Rao         }
6925968caeeSMarri Devender Rao 
6935968caeeSMarri Devender Rao         if (!certificateType)
6945968caeeSMarri Devender Rao         {
6955968caeeSMarri Devender Rao             // should never happen, but it never hurts to be paranoid.
6965968caeeSMarri Devender Rao             return;
6975968caeeSMarri Devender Rao         }
6985968caeeSMarri Devender Rao         if (certificateType != "PEM")
6995968caeeSMarri Devender Rao         {
7005968caeeSMarri Devender Rao             messages::actionParameterNotSupported(
7015968caeeSMarri Devender Rao                 asyncResp->res, "CertificateType", "ReplaceCertificate");
7025968caeeSMarri Devender Rao             return;
7035968caeeSMarri Devender Rao         }
7045968caeeSMarri Devender Rao 
7055968caeeSMarri Devender Rao         std::string certURI;
7065968caeeSMarri Devender Rao         if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
7075968caeeSMarri Devender Rao                                           "@odata.id", certURI))
7085968caeeSMarri Devender Rao         {
7095968caeeSMarri Devender Rao             messages::actionParameterMissing(
7105968caeeSMarri Devender Rao                 asyncResp->res, "ReplaceCertificate", "CertificateUri");
7115968caeeSMarri Devender Rao             return;
7125968caeeSMarri Devender Rao         }
7135968caeeSMarri Devender Rao 
7145968caeeSMarri Devender Rao         BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI;
7155968caeeSMarri Devender Rao         long id = getIDFromURL(certURI);
7165968caeeSMarri Devender Rao         if (id < 0)
7175968caeeSMarri Devender Rao         {
718*002d39b4SEd Tanous             messages::actionParameterValueFormatError(asyncResp->res, certURI,
719*002d39b4SEd Tanous                                                       "CertificateUri",
7205968caeeSMarri Devender Rao                                                       "ReplaceCertificate");
7215968caeeSMarri Devender Rao             return;
7225968caeeSMarri Devender Rao         }
7235968caeeSMarri Devender Rao         std::string objectPath;
7245968caeeSMarri Devender Rao         std::string name;
72537cce918SMarri Devender Rao         std::string service;
7260fda0f12SGeorge Liu         if (boost::starts_with(
7270fda0f12SGeorge Liu                 certURI,
7280fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"))
7295968caeeSMarri Devender Rao         {
730*002d39b4SEd Tanous             objectPath =
731*002d39b4SEd Tanous                 std::string(certs::httpsObjectPath) + "/" + std::to_string(id);
7325968caeeSMarri Devender Rao             name = "HTTPS certificate";
73337cce918SMarri Devender Rao             service = certs::httpsServiceName;
73437cce918SMarri Devender Rao         }
73537cce918SMarri Devender Rao         else if (boost::starts_with(
736*002d39b4SEd Tanous                      certURI, "/redfish/v1/AccountService/LDAP/Certificates/"))
73737cce918SMarri Devender Rao         {
738*002d39b4SEd Tanous             objectPath =
739*002d39b4SEd Tanous                 std::string(certs::ldapObjectPath) + "/" + std::to_string(id);
74037cce918SMarri Devender Rao             name = "LDAP certificate";
74137cce918SMarri Devender Rao             service = certs::ldapServiceName;
7425968caeeSMarri Devender Rao         }
743cfcd5f6bSMarri Devender Rao         else if (boost::starts_with(
744cfcd5f6bSMarri Devender Rao                      certURI,
745cfcd5f6bSMarri Devender Rao                      "/redfish/v1/Managers/bmc/Truststore/Certificates/"))
746cfcd5f6bSMarri Devender Rao         {
747cfcd5f6bSMarri Devender Rao             objectPath = std::string(certs::authorityObjectPath) + "/" +
748cfcd5f6bSMarri Devender Rao                          std::to_string(id);
749cfcd5f6bSMarri Devender Rao             name = "TrustStore certificate";
750cfcd5f6bSMarri Devender Rao             service = certs::authorityServiceName;
751cfcd5f6bSMarri Devender Rao         }
7525968caeeSMarri Devender Rao         else
7535968caeeSMarri Devender Rao         {
7545968caeeSMarri Devender Rao             messages::actionParameterNotSupported(
7555968caeeSMarri Devender Rao                 asyncResp->res, "CertificateUri", "ReplaceCertificate");
7565968caeeSMarri Devender Rao             return;
7575968caeeSMarri Devender Rao         }
7585968caeeSMarri Devender Rao 
7595968caeeSMarri Devender Rao         std::shared_ptr<CertificateFile> certFile =
7605968caeeSMarri Devender Rao             std::make_shared<CertificateFile>(certificate);
7615968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
76237cce918SMarri Devender Rao             [asyncResp, certFile, objectPath, service, certURI, id,
7635968caeeSMarri Devender Rao              name](const boost::system::error_code ec) {
7645968caeeSMarri Devender Rao             if (ec)
7655968caeeSMarri Devender Rao             {
7665968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
76790d2d1e8SJiaqing Zhao                 if (ec.value() ==
76890d2d1e8SJiaqing Zhao                     boost::system::linux_error::bad_request_descriptor)
76990d2d1e8SJiaqing Zhao                 {
7708aae75adSMarri Devender Rao                     messages::resourceNotFound(asyncResp->res, name,
7718aae75adSMarri Devender Rao                                                std::to_string(id));
7725968caeeSMarri Devender Rao                     return;
7735968caeeSMarri Devender Rao                 }
77490d2d1e8SJiaqing Zhao                 messages::internalError(asyncResp->res);
77590d2d1e8SJiaqing Zhao                 return;
77690d2d1e8SJiaqing Zhao             }
77737cce918SMarri Devender Rao             getCertificateProperties(asyncResp, objectPath, service, id,
7785968caeeSMarri Devender Rao                                      certURI, name);
7795968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
7805968caeeSMarri Devender Rao                              << certFile->getCertFilePath();
7815968caeeSMarri Devender Rao             },
7825968caeeSMarri Devender Rao             service, objectPath, certs::certReplaceIntf, "Replace",
7835968caeeSMarri Devender Rao             certFile->getCertFilePath());
7847e860f15SJohn Edward Broadbent         });
7857e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionsReplaceCertificate
7865968caeeSMarri Devender Rao 
7875968caeeSMarri Devender Rao /**
7885968caeeSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
7895968caeeSMarri Devender Rao  * of a component, account or service.
7905968caeeSMarri Devender Rao  */
7915968caeeSMarri Devender Rao 
7927e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificate(App& app)
7935968caeeSMarri Devender Rao {
7947e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
7957e860f15SJohn Edward Broadbent         app,
7967e860f15SJohn Edward Broadbent         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
797ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
7987e860f15SJohn Edward Broadbent         .methods(
7997e860f15SJohn Edward Broadbent             boost::beast::http::verb::
80045ca1b86SEd Tanous                 get)([&app](const crow::Request& req,
8017e860f15SJohn Edward Broadbent                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8027e860f15SJohn Edward Broadbent                             const std::string& param) -> void {
80345ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
80445ca1b86SEd Tanous             {
80545ca1b86SEd Tanous                 return;
80645ca1b86SEd Tanous             }
8077e860f15SJohn Edward Broadbent             if (param.empty())
8085968caeeSMarri Devender Rao             {
8095968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
8105968caeeSMarri Devender Rao                 return;
8115968caeeSMarri Devender Rao             }
8125968caeeSMarri Devender Rao             long id = getIDFromURL(req.url);
8135968caeeSMarri Devender Rao 
8147e860f15SJohn Edward Broadbent             BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID="
8157e860f15SJohn Edward Broadbent                              << std::to_string(id);
8165968caeeSMarri Devender Rao             std::string certURL =
8175968caeeSMarri Devender Rao                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8185968caeeSMarri Devender Rao                 std::to_string(id);
8195968caeeSMarri Devender Rao             std::string objectPath = certs::httpsObjectPath;
8205968caeeSMarri Devender Rao             objectPath += "/";
8215968caeeSMarri Devender Rao             objectPath += std::to_string(id);
8227e860f15SJohn Edward Broadbent             getCertificateProperties(asyncResp, objectPath,
8237e860f15SJohn Edward Broadbent                                      certs::httpsServiceName, id, certURL,
8247e860f15SJohn Edward Broadbent                                      "HTTPS Certificate");
8257e860f15SJohn Edward Broadbent         });
8265968caeeSMarri Devender Rao }
8275968caeeSMarri Devender Rao 
8285968caeeSMarri Devender Rao /**
8295968caeeSMarri Devender Rao  * Collection of HTTPS certificates
8305968caeeSMarri Devender Rao  */
8317e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificateCollection(App& app)
8325968caeeSMarri Devender Rao {
8337e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8345968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
835ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
836*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
837*002d39b4SEd Tanous             [&app](const crow::Request& req,
838*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
83945ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
84045ca1b86SEd Tanous         {
84145ca1b86SEd Tanous             return;
84245ca1b86SEd Tanous         }
8431476687dSEd Tanous 
8441476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
8451476687dSEd Tanous             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
8461476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
8471476687dSEd Tanous             "#CertificateCollection.CertificateCollection";
8481476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8491476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
8501476687dSEd Tanous             "A Collection of HTTPS certificate instances";
8518d1b46d7Szhanghch05 
8525968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
8535968caeeSMarri Devender Rao             [asyncResp](const boost::system::error_code ec,
854711ac7a9SEd Tanous                         const dbus::utility::ManagedObjectType& certs) {
8555968caeeSMarri Devender Rao             if (ec)
8565968caeeSMarri Devender Rao             {
8575968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
8585968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
8595968caeeSMarri Devender Rao                 return;
8605968caeeSMarri Devender Rao             }
861*002d39b4SEd Tanous             nlohmann::json& members = asyncResp->res.jsonValue["Members"];
8625968caeeSMarri Devender Rao             members = nlohmann::json::array();
8635968caeeSMarri Devender Rao             for (const auto& cert : certs)
8645968caeeSMarri Devender Rao             {
8655968caeeSMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
86637cce918SMarri Devender Rao                 if (id >= 0)
8675968caeeSMarri Devender Rao                 {
8681476687dSEd Tanous                     nlohmann::json::object_t member;
8691476687dSEd Tanous                     member["@odata.id"] =
8700fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8711476687dSEd Tanous                         std::to_string(id);
8721476687dSEd Tanous                     members.push_back(std::move(member));
8735968caeeSMarri Devender Rao                 }
8745968caeeSMarri Devender Rao             }
875*002d39b4SEd Tanous             asyncResp->res.jsonValue["Members@odata.count"] = members.size();
8765968caeeSMarri Devender Rao             },
87737cce918SMarri Devender Rao             certs::httpsServiceName, certs::httpsObjectPath,
87837cce918SMarri Devender Rao             certs::dbusObjManagerIntf, "GetManagedObjects");
8797e860f15SJohn Edward Broadbent         });
8805968caeeSMarri Devender Rao 
8817e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8827e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
883ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
884*002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
885*002d39b4SEd Tanous             [&app](const crow::Request& req,
8867e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
88745ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
88845ca1b86SEd Tanous         {
88945ca1b86SEd Tanous             return;
89045ca1b86SEd Tanous         }
8915968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
8928d1b46d7Szhanghch05 
8931476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
8941476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
8955968caeeSMarri Devender Rao 
896*002d39b4SEd Tanous         std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
89758eb238fSKowalski, Kamil 
89858eb238fSKowalski, Kamil         if (certFileBody.empty())
89958eb238fSKowalski, Kamil         {
9000fda0f12SGeorge Liu             BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
901a08752f5SZbigniew Kurzynski             messages::unrecognizedRequestBody(asyncResp->res);
90258eb238fSKowalski, Kamil             return;
90358eb238fSKowalski, Kamil         }
90458eb238fSKowalski, Kamil 
9055968caeeSMarri Devender Rao         std::shared_ptr<CertificateFile> certFile =
90658eb238fSKowalski, Kamil             std::make_shared<CertificateFile>(certFileBody);
9075968caeeSMarri Devender Rao 
9085968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
909656ec7e3SZbigniew Kurzynski             [asyncResp, certFile](const boost::system::error_code ec,
910656ec7e3SZbigniew Kurzynski                                   const std::string& objectPath) {
9115968caeeSMarri Devender Rao             if (ec)
9125968caeeSMarri Devender Rao             {
9135968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9145968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
9155968caeeSMarri Devender Rao                 return;
9165968caeeSMarri Devender Rao             }
917656ec7e3SZbigniew Kurzynski             long certId = getIDFromURL(objectPath);
918656ec7e3SZbigniew Kurzynski             if (certId < 0)
919656ec7e3SZbigniew Kurzynski             {
920*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath;
921656ec7e3SZbigniew Kurzynski                 messages::internalError(asyncResp->res);
922656ec7e3SZbigniew Kurzynski                 return;
923656ec7e3SZbigniew Kurzynski             }
9245968caeeSMarri Devender Rao             std::string certURL =
9250fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
9265968caeeSMarri Devender Rao                 std::to_string(certId);
9270fda0f12SGeorge Liu             getCertificateProperties(asyncResp, objectPath,
928*002d39b4SEd Tanous                                      certs::httpsServiceName, certId, certURL,
929*002d39b4SEd Tanous                                      "HTTPS Certificate");
9305968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9315968caeeSMarri Devender Rao                              << certFile->getCertFilePath();
9325968caeeSMarri Devender Rao             },
93337cce918SMarri Devender Rao             certs::httpsServiceName, certs::httpsObjectPath,
9340fda0f12SGeorge Liu             certs::certInstallIntf, "Install", certFile->getCertFilePath());
9357e860f15SJohn Edward Broadbent         });
9367e860f15SJohn Edward Broadbent } // requestRoutesHTTPSCertificateCollection
9375968caeeSMarri Devender Rao 
9385968caeeSMarri Devender Rao /**
93937cce918SMarri Devender Rao  * @brief Retrieve the certificates installed list and append to the
94037cce918SMarri Devender Rao  * response
94137cce918SMarri Devender Rao  *
94237cce918SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
94337cce918SMarri Devender Rao  * @param[in] certURL  Path of the certificate object
94437cce918SMarri Devender Rao  * @param[in] path  Path of the D-Bus service object
94537cce918SMarri Devender Rao  * @return None
94637cce918SMarri Devender Rao  */
9474f48d5f6SEd Tanous inline void
9484f48d5f6SEd Tanous     getCertificateLocations(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9498d1b46d7Szhanghch05                             const std::string& certURL, const std::string& path,
95037cce918SMarri Devender Rao                             const std::string& service)
95137cce918SMarri Devender Rao {
95237cce918SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL
95337cce918SMarri Devender Rao                      << " Path=" << path << " service= " << service;
95437cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
95537cce918SMarri Devender Rao         [asyncResp, certURL](const boost::system::error_code ec,
956711ac7a9SEd Tanous                              const dbus::utility::ManagedObjectType& certs) {
95737cce918SMarri Devender Rao         if (ec)
95837cce918SMarri Devender Rao         {
959*002d39b4SEd Tanous             BMCWEB_LOG_WARNING << "Certificate collection query failed: " << ec
9609c8e039eSJonathan Doman                                << ", skipping " << certURL;
96137cce918SMarri Devender Rao             return;
96237cce918SMarri Devender Rao         }
96337cce918SMarri Devender Rao         nlohmann::json& links =
96437cce918SMarri Devender Rao             asyncResp->res.jsonValue["Links"]["Certificates"];
9659eb808c1SEd Tanous         for (const auto& cert : certs)
96637cce918SMarri Devender Rao         {
96737cce918SMarri Devender Rao             long id = getIDFromURL(cert.first.str);
96837cce918SMarri Devender Rao             if (id >= 0)
96937cce918SMarri Devender Rao             {
9701476687dSEd Tanous                 nlohmann::json::object_t link;
9711476687dSEd Tanous                 link["@odata.id"] = certURL + std::to_string(id);
9721476687dSEd Tanous                 links.push_back(std::move(link));
97337cce918SMarri Devender Rao             }
97437cce918SMarri Devender Rao         }
97537cce918SMarri Devender Rao         asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] =
97637cce918SMarri Devender Rao             links.size();
97737cce918SMarri Devender Rao         },
97837cce918SMarri Devender Rao         service, path, certs::dbusObjManagerIntf, "GetManagedObjects");
9795968caeeSMarri Devender Rao }
9807e860f15SJohn Edward Broadbent 
9817e860f15SJohn Edward Broadbent /**
9827e860f15SJohn Edward Broadbent  * The certificate location schema defines a resource that an administrator
9837e860f15SJohn Edward Broadbent  * can use in order to locate all certificates installed on a given service.
9847e860f15SJohn Edward Broadbent  */
9857e860f15SJohn Edward Broadbent inline void requestRoutesCertificateLocations(App& app)
9867e860f15SJohn Edward Broadbent {
9877e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
988ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateLocations)
989*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
990*002d39b4SEd Tanous             [&app](const crow::Request& req,
991*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
99245ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
99345ca1b86SEd Tanous         {
99445ca1b86SEd Tanous             return;
99545ca1b86SEd Tanous         }
9961476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
9971476687dSEd Tanous             "/redfish/v1/CertificateService/CertificateLocations";
9981476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
9991476687dSEd Tanous             "#CertificateLocations.v1_0_0.CertificateLocations";
10001476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "Certificate Locations";
10011476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "CertificateLocations";
10021476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
10037e860f15SJohn Edward Broadbent             "Defines a resource that an administrator can use in order to "
10041476687dSEd Tanous             "locate all certificates installed on a given service";
10057e860f15SJohn Edward Broadbent 
10067e860f15SJohn Edward Broadbent         nlohmann::json& links =
10077e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["Links"]["Certificates"];
10087e860f15SJohn Edward Broadbent         links = nlohmann::json::array();
10097e860f15SJohn Edward Broadbent         getCertificateLocations(
10107e860f15SJohn Edward Broadbent             asyncResp,
10117e860f15SJohn Edward Broadbent             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/",
10127e860f15SJohn Edward Broadbent             certs::httpsObjectPath, certs::httpsServiceName);
1013*002d39b4SEd Tanous         getCertificateLocations(asyncResp,
1014*002d39b4SEd Tanous                                 "/redfish/v1/AccountService/LDAP/Certificates/",
10157e860f15SJohn Edward Broadbent                                 certs::ldapObjectPath, certs::ldapServiceName);
10167e860f15SJohn Edward Broadbent         getCertificateLocations(
10177e860f15SJohn Edward Broadbent             asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/",
10187e860f15SJohn Edward Broadbent             certs::authorityObjectPath, certs::authorityServiceName);
10197e860f15SJohn Edward Broadbent         });
10207e860f15SJohn Edward Broadbent }
10217e860f15SJohn Edward Broadbent // requestRoutesCertificateLocations
102237cce918SMarri Devender Rao 
102337cce918SMarri Devender Rao /**
102437cce918SMarri Devender Rao  * Collection of LDAP certificates
102537cce918SMarri Devender Rao  */
10267e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificateCollection(App& app)
102737cce918SMarri Devender Rao {
10287e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1029ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
1030*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1031*002d39b4SEd Tanous             [&app](const crow::Request& req,
1032*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
103345ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
103445ca1b86SEd Tanous         {
103545ca1b86SEd Tanous             return;
103645ca1b86SEd Tanous         }
10371476687dSEd Tanous 
10381476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
10391476687dSEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates";
10401476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
10411476687dSEd Tanous             "#CertificateCollection.CertificateCollection";
10421476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10431476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
10441476687dSEd Tanous             "A Collection of LDAP certificate instances";
10458d1b46d7Szhanghch05 
104637cce918SMarri Devender Rao         crow::connections::systemBus->async_method_call(
104737cce918SMarri Devender Rao             [asyncResp](const boost::system::error_code ec,
1048711ac7a9SEd Tanous                         const dbus::utility::ManagedObjectType& certs) {
1049*002d39b4SEd Tanous             nlohmann::json& members = asyncResp->res.jsonValue["Members"];
10509c8e039eSJonathan Doman             nlohmann::json& count =
10519c8e039eSJonathan Doman                 asyncResp->res.jsonValue["Members@odata.count"];
10529c8e039eSJonathan Doman             members = nlohmann::json::array();
10539c8e039eSJonathan Doman             count = 0;
105437cce918SMarri Devender Rao             if (ec)
105537cce918SMarri Devender Rao             {
1056*002d39b4SEd Tanous                 BMCWEB_LOG_WARNING << "LDAP certificate query failed: " << ec;
105737cce918SMarri Devender Rao                 return;
105837cce918SMarri Devender Rao             }
105937cce918SMarri Devender Rao             for (const auto& cert : certs)
106037cce918SMarri Devender Rao             {
106137cce918SMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
106237cce918SMarri Devender Rao                 if (id >= 0)
106337cce918SMarri Devender Rao                 {
10641476687dSEd Tanous                     nlohmann::json::object_t member;
10651476687dSEd Tanous                     member["@odata.id"] =
10660fda0f12SGeorge Liu                         "/redfish/v1/AccountService/LDAP/Certificates/" +
10671476687dSEd Tanous                         std::to_string(id);
10681476687dSEd Tanous                     members.push_back(std::move(member));
106937cce918SMarri Devender Rao                 }
107037cce918SMarri Devender Rao             }
10719c8e039eSJonathan Doman             count = members.size();
107237cce918SMarri Devender Rao             },
107337cce918SMarri Devender Rao             certs::ldapServiceName, certs::ldapObjectPath,
107437cce918SMarri Devender Rao             certs::dbusObjManagerIntf, "GetManagedObjects");
10757e860f15SJohn Edward Broadbent         });
107637cce918SMarri Devender Rao 
10777e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1078ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
10797e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
108045ca1b86SEd Tanous             [&app](const crow::Request& req,
10817e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
108245ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
108345ca1b86SEd Tanous         {
108445ca1b86SEd Tanous             return;
108545ca1b86SEd Tanous         }
1086*002d39b4SEd Tanous         std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
108758eb238fSKowalski, Kamil 
108858eb238fSKowalski, Kamil         if (certFileBody.empty())
108958eb238fSKowalski, Kamil         {
1090*002d39b4SEd Tanous             BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1091a08752f5SZbigniew Kurzynski             messages::unrecognizedRequestBody(asyncResp->res);
109258eb238fSKowalski, Kamil             return;
109358eb238fSKowalski, Kamil         }
109458eb238fSKowalski, Kamil 
109558eb238fSKowalski, Kamil         std::shared_ptr<CertificateFile> certFile =
109658eb238fSKowalski, Kamil             std::make_shared<CertificateFile>(certFileBody);
109758eb238fSKowalski, Kamil 
109837cce918SMarri Devender Rao         crow::connections::systemBus->async_method_call(
1099656ec7e3SZbigniew Kurzynski             [asyncResp, certFile](const boost::system::error_code ec,
1100656ec7e3SZbigniew Kurzynski                                   const std::string& objectPath) {
110137cce918SMarri Devender Rao             if (ec)
110237cce918SMarri Devender Rao             {
110337cce918SMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
110437cce918SMarri Devender Rao                 messages::internalError(asyncResp->res);
110537cce918SMarri Devender Rao                 return;
110637cce918SMarri Devender Rao             }
1107656ec7e3SZbigniew Kurzynski             long certId = getIDFromURL(objectPath);
1108656ec7e3SZbigniew Kurzynski             if (certId < 0)
1109656ec7e3SZbigniew Kurzynski             {
1110*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath;
1111656ec7e3SZbigniew Kurzynski                 messages::internalError(asyncResp->res);
1112656ec7e3SZbigniew Kurzynski                 return;
1113656ec7e3SZbigniew Kurzynski             }
111437cce918SMarri Devender Rao             std::string certURL =
111537cce918SMarri Devender Rao                 "/redfish/v1/AccountService/LDAP/Certificates/" +
111637cce918SMarri Devender Rao                 std::to_string(certId);
111737cce918SMarri Devender Rao             getCertificateProperties(asyncResp, objectPath,
1118*002d39b4SEd Tanous                                      certs::ldapServiceName, certId, certURL,
1119*002d39b4SEd Tanous                                      "LDAP Certificate");
112037cce918SMarri Devender Rao             BMCWEB_LOG_DEBUG << "LDAP certificate install file="
112137cce918SMarri Devender Rao                              << certFile->getCertFilePath();
112237cce918SMarri Devender Rao             },
112337cce918SMarri Devender Rao             certs::ldapServiceName, certs::ldapObjectPath,
1124*002d39b4SEd Tanous             certs::certInstallIntf, "Install", certFile->getCertFilePath());
11257e860f15SJohn Edward Broadbent         });
11267e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificateCollection
112737cce918SMarri Devender Rao 
112837cce918SMarri Devender Rao /**
112937cce918SMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
113037cce918SMarri Devender Rao  * of a component, account or service.
113137cce918SMarri Devender Rao  */
11327e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificate(App& app)
113337cce918SMarri Devender Rao {
11347e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1135ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
11367e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
113745ca1b86SEd Tanous             [&app](const crow::Request& req,
11387e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11397e860f15SJohn Edward Broadbent                    const std::string&) {
114045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
114145ca1b86SEd Tanous         {
114245ca1b86SEd Tanous             return;
114345ca1b86SEd Tanous         }
114437cce918SMarri Devender Rao         long id = getIDFromURL(req.url);
114537cce918SMarri Devender Rao         if (id < 0)
114637cce918SMarri Devender Rao         {
114737cce918SMarri Devender Rao             BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
114837cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
114937cce918SMarri Devender Rao             return;
115037cce918SMarri Devender Rao         }
1151*002d39b4SEd Tanous         BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << std::to_string(id);
1152*002d39b4SEd Tanous         std::string certURL = "/redfish/v1/AccountService/LDAP/Certificates/" +
115337cce918SMarri Devender Rao                               std::to_string(id);
115437cce918SMarri Devender Rao         std::string objectPath = certs::ldapObjectPath;
115537cce918SMarri Devender Rao         objectPath += "/";
115637cce918SMarri Devender Rao         objectPath += std::to_string(id);
1157*002d39b4SEd Tanous         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1158*002d39b4SEd Tanous                                  id, certURL, "LDAP Certificate");
11597e860f15SJohn Edward Broadbent         });
11607e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificate
1161cfcd5f6bSMarri Devender Rao /**
1162cfcd5f6bSMarri Devender Rao  * Collection of TrustStoreCertificate certificates
1163cfcd5f6bSMarri Devender Rao  */
11647e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificateCollection(App& app)
1165cfcd5f6bSMarri Devender Rao {
11667e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1167ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1168*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1169*002d39b4SEd Tanous             [&app](const crow::Request& req,
1170*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
117145ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
117245ca1b86SEd Tanous         {
117345ca1b86SEd Tanous             return;
117445ca1b86SEd Tanous         }
11751476687dSEd Tanous 
11761476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
11771476687dSEd Tanous             "/redfish/v1/Managers/bmc/Truststore/Certificates/";
11781476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
11791476687dSEd Tanous             "#CertificateCollection.CertificateCollection";
1180*002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11811476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
11821476687dSEd Tanous             "A Collection of TrustStore certificate instances";
11838d1b46d7Szhanghch05 
1184cfcd5f6bSMarri Devender Rao         crow::connections::systemBus->async_method_call(
1185cfcd5f6bSMarri Devender Rao             [asyncResp](const boost::system::error_code ec,
1186711ac7a9SEd Tanous                         const dbus::utility::ManagedObjectType& certs) {
1187cfcd5f6bSMarri Devender Rao             if (ec)
1188cfcd5f6bSMarri Devender Rao             {
1189cfcd5f6bSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1190cfcd5f6bSMarri Devender Rao                 messages::internalError(asyncResp->res);
1191cfcd5f6bSMarri Devender Rao                 return;
1192cfcd5f6bSMarri Devender Rao             }
1193*002d39b4SEd Tanous             nlohmann::json& members = asyncResp->res.jsonValue["Members"];
1194cfcd5f6bSMarri Devender Rao             members = nlohmann::json::array();
1195cfcd5f6bSMarri Devender Rao             for (const auto& cert : certs)
1196cfcd5f6bSMarri Devender Rao             {
1197cfcd5f6bSMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
1198cfcd5f6bSMarri Devender Rao                 if (id >= 0)
1199cfcd5f6bSMarri Devender Rao                 {
12001476687dSEd Tanous                     nlohmann::json::object_t member;
12011476687dSEd Tanous                     member["@odata.id"] =
12020fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
12031476687dSEd Tanous                         std::to_string(id);
12041476687dSEd Tanous                     members.push_back(std::move(member));
1205cfcd5f6bSMarri Devender Rao                 }
1206cfcd5f6bSMarri Devender Rao             }
1207*002d39b4SEd Tanous             asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1208cfcd5f6bSMarri Devender Rao             },
1209cfcd5f6bSMarri Devender Rao             certs::authorityServiceName, certs::authorityObjectPath,
1210cfcd5f6bSMarri Devender Rao             certs::dbusObjManagerIntf, "GetManagedObjects");
12117e860f15SJohn Edward Broadbent         });
1212cfcd5f6bSMarri Devender Rao 
12137e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1214ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
1215*002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
1216*002d39b4SEd Tanous             [&app](const crow::Request& req,
12177e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
121845ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
121945ca1b86SEd Tanous         {
122045ca1b86SEd Tanous             return;
122145ca1b86SEd Tanous         }
1222*002d39b4SEd Tanous         std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1223a08752f5SZbigniew Kurzynski 
1224a08752f5SZbigniew Kurzynski         if (certFileBody.empty())
1225a08752f5SZbigniew Kurzynski         {
12260fda0f12SGeorge Liu             BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1227a08752f5SZbigniew Kurzynski             messages::unrecognizedRequestBody(asyncResp->res);
1228a08752f5SZbigniew Kurzynski             return;
1229a08752f5SZbigniew Kurzynski         }
1230a08752f5SZbigniew Kurzynski 
1231a08752f5SZbigniew Kurzynski         std::shared_ptr<CertificateFile> certFile =
1232a08752f5SZbigniew Kurzynski             std::make_shared<CertificateFile>(certFileBody);
1233cfcd5f6bSMarri Devender Rao         crow::connections::systemBus->async_method_call(
1234656ec7e3SZbigniew Kurzynski             [asyncResp, certFile](const boost::system::error_code ec,
1235656ec7e3SZbigniew Kurzynski                                   const std::string& objectPath) {
1236cfcd5f6bSMarri Devender Rao             if (ec)
1237cfcd5f6bSMarri Devender Rao             {
1238cfcd5f6bSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1239cfcd5f6bSMarri Devender Rao                 messages::internalError(asyncResp->res);
1240cfcd5f6bSMarri Devender Rao                 return;
1241cfcd5f6bSMarri Devender Rao             }
1242656ec7e3SZbigniew Kurzynski             long certId = getIDFromURL(objectPath);
1243656ec7e3SZbigniew Kurzynski             if (certId < 0)
1244656ec7e3SZbigniew Kurzynski             {
1245*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath;
1246656ec7e3SZbigniew Kurzynski                 messages::internalError(asyncResp->res);
1247656ec7e3SZbigniew Kurzynski                 return;
1248656ec7e3SZbigniew Kurzynski             }
12490fda0f12SGeorge Liu             std::string certURL =
12500fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1251cfcd5f6bSMarri Devender Rao                 std::to_string(certId);
1252656ec7e3SZbigniew Kurzynski 
1253*002d39b4SEd Tanous             getCertificateProperties(asyncResp, objectPath,
1254*002d39b4SEd Tanous                                      certs::authorityServiceName, certId,
1255*002d39b4SEd Tanous                                      certURL, "TrustStore Certificate");
12560fda0f12SGeorge Liu             BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1257cfcd5f6bSMarri Devender Rao                              << certFile->getCertFilePath();
1258cfcd5f6bSMarri Devender Rao             },
1259cfcd5f6bSMarri Devender Rao             certs::authorityServiceName, certs::authorityObjectPath,
12600fda0f12SGeorge Liu             certs::certInstallIntf, "Install", certFile->getCertFilePath());
12617e860f15SJohn Edward Broadbent         });
12627e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificateCollection
1263cfcd5f6bSMarri Devender Rao 
1264cfcd5f6bSMarri Devender Rao /**
1265cfcd5f6bSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
1266cfcd5f6bSMarri Devender Rao  * of a component, account or service.
1267cfcd5f6bSMarri Devender Rao  */
12687e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificate(App& app)
1269cfcd5f6bSMarri Devender Rao {
12707e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1271ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
12727e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
127345ca1b86SEd Tanous             [&app](const crow::Request& req,
12747e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12757e860f15SJohn Edward Broadbent                    const std::string&) {
127645ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
127745ca1b86SEd Tanous         {
127845ca1b86SEd Tanous             return;
127945ca1b86SEd Tanous         }
1280cfcd5f6bSMarri Devender Rao         long id = getIDFromURL(req.url);
1281cfcd5f6bSMarri Devender Rao         if (id < 0)
1282cfcd5f6bSMarri Devender Rao         {
1283cfcd5f6bSMarri Devender Rao             BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
1284cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1285cfcd5f6bSMarri Devender Rao             return;
1286cfcd5f6bSMarri Devender Rao         }
1287cfcd5f6bSMarri Devender Rao         BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID="
1288cfcd5f6bSMarri Devender Rao                          << std::to_string(id);
1289cfcd5f6bSMarri Devender Rao         std::string certURL =
1290cfcd5f6bSMarri Devender Rao             "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1291cfcd5f6bSMarri Devender Rao             std::to_string(id);
1292cfcd5f6bSMarri Devender Rao         std::string objectPath = certs::authorityObjectPath;
1293cfcd5f6bSMarri Devender Rao         objectPath += "/";
1294cfcd5f6bSMarri Devender Rao         objectPath += std::to_string(id);
1295cfcd5f6bSMarri Devender Rao         getCertificateProperties(asyncResp, objectPath,
1296*002d39b4SEd Tanous                                  certs::authorityServiceName, id, certURL,
1297*002d39b4SEd Tanous                                  "TrustStore Certificate");
12987e860f15SJohn Edward Broadbent         });
129907a60299SZbigniew Kurzynski 
13007e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1301ed398213SEd Tanous         .privileges(redfish::privileges::deleteCertificate)
13027e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
130345ca1b86SEd Tanous             [&app](const crow::Request& req,
13047e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
13057e860f15SJohn Edward Broadbent                    const std::string& param) {
130645ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
130745ca1b86SEd Tanous         {
130845ca1b86SEd Tanous             return;
130945ca1b86SEd Tanous         }
13107e860f15SJohn Edward Broadbent         if (param.empty())
131107a60299SZbigniew Kurzynski         {
131207a60299SZbigniew Kurzynski             messages::internalError(asyncResp->res);
131307a60299SZbigniew Kurzynski             return;
131407a60299SZbigniew Kurzynski         }
131507a60299SZbigniew Kurzynski 
131607a60299SZbigniew Kurzynski         long id = getIDFromURL(req.url);
131707a60299SZbigniew Kurzynski         if (id < 0)
131807a60299SZbigniew Kurzynski         {
131907a60299SZbigniew Kurzynski             BMCWEB_LOG_ERROR << "Invalid url value: " << req.url;
1320*002d39b4SEd Tanous             messages::resourceNotFound(asyncResp->res, "TrustStore Certificate",
132107a60299SZbigniew Kurzynski                                        std::string(req.url));
132207a60299SZbigniew Kurzynski             return;
132307a60299SZbigniew Kurzynski         }
132407a60299SZbigniew Kurzynski         BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID="
132507a60299SZbigniew Kurzynski                          << std::to_string(id);
132607a60299SZbigniew Kurzynski         std::string certPath = certs::authorityObjectPath;
132707a60299SZbigniew Kurzynski         certPath += "/";
132807a60299SZbigniew Kurzynski         certPath += std::to_string(id);
132907a60299SZbigniew Kurzynski 
133007a60299SZbigniew Kurzynski         crow::connections::systemBus->async_method_call(
133107a60299SZbigniew Kurzynski             [asyncResp, id](const boost::system::error_code ec) {
133207a60299SZbigniew Kurzynski             if (ec)
133307a60299SZbigniew Kurzynski             {
133407a60299SZbigniew Kurzynski                 messages::resourceNotFound(asyncResp->res,
133507a60299SZbigniew Kurzynski                                            "TrustStore Certificate",
133607a60299SZbigniew Kurzynski                                            std::to_string(id));
133707a60299SZbigniew Kurzynski                 return;
133807a60299SZbigniew Kurzynski             }
133907a60299SZbigniew Kurzynski             BMCWEB_LOG_INFO << "Certificate deleted";
1340*002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::no_content);
134107a60299SZbigniew Kurzynski             },
134207a60299SZbigniew Kurzynski             certs::authorityServiceName, certPath, certs::objDeleteIntf,
134307a60299SZbigniew Kurzynski             "Delete");
13447e860f15SJohn Edward Broadbent         });
13457e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
13465968caeeSMarri Devender Rao } // namespace redfish
1347