xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 3ba0007367777144f474fdf99439ae8c03633486)
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)
49002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
50002d39b4SEd Tanous             [&app](const crow::Request& req,
51002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
52*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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
77002d39b4SEd 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)
251002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
252002d39b4SEd Tanous             [&app](const crow::Request& req,
2537e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
254*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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",
289002d39b4SEd Tanous                 certificateCollection, "AlternativeNames", optAlternativeNames,
290002d39b4SEd Tanous                 "ChallengePassword", optChallengePassword, "Email", optEmail,
291002d39b4SEd Tanous                 "GivenName", optGivenName, "Initials", optInitials,
292002d39b4SEd 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         {
306002d39b4SEd Tanous             messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
307002d39b4SEd Tanous                                                   "ChallengePassword");
30830215816SMarri Devender Rao             return;
30930215816SMarri Devender Rao         }
31030215816SMarri Devender Rao 
31130215816SMarri Devender Rao         std::string certURI;
312002d39b4SEd Tanous         if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
313002d39b4SEd 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(
328002d39b4SEd 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         {
353002d39b4SEd Tanous             messages::propertyValueNotInList(asyncResp->res,
354002d39b4SEd 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(
385002d39b4SEd 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         {
413002d39b4SEd Tanous             messages::serviceTemporarilyUnavailable(asyncResp->res,
414002d39b4SEd 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));
421002d39b4SEd 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             {
477002d39b4SEd 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",
483002d39b4SEd Tanous             "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
484002d39b4SEd Tanous             commonName, *optContactPerson, country, *optEmail, *optGivenName,
485002d39b4SEd 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             {
606002d39b4SEd 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             {
640002d39b4SEd 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             {
649002d39b4SEd 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)
672002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
673002d39b4SEd Tanous             [&app](const crow::Request& req,
6747e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
675*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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 
683002d39b4SEd Tanous         if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
684002d39b4SEd Tanous                                        certificate, "CertificateUri",
685002d39b4SEd Tanous                                        certificateUri, "CertificateType",
686002d39b4SEd 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         {
718002d39b4SEd Tanous             messages::actionParameterValueFormatError(asyncResp->res, certURI,
719002d39b4SEd 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         {
730002d39b4SEd Tanous             objectPath =
731002d39b4SEd 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(
736002d39b4SEd Tanous                      certURI, "/redfish/v1/AccountService/LDAP/Certificates/"))
73737cce918SMarri Devender Rao         {
738002d39b4SEd Tanous             objectPath =
739002d39b4SEd 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 {
803*3ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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)
836002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
837002d39b4SEd Tanous             [&app](const crow::Request& req,
838002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
839*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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             }
861002d39b4SEd 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             }
875002d39b4SEd 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)
884002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
885002d39b4SEd Tanous             [&app](const crow::Request& req,
8867e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
887*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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 
896002d39b4SEd 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             {
920002d39b4SEd 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,
928002d39b4SEd Tanous                                      certs::httpsServiceName, certId, certURL,
929002d39b4SEd 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         {
959002d39b4SEd 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)
989002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
990002d39b4SEd Tanous             [&app](const crow::Request& req,
991002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
992*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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);
1013002d39b4SEd Tanous         getCertificateLocations(asyncResp,
1014002d39b4SEd 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)
1030002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1031002d39b4SEd Tanous             [&app](const crow::Request& req,
1032002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1033*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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) {
1049002d39b4SEd 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             {
1056002d39b4SEd 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) {
1082*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
108345ca1b86SEd Tanous         {
108445ca1b86SEd Tanous             return;
108545ca1b86SEd Tanous         }
1086002d39b4SEd Tanous         std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
108758eb238fSKowalski, Kamil 
108858eb238fSKowalski, Kamil         if (certFileBody.empty())
108958eb238fSKowalski, Kamil         {
1090002d39b4SEd 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             {
1110002d39b4SEd 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,
1118002d39b4SEd Tanous                                      certs::ldapServiceName, certId, certURL,
1119002d39b4SEd 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,
1124002d39b4SEd 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&) {
1140*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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         }
1151002d39b4SEd Tanous         BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << std::to_string(id);
1152002d39b4SEd 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);
1157002d39b4SEd Tanous         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1158002d39b4SEd 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)
1168002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1169002d39b4SEd Tanous             [&app](const crow::Request& req,
1170002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1171*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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";
1180002d39b4SEd 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             }
1193002d39b4SEd 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             }
1207002d39b4SEd 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)
1215002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
1216002d39b4SEd Tanous             [&app](const crow::Request& req,
12177e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1218*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
121945ca1b86SEd Tanous         {
122045ca1b86SEd Tanous             return;
122145ca1b86SEd Tanous         }
1222002d39b4SEd 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             {
1245002d39b4SEd 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 
1253002d39b4SEd Tanous             getCertificateProperties(asyncResp, objectPath,
1254002d39b4SEd Tanous                                      certs::authorityServiceName, certId,
1255002d39b4SEd 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&) {
1276*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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,
1296002d39b4SEd Tanous                                  certs::authorityServiceName, id, certURL,
1297002d39b4SEd 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) {
1306*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
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;
1320002d39b4SEd 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";
1340002d39b4SEd 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