xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision c6a8dfb1abcc41a3f4123477802ba5d2ca0baabf)
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* certInstallIntf = "xyz.openbmc_project.Certs.Install";
165968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
1707a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
185968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
195968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
205968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
2137cce918SMarri Devender Rao constexpr char const* httpsServiceName =
2237cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
2337cce918SMarri Devender Rao constexpr char const* ldapServiceName =
2437cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
25cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
26cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
27*c6a8dfb1SJiaqing Zhao constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
28*c6a8dfb1SJiaqing Zhao constexpr char const* httpsObjectPath =
29*c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
30*c6a8dfb1SJiaqing Zhao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
31cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
32cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
335968caeeSMarri Devender Rao } // namespace certs
345968caeeSMarri Devender Rao 
355968caeeSMarri Devender Rao /**
365968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
375968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
385968caeeSMarri Devender Rao  * are installed.
395968caeeSMarri Devender Rao  */
407e860f15SJohn Edward Broadbent 
415968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate
424e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish
435968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF
445968caeeSMarri Devender Rao // publish Privilege details for certificate service
455968caeeSMarri Devender Rao 
467e860f15SJohn Edward Broadbent inline void requestRoutesCertificateService(App& app)
475968caeeSMarri Devender Rao {
487e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
49ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateService)
50002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
51002d39b4SEd Tanous             [&app](const crow::Request& req,
52002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
533ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
5445ca1b86SEd Tanous         {
5545ca1b86SEd Tanous             return;
5645ca1b86SEd Tanous         }
571476687dSEd Tanous 
581476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
591476687dSEd Tanous             "#CertificateService.v1_0_0.CertificateService";
601476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
611476687dSEd Tanous             "/redfish/v1/CertificateService";
621476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "CertificateService";
631476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "Certificate Service";
641476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
651476687dSEd Tanous             "Actions available to manage certificates";
6672048780SAbhishek Patel         // /redfish/v1/CertificateService/CertificateLocations is something
6772048780SAbhishek Patel         // only ConfigureManager can access then only display when the user
6872048780SAbhishek Patel         // has permissions ConfigureManager
6972048780SAbhishek Patel         Privileges effectiveUserPrivileges =
7072048780SAbhishek Patel             redfish::getUserPrivileges(req.userRole);
7172048780SAbhishek Patel         if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
7272048780SAbhishek Patel                                              effectiveUserPrivileges))
7372048780SAbhishek Patel         {
741476687dSEd Tanous             asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
751476687dSEd Tanous                 "/redfish/v1/CertificateService/CertificateLocations";
7672048780SAbhishek Patel         }
770fda0f12SGeorge Liu         asyncResp->res
78002d39b4SEd Tanous             .jsonValue["Actions"]["#CertificateService.ReplaceCertificate"] = {
790fda0f12SGeorge Liu             {"target",
800fda0f12SGeorge Liu              "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"},
815968caeeSMarri Devender Rao             {"CertificateType@Redfish.AllowableValues", {"PEM"}}};
827e860f15SJohn Edward Broadbent         asyncResp->res
837e860f15SJohn Edward Broadbent             .jsonValue["Actions"]["#CertificateService.GenerateCSR"] = {
840fda0f12SGeorge Liu             {"target",
850fda0f12SGeorge Liu              "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"}};
867e860f15SJohn Edward Broadbent         });
877e860f15SJohn Edward Broadbent } // requestRoutesCertificateService
8837cce918SMarri Devender Rao 
895968caeeSMarri Devender Rao /**
905968caeeSMarri Devender Rao  * @brief Find the ID specified in the URL
915968caeeSMarri Devender Rao  * Finds the numbers specified after the last "/" in the URL and returns.
925968caeeSMarri Devender Rao  * @param[in] path URL
935968caeeSMarri Devender Rao  * @return -1 on failure and number on success
945968caeeSMarri Devender Rao  */
9523a21a1cSEd Tanous inline long getIDFromURL(const std::string_view url)
965968caeeSMarri Devender Rao {
97f23b7296SEd Tanous     std::size_t found = url.rfind('/');
985968caeeSMarri Devender Rao     if (found == std::string::npos)
995968caeeSMarri Devender Rao     {
1005968caeeSMarri Devender Rao         return -1;
1015968caeeSMarri Devender Rao     }
102e6604b11SIwona Klimaszewska 
1035968caeeSMarri Devender Rao     if ((found + 1) < url.length())
1045968caeeSMarri Devender Rao     {
1055968caeeSMarri Devender Rao         std::string_view str = url.substr(found + 1);
106e6604b11SIwona Klimaszewska 
107e6604b11SIwona Klimaszewska         return boost::convert<long>(str, boost::cnv::strtol()).value_or(-1);
1085968caeeSMarri Devender Rao     }
109e6604b11SIwona Klimaszewska 
1105968caeeSMarri Devender Rao     return -1;
1115968caeeSMarri Devender Rao }
1125968caeeSMarri Devender Rao 
1138d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
1148d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11558eb238fSKowalski, Kamil     const crow::Request& req)
11658eb238fSKowalski, Kamil {
11758eb238fSKowalski, Kamil     nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
11858eb238fSKowalski, Kamil 
11958eb238fSKowalski, Kamil     if (reqJson.is_discarded())
12058eb238fSKowalski, Kamil     {
12158eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
12258eb238fSKowalski, Kamil         return req.body;
12358eb238fSKowalski, Kamil     }
12458eb238fSKowalski, Kamil 
12558eb238fSKowalski, Kamil     std::string certificate;
12658eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
12758eb238fSKowalski, Kamil 
12815ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
12915ed6780SWilly Tu                                   certificate, "CertificateType",
13015ed6780SWilly Tu                                   certificateType))
13158eb238fSKowalski, Kamil     {
13258eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
13358eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
134abb93cddSEd Tanous         return {};
13558eb238fSKowalski, Kamil     }
13658eb238fSKowalski, Kamil 
13758eb238fSKowalski, Kamil     if (*certificateType != "PEM")
13858eb238fSKowalski, Kamil     {
13958eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
14058eb238fSKowalski, Kamil                                          "CertificateType");
141abb93cddSEd Tanous         return {};
14258eb238fSKowalski, Kamil     }
14358eb238fSKowalski, Kamil 
14458eb238fSKowalski, Kamil     return certificate;
14558eb238fSKowalski, Kamil }
14658eb238fSKowalski, Kamil 
1475968caeeSMarri Devender Rao /**
1485968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
1495968caeeSMarri Devender Rao  */
1505968caeeSMarri Devender Rao class CertificateFile
1515968caeeSMarri Devender Rao {
1525968caeeSMarri Devender Rao   public:
1535968caeeSMarri Devender Rao     CertificateFile() = delete;
1545968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
1555968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
1565968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
1575968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
1585968caeeSMarri Devender Rao     CertificateFile(const std::string& certString)
1595968caeeSMarri Devender Rao     {
16072d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1615207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1625207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1635207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
164e662eae8SEd Tanous         if (tempDirectory != nullptr)
1655968caeeSMarri Devender Rao         {
1665968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1675968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1685968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1695968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1705968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1715968caeeSMarri Devender Rao             out << certString;
1725968caeeSMarri Devender Rao             out.close();
1738cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Creating certificate file"
1748cc8edecSEd Tanous                              << certificateFile.string();
1755968caeeSMarri Devender Rao         }
1765968caeeSMarri Devender Rao     }
1775968caeeSMarri Devender Rao     ~CertificateFile()
1785968caeeSMarri Devender Rao     {
1795968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1805968caeeSMarri Devender Rao         {
1818cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Removing certificate file"
1828cc8edecSEd Tanous                              << certificateFile.string();
18323a21a1cSEd Tanous             std::error_code ec;
18423a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
18523a21a1cSEd Tanous             if (ec)
1865968caeeSMarri Devender Rao             {
1875968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1888cc8edecSEd Tanous                                  << certDirectory.string();
1895968caeeSMarri Devender Rao             }
1905968caeeSMarri Devender Rao         }
1915968caeeSMarri Devender Rao     }
1925968caeeSMarri Devender Rao     std::string getCertFilePath()
1935968caeeSMarri Devender Rao     {
1945968caeeSMarri Devender Rao         return certificateFile;
1955968caeeSMarri Devender Rao     }
1965968caeeSMarri Devender Rao 
1975968caeeSMarri Devender Rao   private:
1985968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1995968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
2005968caeeSMarri Devender Rao };
2015968caeeSMarri Devender Rao 
20230215816SMarri Devender Rao static std::unique_ptr<sdbusplus::bus::match::match> csrMatcher;
20330215816SMarri Devender Rao /**
20430215816SMarri Devender Rao  * @brief Read data from CSR D-bus object and set to response
20530215816SMarri Devender Rao  *
20630215816SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
20730215816SMarri Devender Rao  * @param[in] certURI Link to certifiate collection URI
20830215816SMarri Devender Rao  * @param[in] service D-Bus service name
20930215816SMarri Devender Rao  * @param[in] certObjPath certificate D-Bus object path
21030215816SMarri Devender Rao  * @param[in] csrObjPath CSR D-Bus object path
21130215816SMarri Devender Rao  * @return None
21230215816SMarri Devender Rao  */
2138d1b46d7Szhanghch05 static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21430215816SMarri Devender Rao                    const std::string& certURI, const std::string& service,
21530215816SMarri Devender Rao                    const std::string& certObjPath,
21630215816SMarri Devender Rao                    const std::string& csrObjPath)
21730215816SMarri Devender Rao {
21830215816SMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
21930215816SMarri Devender Rao                      << " CSRObjectPath=" << csrObjPath
22030215816SMarri Devender Rao                      << " service=" << service;
22130215816SMarri Devender Rao     crow::connections::systemBus->async_method_call(
22230215816SMarri Devender Rao         [asyncResp, certURI](const boost::system::error_code ec,
22330215816SMarri Devender Rao                              const std::string& csr) {
22430215816SMarri Devender Rao         if (ec)
22530215816SMarri Devender Rao         {
22630215816SMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
22730215816SMarri Devender Rao             messages::internalError(asyncResp->res);
22830215816SMarri Devender Rao             return;
22930215816SMarri Devender Rao         }
23030215816SMarri Devender Rao         if (csr.empty())
23130215816SMarri Devender Rao         {
23230215816SMarri Devender Rao             BMCWEB_LOG_ERROR << "CSR read is empty";
23330215816SMarri Devender Rao             messages::internalError(asyncResp->res);
23430215816SMarri Devender Rao             return;
23530215816SMarri Devender Rao         }
23630215816SMarri Devender Rao         asyncResp->res.jsonValue["CSRString"] = csr;
2371476687dSEd Tanous         asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
2381476687dSEd Tanous             certURI;
23930215816SMarri Devender Rao         },
24030215816SMarri Devender Rao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
24130215816SMarri Devender Rao }
24230215816SMarri Devender Rao 
24330215816SMarri Devender Rao /**
24430215816SMarri Devender Rao  * Action to Generate CSR
24530215816SMarri Devender Rao  */
2467e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionGenerateCSR(App& app)
24730215816SMarri Devender Rao {
2480fda0f12SGeorge Liu     BMCWEB_ROUTE(
2490fda0f12SGeorge Liu         app,
2500fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
2515344ab8eSAbhishek Patel         .privileges(redfish::privileges::postCertificateService)
252002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
253002d39b4SEd Tanous             [&app](const crow::Request& req,
2547e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2553ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
25645ca1b86SEd Tanous         {
25745ca1b86SEd Tanous             return;
25845ca1b86SEd Tanous         }
2592c70f800SEd Tanous         static const int rsaKeyBitLength = 2048;
2608d1b46d7Szhanghch05 
26130215816SMarri Devender Rao         // Required parameters
26230215816SMarri Devender Rao         std::string city;
26330215816SMarri Devender Rao         std::string commonName;
26430215816SMarri Devender Rao         std::string country;
26530215816SMarri Devender Rao         std::string organization;
26630215816SMarri Devender Rao         std::string organizationalUnit;
26730215816SMarri Devender Rao         std::string state;
26830215816SMarri Devender Rao         nlohmann::json certificateCollection;
26930215816SMarri Devender Rao 
27030215816SMarri Devender Rao         // Optional parameters
27130215816SMarri Devender Rao         std::optional<std::vector<std::string>> optAlternativeNames =
27230215816SMarri Devender Rao             std::vector<std::string>();
27330215816SMarri Devender Rao         std::optional<std::string> optContactPerson = "";
27430215816SMarri Devender Rao         std::optional<std::string> optChallengePassword = "";
27530215816SMarri Devender Rao         std::optional<std::string> optEmail = "";
27630215816SMarri Devender Rao         std::optional<std::string> optGivenName = "";
27730215816SMarri Devender Rao         std::optional<std::string> optInitials = "";
2782c70f800SEd Tanous         std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
279aaf3206fSVernon Mauery         std::optional<std::string> optKeyCurveId = "secp384r1";
28030215816SMarri Devender Rao         std::optional<std::string> optKeyPairAlgorithm = "EC";
28130215816SMarri Devender Rao         std::optional<std::vector<std::string>> optKeyUsage =
28230215816SMarri Devender Rao             std::vector<std::string>();
28330215816SMarri Devender Rao         std::optional<std::string> optSurname = "";
28430215816SMarri Devender Rao         std::optional<std::string> optUnstructuredName = "";
28515ed6780SWilly Tu         if (!json_util::readJsonAction(
2860fda0f12SGeorge Liu                 req, asyncResp->res, "City", city, "CommonName", commonName,
2870fda0f12SGeorge Liu                 "ContactPerson", optContactPerson, "Country", country,
2880fda0f12SGeorge Liu                 "Organization", organization, "OrganizationalUnit",
2890fda0f12SGeorge Liu                 organizationalUnit, "State", state, "CertificateCollection",
290002d39b4SEd Tanous                 certificateCollection, "AlternativeNames", optAlternativeNames,
291002d39b4SEd Tanous                 "ChallengePassword", optChallengePassword, "Email", optEmail,
292002d39b4SEd Tanous                 "GivenName", optGivenName, "Initials", optInitials,
293002d39b4SEd Tanous                 "KeyBitLength", optKeyBitLength, "KeyCurveId", optKeyCurveId,
2940fda0f12SGeorge Liu                 "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
2950fda0f12SGeorge Liu                 optKeyUsage, "Surname", optSurname, "UnstructuredName",
2960fda0f12SGeorge Liu                 optUnstructuredName))
29730215816SMarri Devender Rao         {
29830215816SMarri Devender Rao             return;
29930215816SMarri Devender Rao         }
30030215816SMarri Devender Rao 
30130215816SMarri Devender Rao         // bmcweb has no way to store or decode a private key challenge
3027e860f15SJohn Edward Broadbent         // password, which will likely cause bmcweb to crash on startup
3037e860f15SJohn Edward Broadbent         // if this is not set on a post so not allowing the user to set
3047e860f15SJohn Edward Broadbent         // value
30526f6976fSEd Tanous         if (!optChallengePassword->empty())
30630215816SMarri Devender Rao         {
307002d39b4SEd Tanous             messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
308002d39b4SEd Tanous                                                   "ChallengePassword");
30930215816SMarri Devender Rao             return;
31030215816SMarri Devender Rao         }
31130215816SMarri Devender Rao 
31230215816SMarri Devender Rao         std::string certURI;
313002d39b4SEd Tanous         if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
314002d39b4SEd Tanous                                           "@odata.id", certURI))
31530215816SMarri Devender Rao         {
31630215816SMarri Devender Rao             return;
31730215816SMarri Devender Rao         }
31830215816SMarri Devender Rao 
31930215816SMarri Devender Rao         std::string objectPath;
32030215816SMarri Devender Rao         std::string service;
3210fda0f12SGeorge Liu         if (boost::starts_with(
3220fda0f12SGeorge Liu                 certURI,
3230fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
32430215816SMarri Devender Rao         {
32530215816SMarri Devender Rao             objectPath = certs::httpsObjectPath;
32630215816SMarri Devender Rao             service = certs::httpsServiceName;
32730215816SMarri Devender Rao         }
3283b7f0149SMarri Devender Rao         else if (boost::starts_with(
329002d39b4SEd Tanous                      certURI, "/redfish/v1/AccountService/LDAP/Certificates"))
3303b7f0149SMarri Devender Rao         {
3313b7f0149SMarri Devender Rao             objectPath = certs::ldapObjectPath;
3323b7f0149SMarri Devender Rao             service = certs::ldapServiceName;
3333b7f0149SMarri Devender Rao         }
33430215816SMarri Devender Rao         else
33530215816SMarri Devender Rao         {
33630215816SMarri Devender Rao             messages::actionParameterNotSupported(
33730215816SMarri Devender Rao                 asyncResp->res, "CertificateCollection", "GenerateCSR");
33830215816SMarri Devender Rao             return;
33930215816SMarri Devender Rao         }
34030215816SMarri Devender Rao 
34130215816SMarri Devender Rao         // supporting only EC and RSA algorithm
3420fda0f12SGeorge Liu         if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
34330215816SMarri Devender Rao         {
34430215816SMarri Devender Rao             messages::actionParameterNotSupported(
34530215816SMarri Devender Rao                 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
34630215816SMarri Devender Rao             return;
34730215816SMarri Devender Rao         }
34830215816SMarri Devender Rao 
3497e860f15SJohn Edward Broadbent         // supporting only 2048 key bit length for RSA algorithm due to
3507e860f15SJohn Edward Broadbent         // time consumed in generating private key
35130215816SMarri Devender Rao         if (*optKeyPairAlgorithm == "RSA" &&
3522c70f800SEd Tanous             *optKeyBitLength != rsaKeyBitLength)
35330215816SMarri Devender Rao         {
354002d39b4SEd Tanous             messages::propertyValueNotInList(asyncResp->res,
355002d39b4SEd Tanous                                              std::to_string(*optKeyBitLength),
35630215816SMarri Devender Rao                                              "KeyBitLength");
35730215816SMarri Devender Rao             return;
35830215816SMarri Devender Rao         }
35930215816SMarri Devender Rao 
36030215816SMarri Devender Rao         // validate KeyUsage supporting only 1 type based on URL
3610fda0f12SGeorge Liu         if (boost::starts_with(
3620fda0f12SGeorge Liu                 certURI,
3630fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
36430215816SMarri Devender Rao         {
36526f6976fSEd Tanous             if (optKeyUsage->empty())
36630215816SMarri Devender Rao             {
36730215816SMarri Devender Rao                 optKeyUsage->push_back("ServerAuthentication");
36830215816SMarri Devender Rao             }
36930215816SMarri Devender Rao             else if (optKeyUsage->size() == 1)
37030215816SMarri Devender Rao             {
37130215816SMarri Devender Rao                 if ((*optKeyUsage)[0] != "ServerAuthentication")
37230215816SMarri Devender Rao                 {
37330215816SMarri Devender Rao                     messages::propertyValueNotInList(
37430215816SMarri Devender Rao                         asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
37530215816SMarri Devender Rao                     return;
37630215816SMarri Devender Rao                 }
37730215816SMarri Devender Rao             }
37830215816SMarri Devender Rao             else
37930215816SMarri Devender Rao             {
38030215816SMarri Devender Rao                 messages::actionParameterNotSupported(
38130215816SMarri Devender Rao                     asyncResp->res, "KeyUsage", "GenerateCSR");
38230215816SMarri Devender Rao                 return;
38330215816SMarri Devender Rao             }
38430215816SMarri Devender Rao         }
3853b7f0149SMarri Devender Rao         else if (boost::starts_with(
386002d39b4SEd Tanous                      certURI, "/redfish/v1/AccountService/LDAP/Certificates"))
3873b7f0149SMarri Devender Rao         {
38826f6976fSEd Tanous             if (optKeyUsage->empty())
3893b7f0149SMarri Devender Rao             {
3903b7f0149SMarri Devender Rao                 optKeyUsage->push_back("ClientAuthentication");
3913b7f0149SMarri Devender Rao             }
3923b7f0149SMarri Devender Rao             else if (optKeyUsage->size() == 1)
3933b7f0149SMarri Devender Rao             {
3943b7f0149SMarri Devender Rao                 if ((*optKeyUsage)[0] != "ClientAuthentication")
3953b7f0149SMarri Devender Rao                 {
3963b7f0149SMarri Devender Rao                     messages::propertyValueNotInList(
3973b7f0149SMarri Devender Rao                         asyncResp->res, (*optKeyUsage)[0], "KeyUsage");
3983b7f0149SMarri Devender Rao                     return;
3993b7f0149SMarri Devender Rao                 }
4003b7f0149SMarri Devender Rao             }
4013b7f0149SMarri Devender Rao             else
4023b7f0149SMarri Devender Rao             {
4033b7f0149SMarri Devender Rao                 messages::actionParameterNotSupported(
4043b7f0149SMarri Devender Rao                     asyncResp->res, "KeyUsage", "GenerateCSR");
4053b7f0149SMarri Devender Rao                 return;
4063b7f0149SMarri Devender Rao             }
4073b7f0149SMarri Devender Rao         }
40830215816SMarri Devender Rao 
4097e860f15SJohn Edward Broadbent         // Only allow one CSR matcher at a time so setting retry
4107e860f15SJohn Edward Broadbent         // time-out and timer expiry to 10 seconds for now.
4112c70f800SEd Tanous         static const int timeOut = 10;
41230215816SMarri Devender Rao         if (csrMatcher)
41330215816SMarri Devender Rao         {
414002d39b4SEd Tanous             messages::serviceTemporarilyUnavailable(asyncResp->res,
415002d39b4SEd Tanous                                                     std::to_string(timeOut));
41630215816SMarri Devender Rao             return;
41730215816SMarri Devender Rao         }
41830215816SMarri Devender Rao 
41930215816SMarri Devender Rao         // Make this static so it survives outside this method
42030215816SMarri Devender Rao         static boost::asio::steady_timer timeout(*req.ioService);
4212c70f800SEd Tanous         timeout.expires_after(std::chrono::seconds(timeOut));
422002d39b4SEd Tanous         timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
42330215816SMarri Devender Rao             csrMatcher = nullptr;
42430215816SMarri Devender Rao             if (ec)
42530215816SMarri Devender Rao             {
4267e860f15SJohn Edward Broadbent                 // operation_aborted is expected if timer is canceled
4277e860f15SJohn Edward Broadbent                 // before completion.
42830215816SMarri Devender Rao                 if (ec != boost::asio::error::operation_aborted)
42930215816SMarri Devender Rao                 {
43030215816SMarri Devender Rao                     BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
43130215816SMarri Devender Rao                 }
43230215816SMarri Devender Rao                 return;
43330215816SMarri Devender Rao             }
43430215816SMarri Devender Rao             BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
43530215816SMarri Devender Rao             messages::internalError(asyncResp->res);
43630215816SMarri Devender Rao         });
43730215816SMarri Devender Rao 
43830215816SMarri Devender Rao         // create a matcher to wait on CSR object
43930215816SMarri Devender Rao         BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
4400fda0f12SGeorge Liu         std::string match("type='signal',"
44130215816SMarri Devender Rao                           "interface='org.freedesktop.DBus.ObjectManager',"
44230215816SMarri Devender Rao                           "path='" +
44330215816SMarri Devender Rao                           objectPath +
44430215816SMarri Devender Rao                           "',"
44530215816SMarri Devender Rao                           "member='InterfacesAdded'");
44630215816SMarri Devender Rao         csrMatcher = std::make_unique<sdbusplus::bus::match::match>(
44730215816SMarri Devender Rao             *crow::connections::systemBus, match,
44830215816SMarri Devender Rao             [asyncResp, service, objectPath,
44930215816SMarri Devender Rao              certURI](sdbusplus::message::message& m) {
450271584abSEd Tanous             timeout.cancel();
45130215816SMarri Devender Rao             if (m.is_method_error())
45230215816SMarri Devender Rao             {
45330215816SMarri Devender Rao                 BMCWEB_LOG_ERROR << "Dbus method error!!!";
45430215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
45530215816SMarri Devender Rao                 return;
45630215816SMarri Devender Rao             }
457b9d36b47SEd Tanous 
458b9d36b47SEd Tanous             dbus::utility::DBusInteracesMap interfacesProperties;
459b9d36b47SEd Tanous 
46030215816SMarri Devender Rao             sdbusplus::message::object_path csrObjectPath;
46130215816SMarri Devender Rao             m.read(csrObjectPath, interfacesProperties);
4620fda0f12SGeorge Liu             BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
46330215816SMarri Devender Rao             for (auto& interface : interfacesProperties)
46430215816SMarri Devender Rao             {
4650fda0f12SGeorge Liu                 if (interface.first == "xyz.openbmc_project.Certs.CSR")
46630215816SMarri Devender Rao                 {
46730215816SMarri Devender Rao                     getCSR(asyncResp, certURI, service, objectPath,
46830215816SMarri Devender Rao                            csrObjectPath.str);
46930215816SMarri Devender Rao                     break;
47030215816SMarri Devender Rao                 }
47130215816SMarri Devender Rao             }
47230215816SMarri Devender Rao             });
47330215816SMarri Devender Rao         crow::connections::systemBus->async_method_call(
474914e2d5dSEd Tanous             [asyncResp](const boost::system::error_code ec,
475cb13a392SEd Tanous                         const std::string&) {
47630215816SMarri Devender Rao             if (ec)
47730215816SMarri Devender Rao             {
478002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
47930215816SMarri Devender Rao                 messages::internalError(asyncResp->res);
48030215816SMarri Devender Rao                 return;
48130215816SMarri Devender Rao             }
48230215816SMarri Devender Rao             },
48330215816SMarri Devender Rao             service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
484002d39b4SEd Tanous             "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
485002d39b4SEd Tanous             commonName, *optContactPerson, country, *optEmail, *optGivenName,
486002d39b4SEd Tanous             *optInitials, *optKeyBitLength, *optKeyCurveId,
4870fda0f12SGeorge Liu             *optKeyPairAlgorithm, *optKeyUsage, organization,
4880fda0f12SGeorge Liu             organizationalUnit, state, *optSurname, *optUnstructuredName);
4897e860f15SJohn Edward Broadbent         });
4907e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionGenerateCSR
49130215816SMarri Devender Rao 
4925968caeeSMarri Devender Rao /**
4934e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
4945968caeeSMarri Devender Rao  *
4955968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
4965968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
4975968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
4985968caeeSMarri Devender Rao  * @return None
4995968caeeSMarri Devender Rao  */
5005968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
5015968caeeSMarri Devender Rao                                       const std::string_view value)
5025968caeeSMarri Devender Rao {
5035968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
5045968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
5055968caeeSMarri Devender Rao     while (i != value.end())
5065968caeeSMarri Devender Rao     {
5075968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
5085968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
5095968caeeSMarri Devender Rao         {
51017a897dfSManojkiran Eda             ++i;
5115968caeeSMarri Devender Rao         }
5125968caeeSMarri Devender Rao         if (i == value.end())
5135968caeeSMarri Devender Rao         {
5145968caeeSMarri Devender Rao             break;
5155968caeeSMarri Devender Rao         }
516271584abSEd Tanous         const std::string_view key(tokenBegin,
517271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
51817a897dfSManojkiran Eda         ++i;
5195968caeeSMarri Devender Rao         tokenBegin = i;
5205968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
5215968caeeSMarri Devender Rao         {
52217a897dfSManojkiran Eda             ++i;
5235968caeeSMarri Devender Rao         }
524271584abSEd Tanous         const std::string_view val(tokenBegin,
525271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
5265968caeeSMarri Devender Rao         if (key == "L")
5275968caeeSMarri Devender Rao         {
5285968caeeSMarri Devender Rao             out["City"] = val;
5295968caeeSMarri Devender Rao         }
5305968caeeSMarri Devender Rao         else if (key == "CN")
5315968caeeSMarri Devender Rao         {
5325968caeeSMarri Devender Rao             out["CommonName"] = val;
5335968caeeSMarri Devender Rao         }
5345968caeeSMarri Devender Rao         else if (key == "C")
5355968caeeSMarri Devender Rao         {
5365968caeeSMarri Devender Rao             out["Country"] = val;
5375968caeeSMarri Devender Rao         }
5385968caeeSMarri Devender Rao         else if (key == "O")
5395968caeeSMarri Devender Rao         {
5405968caeeSMarri Devender Rao             out["Organization"] = val;
5415968caeeSMarri Devender Rao         }
5425968caeeSMarri Devender Rao         else if (key == "OU")
5435968caeeSMarri Devender Rao         {
5445968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
5455968caeeSMarri Devender Rao         }
5465968caeeSMarri Devender Rao         else if (key == "ST")
5475968caeeSMarri Devender Rao         {
5485968caeeSMarri Devender Rao             out["State"] = val;
5495968caeeSMarri Devender Rao         }
5505968caeeSMarri Devender Rao         // skip comma character
5515968caeeSMarri Devender Rao         if (i != value.end())
5525968caeeSMarri Devender Rao         {
55317a897dfSManojkiran Eda             ++i;
5545968caeeSMarri Devender Rao         }
5555968caeeSMarri Devender Rao     }
5565968caeeSMarri Devender Rao }
5575968caeeSMarri Devender Rao 
5585968caeeSMarri Devender Rao /**
5595968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
5605968caeeSMarri Devender Rao  * message
5615968caeeSMarri Devender Rao  *
5625968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
5635968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
5645968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
5655968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
5665968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
5675968caeeSMarri Devender Rao  * @return None
5685968caeeSMarri Devender Rao  */
5695968caeeSMarri Devender Rao static void getCertificateProperties(
5708d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5718d1b46d7Szhanghch05     const std::string& objectPath, const std::string& service, long certId,
5728d1b46d7Szhanghch05     const std::string& certURL, const std::string& name)
5735968caeeSMarri Devender Rao {
5745968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
5755968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
5765968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
577b9d36b47SEd Tanous         [asyncResp, certURL, certId,
578b9d36b47SEd Tanous          name](const boost::system::error_code ec,
579b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
5805968caeeSMarri Devender Rao         if (ec)
5815968caeeSMarri Devender Rao         {
5825968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
5838aae75adSMarri Devender Rao             messages::resourceNotFound(asyncResp->res, name,
5848aae75adSMarri Devender Rao                                        std::to_string(certId));
5855968caeeSMarri Devender Rao             return;
5865968caeeSMarri Devender Rao         }
5871476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = certURL;
5881476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
5891476687dSEd Tanous             "#Certificate.v1_0_0.Certificate";
5901476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = std::to_string(certId);
5911476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = name;
5921476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = name;
5935968caeeSMarri Devender Rao         for (const auto& property : properties)
5945968caeeSMarri Devender Rao         {
5955968caeeSMarri Devender Rao             if (property.first == "CertificateString")
5965968caeeSMarri Devender Rao             {
5975968caeeSMarri Devender Rao                 asyncResp->res.jsonValue["CertificateString"] = "";
5985968caeeSMarri Devender Rao                 const std::string* value =
5995968caeeSMarri Devender Rao                     std::get_if<std::string>(&property.second);
600e662eae8SEd Tanous                 if (value != nullptr)
6015968caeeSMarri Devender Rao                 {
60237cce918SMarri Devender Rao                     asyncResp->res.jsonValue["CertificateString"] = *value;
6035968caeeSMarri Devender Rao                 }
6045968caeeSMarri Devender Rao             }
6055968caeeSMarri Devender Rao             else if (property.first == "KeyUsage")
6065968caeeSMarri Devender Rao             {
607002d39b4SEd Tanous                 nlohmann::json& keyUsage = asyncResp->res.jsonValue["KeyUsage"];
6085968caeeSMarri Devender Rao                 keyUsage = nlohmann::json::array();
6095968caeeSMarri Devender Rao                 const std::vector<std::string>* value =
61037cce918SMarri Devender Rao                     std::get_if<std::vector<std::string>>(&property.second);
611e662eae8SEd Tanous                 if (value != nullptr)
6125968caeeSMarri Devender Rao                 {
6135968caeeSMarri Devender Rao                     for (const std::string& usage : *value)
6145968caeeSMarri Devender Rao                     {
6155968caeeSMarri Devender Rao                         keyUsage.push_back(usage);
6165968caeeSMarri Devender Rao                     }
6175968caeeSMarri Devender Rao                 }
6185968caeeSMarri Devender Rao             }
6195968caeeSMarri Devender Rao             else if (property.first == "Issuer")
6205968caeeSMarri Devender Rao             {
6215968caeeSMarri Devender Rao                 const std::string* value =
6225968caeeSMarri Devender Rao                     std::get_if<std::string>(&property.second);
623e662eae8SEd Tanous                 if (value != nullptr)
6245968caeeSMarri Devender Rao                 {
6255968caeeSMarri Devender Rao                     updateCertIssuerOrSubject(
6265968caeeSMarri Devender Rao                         asyncResp->res.jsonValue["Issuer"], *value);
6275968caeeSMarri Devender Rao                 }
6285968caeeSMarri Devender Rao             }
6295968caeeSMarri Devender Rao             else if (property.first == "Subject")
6305968caeeSMarri Devender Rao             {
6315968caeeSMarri Devender Rao                 const std::string* value =
6325968caeeSMarri Devender Rao                     std::get_if<std::string>(&property.second);
633e662eae8SEd Tanous                 if (value != nullptr)
6345968caeeSMarri Devender Rao                 {
6355968caeeSMarri Devender Rao                     updateCertIssuerOrSubject(
63637cce918SMarri Devender Rao                         asyncResp->res.jsonValue["Subject"], *value);
6375968caeeSMarri Devender Rao                 }
6385968caeeSMarri Devender Rao             }
6395968caeeSMarri Devender Rao             else if (property.first == "ValidNotAfter")
6405968caeeSMarri Devender Rao             {
641002d39b4SEd Tanous                 const uint64_t* value = std::get_if<uint64_t>(&property.second);
642e662eae8SEd Tanous                 if (value != nullptr)
6435968caeeSMarri Devender Rao                 {
6445968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["ValidNotAfter"] =
6451d8782e7SNan Zhou                         crow::utility::getDateTimeUint(*value);
6465968caeeSMarri Devender Rao                 }
6475968caeeSMarri Devender Rao             }
6485968caeeSMarri Devender Rao             else if (property.first == "ValidNotBefore")
6495968caeeSMarri Devender Rao             {
650002d39b4SEd Tanous                 const uint64_t* value = std::get_if<uint64_t>(&property.second);
651e662eae8SEd Tanous                 if (value != nullptr)
6525968caeeSMarri Devender Rao                 {
6535968caeeSMarri Devender Rao                     asyncResp->res.jsonValue["ValidNotBefore"] =
6541d8782e7SNan Zhou                         crow::utility::getDateTimeUint(*value);
6555968caeeSMarri Devender Rao                 }
6565968caeeSMarri Devender Rao             }
6575968caeeSMarri Devender Rao         }
6585968caeeSMarri Devender Rao         asyncResp->res.addHeader("Location", certURL);
6595968caeeSMarri Devender Rao         },
6605968caeeSMarri Devender Rao         service, objectPath, certs::dbusPropIntf, "GetAll",
6615968caeeSMarri Devender Rao         certs::certPropIntf);
6625968caeeSMarri Devender Rao }
6635968caeeSMarri Devender Rao 
6645968caeeSMarri Devender Rao /**
6655968caeeSMarri Devender Rao  * Action to replace an existing certificate
6665968caeeSMarri Devender Rao  */
6677e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionsReplaceCertificate(App& app)
6685968caeeSMarri Devender Rao {
6690fda0f12SGeorge Liu     BMCWEB_ROUTE(
6700fda0f12SGeorge Liu         app,
6710fda0f12SGeorge Liu         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
672ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateService)
673002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
674002d39b4SEd Tanous             [&app](const crow::Request& req,
6757e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
6763ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
67745ca1b86SEd Tanous         {
67845ca1b86SEd Tanous             return;
67945ca1b86SEd Tanous         }
6805968caeeSMarri Devender Rao         std::string certificate;
6815968caeeSMarri Devender Rao         nlohmann::json certificateUri;
6825968caeeSMarri Devender Rao         std::optional<std::string> certificateType = "PEM";
6838d1b46d7Szhanghch05 
684002d39b4SEd Tanous         if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
685002d39b4SEd Tanous                                        certificate, "CertificateUri",
686002d39b4SEd Tanous                                        certificateUri, "CertificateType",
687002d39b4SEd Tanous                                        certificateType))
6885968caeeSMarri Devender Rao         {
6895968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "Required parameters are missing";
6905968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
6915968caeeSMarri Devender Rao             return;
6925968caeeSMarri Devender Rao         }
6935968caeeSMarri Devender Rao 
6945968caeeSMarri Devender Rao         if (!certificateType)
6955968caeeSMarri Devender Rao         {
6965968caeeSMarri Devender Rao             // should never happen, but it never hurts to be paranoid.
6975968caeeSMarri Devender Rao             return;
6985968caeeSMarri Devender Rao         }
6995968caeeSMarri Devender Rao         if (certificateType != "PEM")
7005968caeeSMarri Devender Rao         {
7015968caeeSMarri Devender Rao             messages::actionParameterNotSupported(
7025968caeeSMarri Devender Rao                 asyncResp->res, "CertificateType", "ReplaceCertificate");
7035968caeeSMarri Devender Rao             return;
7045968caeeSMarri Devender Rao         }
7055968caeeSMarri Devender Rao 
7065968caeeSMarri Devender Rao         std::string certURI;
7075968caeeSMarri Devender Rao         if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
7085968caeeSMarri Devender Rao                                           "@odata.id", certURI))
7095968caeeSMarri Devender Rao         {
7105968caeeSMarri Devender Rao             messages::actionParameterMissing(
7115968caeeSMarri Devender Rao                 asyncResp->res, "ReplaceCertificate", "CertificateUri");
7125968caeeSMarri Devender Rao             return;
7135968caeeSMarri Devender Rao         }
7145968caeeSMarri Devender Rao 
7155968caeeSMarri Devender Rao         BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI;
7165968caeeSMarri Devender Rao         long id = getIDFromURL(certURI);
7175968caeeSMarri Devender Rao         if (id < 0)
7185968caeeSMarri Devender Rao         {
719002d39b4SEd Tanous             messages::actionParameterValueFormatError(asyncResp->res, certURI,
720002d39b4SEd Tanous                                                       "CertificateUri",
7215968caeeSMarri Devender Rao                                                       "ReplaceCertificate");
7225968caeeSMarri Devender Rao             return;
7235968caeeSMarri Devender Rao         }
7245968caeeSMarri Devender Rao         std::string objectPath;
7255968caeeSMarri Devender Rao         std::string name;
72637cce918SMarri Devender Rao         std::string service;
7270fda0f12SGeorge Liu         if (boost::starts_with(
7280fda0f12SGeorge Liu                 certURI,
7290fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"))
7305968caeeSMarri Devender Rao         {
731002d39b4SEd Tanous             objectPath =
732002d39b4SEd Tanous                 std::string(certs::httpsObjectPath) + "/" + std::to_string(id);
7335968caeeSMarri Devender Rao             name = "HTTPS certificate";
73437cce918SMarri Devender Rao             service = certs::httpsServiceName;
73537cce918SMarri Devender Rao         }
73637cce918SMarri Devender Rao         else if (boost::starts_with(
737002d39b4SEd Tanous                      certURI, "/redfish/v1/AccountService/LDAP/Certificates/"))
73837cce918SMarri Devender Rao         {
739002d39b4SEd Tanous             objectPath =
740002d39b4SEd Tanous                 std::string(certs::ldapObjectPath) + "/" + std::to_string(id);
74137cce918SMarri Devender Rao             name = "LDAP certificate";
74237cce918SMarri Devender Rao             service = certs::ldapServiceName;
7435968caeeSMarri Devender Rao         }
744cfcd5f6bSMarri Devender Rao         else if (boost::starts_with(
745cfcd5f6bSMarri Devender Rao                      certURI,
746cfcd5f6bSMarri Devender Rao                      "/redfish/v1/Managers/bmc/Truststore/Certificates/"))
747cfcd5f6bSMarri Devender Rao         {
748cfcd5f6bSMarri Devender Rao             objectPath = std::string(certs::authorityObjectPath) + "/" +
749cfcd5f6bSMarri Devender Rao                          std::to_string(id);
750cfcd5f6bSMarri Devender Rao             name = "TrustStore certificate";
751cfcd5f6bSMarri Devender Rao             service = certs::authorityServiceName;
752cfcd5f6bSMarri Devender Rao         }
7535968caeeSMarri Devender Rao         else
7545968caeeSMarri Devender Rao         {
7555968caeeSMarri Devender Rao             messages::actionParameterNotSupported(
7565968caeeSMarri Devender Rao                 asyncResp->res, "CertificateUri", "ReplaceCertificate");
7575968caeeSMarri Devender Rao             return;
7585968caeeSMarri Devender Rao         }
7595968caeeSMarri Devender Rao 
7605968caeeSMarri Devender Rao         std::shared_ptr<CertificateFile> certFile =
7615968caeeSMarri Devender Rao             std::make_shared<CertificateFile>(certificate);
7625968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
76337cce918SMarri Devender Rao             [asyncResp, certFile, objectPath, service, certURI, id,
7645968caeeSMarri Devender Rao              name](const boost::system::error_code ec) {
7655968caeeSMarri Devender Rao             if (ec)
7665968caeeSMarri Devender Rao             {
7675968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
76890d2d1e8SJiaqing Zhao                 if (ec.value() ==
76990d2d1e8SJiaqing Zhao                     boost::system::linux_error::bad_request_descriptor)
77090d2d1e8SJiaqing Zhao                 {
7718aae75adSMarri Devender Rao                     messages::resourceNotFound(asyncResp->res, name,
7728aae75adSMarri Devender Rao                                                std::to_string(id));
7735968caeeSMarri Devender Rao                     return;
7745968caeeSMarri Devender Rao                 }
77590d2d1e8SJiaqing Zhao                 messages::internalError(asyncResp->res);
77690d2d1e8SJiaqing Zhao                 return;
77790d2d1e8SJiaqing Zhao             }
77837cce918SMarri Devender Rao             getCertificateProperties(asyncResp, objectPath, service, id,
7795968caeeSMarri Devender Rao                                      certURI, name);
7805968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
7815968caeeSMarri Devender Rao                              << certFile->getCertFilePath();
7825968caeeSMarri Devender Rao             },
7835968caeeSMarri Devender Rao             service, objectPath, certs::certReplaceIntf, "Replace",
7845968caeeSMarri Devender Rao             certFile->getCertFilePath());
7857e860f15SJohn Edward Broadbent         });
7867e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionsReplaceCertificate
7875968caeeSMarri Devender Rao 
7885968caeeSMarri Devender Rao /**
7895968caeeSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
7905968caeeSMarri Devender Rao  * of a component, account or service.
7915968caeeSMarri Devender Rao  */
7925968caeeSMarri Devender Rao 
7937e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificate(App& app)
7945968caeeSMarri Devender Rao {
7957e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
7967e860f15SJohn Edward Broadbent         app,
7977e860f15SJohn Edward Broadbent         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
798ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
7997e860f15SJohn Edward Broadbent         .methods(
8007e860f15SJohn Edward Broadbent             boost::beast::http::verb::
80145ca1b86SEd Tanous                 get)([&app](const crow::Request& req,
8027e860f15SJohn Edward Broadbent                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8037e860f15SJohn Edward Broadbent                             const std::string& param) -> void {
8043ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
80545ca1b86SEd Tanous             {
80645ca1b86SEd Tanous                 return;
80745ca1b86SEd Tanous             }
8087e860f15SJohn Edward Broadbent             if (param.empty())
8095968caeeSMarri Devender Rao             {
8105968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
8115968caeeSMarri Devender Rao                 return;
8125968caeeSMarri Devender Rao             }
8135968caeeSMarri Devender Rao             long id = getIDFromURL(req.url);
8145968caeeSMarri Devender Rao 
8157e860f15SJohn Edward Broadbent             BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID="
8167e860f15SJohn Edward Broadbent                              << std::to_string(id);
8175968caeeSMarri Devender Rao             std::string certURL =
8185968caeeSMarri Devender Rao                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8195968caeeSMarri Devender Rao                 std::to_string(id);
8205968caeeSMarri Devender Rao             std::string objectPath = certs::httpsObjectPath;
8215968caeeSMarri Devender Rao             objectPath += "/";
8225968caeeSMarri Devender Rao             objectPath += std::to_string(id);
8237e860f15SJohn Edward Broadbent             getCertificateProperties(asyncResp, objectPath,
8247e860f15SJohn Edward Broadbent                                      certs::httpsServiceName, id, certURL,
8257e860f15SJohn Edward Broadbent                                      "HTTPS Certificate");
8267e860f15SJohn Edward Broadbent         });
8275968caeeSMarri Devender Rao }
8285968caeeSMarri Devender Rao 
8295968caeeSMarri Devender Rao /**
8305968caeeSMarri Devender Rao  * Collection of HTTPS certificates
8315968caeeSMarri Devender Rao  */
8327e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificateCollection(App& app)
8335968caeeSMarri Devender Rao {
8347e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8355968caeeSMarri Devender Rao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
836ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
837002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
838002d39b4SEd Tanous             [&app](const crow::Request& req,
839002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8403ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
84145ca1b86SEd Tanous         {
84245ca1b86SEd Tanous             return;
84345ca1b86SEd Tanous         }
8441476687dSEd Tanous 
8451476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
8461476687dSEd Tanous             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
8471476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
8481476687dSEd Tanous             "#CertificateCollection.CertificateCollection";
8491476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8501476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
8511476687dSEd Tanous             "A Collection of HTTPS certificate instances";
8528d1b46d7Szhanghch05 
8535968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
8545968caeeSMarri Devender Rao             [asyncResp](const boost::system::error_code ec,
855711ac7a9SEd Tanous                         const dbus::utility::ManagedObjectType& certs) {
8565968caeeSMarri Devender Rao             if (ec)
8575968caeeSMarri Devender Rao             {
8585968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
8595968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
8605968caeeSMarri Devender Rao                 return;
8615968caeeSMarri Devender Rao             }
862002d39b4SEd Tanous             nlohmann::json& members = asyncResp->res.jsonValue["Members"];
8635968caeeSMarri Devender Rao             members = nlohmann::json::array();
8645968caeeSMarri Devender Rao             for (const auto& cert : certs)
8655968caeeSMarri Devender Rao             {
8665968caeeSMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
86737cce918SMarri Devender Rao                 if (id >= 0)
8685968caeeSMarri Devender Rao                 {
8691476687dSEd Tanous                     nlohmann::json::object_t member;
8701476687dSEd Tanous                     member["@odata.id"] =
8710fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
8721476687dSEd Tanous                         std::to_string(id);
8731476687dSEd Tanous                     members.push_back(std::move(member));
8745968caeeSMarri Devender Rao                 }
8755968caeeSMarri Devender Rao             }
876002d39b4SEd Tanous             asyncResp->res.jsonValue["Members@odata.count"] = members.size();
8775968caeeSMarri Devender Rao             },
87837cce918SMarri Devender Rao             certs::httpsServiceName, certs::httpsObjectPath,
87937cce918SMarri Devender Rao             certs::dbusObjManagerIntf, "GetManagedObjects");
8807e860f15SJohn Edward Broadbent         });
8815968caeeSMarri Devender Rao 
8827e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
8837e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
884ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
885002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
886002d39b4SEd Tanous             [&app](const crow::Request& req,
8877e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
8883ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
88945ca1b86SEd Tanous         {
89045ca1b86SEd Tanous             return;
89145ca1b86SEd Tanous         }
8925968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
8938d1b46d7Szhanghch05 
8941476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
8951476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
8965968caeeSMarri Devender Rao 
897002d39b4SEd Tanous         std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
89858eb238fSKowalski, Kamil 
89958eb238fSKowalski, Kamil         if (certFileBody.empty())
90058eb238fSKowalski, Kamil         {
9010fda0f12SGeorge Liu             BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
902a08752f5SZbigniew Kurzynski             messages::unrecognizedRequestBody(asyncResp->res);
90358eb238fSKowalski, Kamil             return;
90458eb238fSKowalski, Kamil         }
90558eb238fSKowalski, Kamil 
9065968caeeSMarri Devender Rao         std::shared_ptr<CertificateFile> certFile =
90758eb238fSKowalski, Kamil             std::make_shared<CertificateFile>(certFileBody);
9085968caeeSMarri Devender Rao 
9095968caeeSMarri Devender Rao         crow::connections::systemBus->async_method_call(
910656ec7e3SZbigniew Kurzynski             [asyncResp, certFile](const boost::system::error_code ec,
911656ec7e3SZbigniew Kurzynski                                   const std::string& objectPath) {
9125968caeeSMarri Devender Rao             if (ec)
9135968caeeSMarri Devender Rao             {
9145968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9155968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
9165968caeeSMarri Devender Rao                 return;
9175968caeeSMarri Devender Rao             }
918656ec7e3SZbigniew Kurzynski             long certId = getIDFromURL(objectPath);
919656ec7e3SZbigniew Kurzynski             if (certId < 0)
920656ec7e3SZbigniew Kurzynski             {
921002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath;
922656ec7e3SZbigniew Kurzynski                 messages::internalError(asyncResp->res);
923656ec7e3SZbigniew Kurzynski                 return;
924656ec7e3SZbigniew Kurzynski             }
9255968caeeSMarri Devender Rao             std::string certURL =
9260fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" +
9275968caeeSMarri Devender Rao                 std::to_string(certId);
9280fda0f12SGeorge Liu             getCertificateProperties(asyncResp, objectPath,
929002d39b4SEd Tanous                                      certs::httpsServiceName, certId, certURL,
930002d39b4SEd Tanous                                      "HTTPS Certificate");
9315968caeeSMarri Devender Rao             BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9325968caeeSMarri Devender Rao                              << certFile->getCertFilePath();
9335968caeeSMarri Devender Rao             },
93437cce918SMarri Devender Rao             certs::httpsServiceName, certs::httpsObjectPath,
9350fda0f12SGeorge Liu             certs::certInstallIntf, "Install", certFile->getCertFilePath());
9367e860f15SJohn Edward Broadbent         });
9377e860f15SJohn Edward Broadbent } // requestRoutesHTTPSCertificateCollection
9385968caeeSMarri Devender Rao 
9395968caeeSMarri Devender Rao /**
940*c6a8dfb1SJiaqing Zhao  * @brief Retrieve the installed certificate list
94137cce918SMarri Devender Rao  *
94237cce918SMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
94337cce918SMarri Devender Rao  * @return None
94437cce918SMarri Devender Rao  */
9454f48d5f6SEd Tanous inline void
946*c6a8dfb1SJiaqing Zhao     getCertificateLocations(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
94737cce918SMarri Devender Rao {
94837cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
949*c6a8dfb1SJiaqing Zhao         [asyncResp](
950*c6a8dfb1SJiaqing Zhao             const boost::system::error_code ec,
951*c6a8dfb1SJiaqing Zhao             const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
95237cce918SMarri Devender Rao         if (ec)
95337cce918SMarri Devender Rao         {
954*c6a8dfb1SJiaqing Zhao             BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
955*c6a8dfb1SJiaqing Zhao             messages::internalError(asyncResp->res);
95637cce918SMarri Devender Rao             return;
95737cce918SMarri Devender Rao         }
958*c6a8dfb1SJiaqing Zhao 
95937cce918SMarri Devender Rao         nlohmann::json& links =
96037cce918SMarri Devender Rao             asyncResp->res.jsonValue["Links"]["Certificates"];
961*c6a8dfb1SJiaqing Zhao         links = nlohmann::json::array();
962*c6a8dfb1SJiaqing Zhao         for (const auto& certPath : certPaths)
96337cce918SMarri Devender Rao         {
964*c6a8dfb1SJiaqing Zhao             sdbusplus::message::object_path objPath(certPath);
965*c6a8dfb1SJiaqing Zhao             std::string certId = objPath.filename();
966*c6a8dfb1SJiaqing Zhao             if (certId.empty())
96737cce918SMarri Devender Rao             {
968*c6a8dfb1SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
969*c6a8dfb1SJiaqing Zhao                 continue;
970*c6a8dfb1SJiaqing Zhao             }
971*c6a8dfb1SJiaqing Zhao 
972*c6a8dfb1SJiaqing Zhao             boost::urls::url certURL;
973*c6a8dfb1SJiaqing Zhao             if (objPath.parent_path() == certs::httpsObjectPath)
974*c6a8dfb1SJiaqing Zhao             {
975*c6a8dfb1SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
976*c6a8dfb1SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
977*c6a8dfb1SJiaqing Zhao                     "HTTPS", "Certificates", certId);
978*c6a8dfb1SJiaqing Zhao             }
979*c6a8dfb1SJiaqing Zhao             else if (objPath.parent_path() == certs::ldapObjectPath)
980*c6a8dfb1SJiaqing Zhao             {
981*c6a8dfb1SJiaqing Zhao                 certURL = crow::utility::urlFromPieces("redfish", "v1",
982*c6a8dfb1SJiaqing Zhao                                                        "AccountService", "LDAP",
983*c6a8dfb1SJiaqing Zhao                                                        "Certificates", certId);
984*c6a8dfb1SJiaqing Zhao             }
985*c6a8dfb1SJiaqing Zhao             else if (objPath.parent_path() == certs::authorityObjectPath)
986*c6a8dfb1SJiaqing Zhao             {
987*c6a8dfb1SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
988*c6a8dfb1SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "Truststore",
989*c6a8dfb1SJiaqing Zhao                     "Certificates", certId);
990*c6a8dfb1SJiaqing Zhao             }
991*c6a8dfb1SJiaqing Zhao             else
992*c6a8dfb1SJiaqing Zhao             {
993*c6a8dfb1SJiaqing Zhao                 continue;
994*c6a8dfb1SJiaqing Zhao             }
9951476687dSEd Tanous             nlohmann::json::object_t link;
996*c6a8dfb1SJiaqing Zhao             link["@odata.id"] = certURL;
997*c6a8dfb1SJiaqing Zhao             links.emplace_back(std::move(link));
99837cce918SMarri Devender Rao         }
999*c6a8dfb1SJiaqing Zhao 
100037cce918SMarri Devender Rao         asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] =
100137cce918SMarri Devender Rao             links.size();
100237cce918SMarri Devender Rao         },
1003*c6a8dfb1SJiaqing Zhao         "xyz.openbmc_project.ObjectMapper",
1004*c6a8dfb1SJiaqing Zhao         "/xyz/openbmc_project/object_mapper",
1005*c6a8dfb1SJiaqing Zhao         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1006*c6a8dfb1SJiaqing Zhao         certs::baseObjectPath, 0,
1007*c6a8dfb1SJiaqing Zhao         std::array<const char*, 1>{certs::certPropIntf});
10085968caeeSMarri Devender Rao }
10097e860f15SJohn Edward Broadbent 
10107e860f15SJohn Edward Broadbent /**
10117e860f15SJohn Edward Broadbent  * The certificate location schema defines a resource that an administrator
10127e860f15SJohn Edward Broadbent  * can use in order to locate all certificates installed on a given service.
10137e860f15SJohn Edward Broadbent  */
10147e860f15SJohn Edward Broadbent inline void requestRoutesCertificateLocations(App& app)
10157e860f15SJohn Edward Broadbent {
10167e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
1017ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateLocations)
1018002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1019002d39b4SEd Tanous             [&app](const crow::Request& req,
1020002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10213ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
102245ca1b86SEd Tanous         {
102345ca1b86SEd Tanous             return;
102445ca1b86SEd Tanous         }
10251476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
10261476687dSEd Tanous             "/redfish/v1/CertificateService/CertificateLocations";
10271476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
10281476687dSEd Tanous             "#CertificateLocations.v1_0_0.CertificateLocations";
10291476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "Certificate Locations";
10301476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "CertificateLocations";
10311476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
10327e860f15SJohn Edward Broadbent             "Defines a resource that an administrator can use in order to "
10331476687dSEd Tanous             "locate all certificates installed on a given service";
10347e860f15SJohn Edward Broadbent 
1035*c6a8dfb1SJiaqing Zhao         getCertificateLocations(asyncResp);
10367e860f15SJohn Edward Broadbent         });
10377e860f15SJohn Edward Broadbent }
10387e860f15SJohn Edward Broadbent // requestRoutesCertificateLocations
103937cce918SMarri Devender Rao 
104037cce918SMarri Devender Rao /**
104137cce918SMarri Devender Rao  * Collection of LDAP certificates
104237cce918SMarri Devender Rao  */
10437e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificateCollection(App& app)
104437cce918SMarri Devender Rao {
10457e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1046ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
1047002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1048002d39b4SEd Tanous             [&app](const crow::Request& req,
1049002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10503ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
105145ca1b86SEd Tanous         {
105245ca1b86SEd Tanous             return;
105345ca1b86SEd Tanous         }
10541476687dSEd Tanous 
10551476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
10561476687dSEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates";
10571476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
10581476687dSEd Tanous             "#CertificateCollection.CertificateCollection";
10591476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10601476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
10611476687dSEd Tanous             "A Collection of LDAP certificate instances";
10628d1b46d7Szhanghch05 
106337cce918SMarri Devender Rao         crow::connections::systemBus->async_method_call(
106437cce918SMarri Devender Rao             [asyncResp](const boost::system::error_code ec,
1065711ac7a9SEd Tanous                         const dbus::utility::ManagedObjectType& certs) {
1066002d39b4SEd Tanous             nlohmann::json& members = asyncResp->res.jsonValue["Members"];
10679c8e039eSJonathan Doman             nlohmann::json& count =
10689c8e039eSJonathan Doman                 asyncResp->res.jsonValue["Members@odata.count"];
10699c8e039eSJonathan Doman             members = nlohmann::json::array();
10709c8e039eSJonathan Doman             count = 0;
107137cce918SMarri Devender Rao             if (ec)
107237cce918SMarri Devender Rao             {
1073002d39b4SEd Tanous                 BMCWEB_LOG_WARNING << "LDAP certificate query failed: " << ec;
107437cce918SMarri Devender Rao                 return;
107537cce918SMarri Devender Rao             }
107637cce918SMarri Devender Rao             for (const auto& cert : certs)
107737cce918SMarri Devender Rao             {
107837cce918SMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
107937cce918SMarri Devender Rao                 if (id >= 0)
108037cce918SMarri Devender Rao                 {
10811476687dSEd Tanous                     nlohmann::json::object_t member;
10821476687dSEd Tanous                     member["@odata.id"] =
10830fda0f12SGeorge Liu                         "/redfish/v1/AccountService/LDAP/Certificates/" +
10841476687dSEd Tanous                         std::to_string(id);
10851476687dSEd Tanous                     members.push_back(std::move(member));
108637cce918SMarri Devender Rao                 }
108737cce918SMarri Devender Rao             }
10889c8e039eSJonathan Doman             count = members.size();
108937cce918SMarri Devender Rao             },
109037cce918SMarri Devender Rao             certs::ldapServiceName, certs::ldapObjectPath,
109137cce918SMarri Devender Rao             certs::dbusObjManagerIntf, "GetManagedObjects");
10927e860f15SJohn Edward Broadbent         });
109337cce918SMarri Devender Rao 
10947e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1095ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
10967e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
109745ca1b86SEd Tanous             [&app](const crow::Request& req,
10987e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10993ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
110045ca1b86SEd Tanous         {
110145ca1b86SEd Tanous             return;
110245ca1b86SEd Tanous         }
1103002d39b4SEd Tanous         std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
110458eb238fSKowalski, Kamil 
110558eb238fSKowalski, Kamil         if (certFileBody.empty())
110658eb238fSKowalski, Kamil         {
1107002d39b4SEd Tanous             BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1108a08752f5SZbigniew Kurzynski             messages::unrecognizedRequestBody(asyncResp->res);
110958eb238fSKowalski, Kamil             return;
111058eb238fSKowalski, Kamil         }
111158eb238fSKowalski, Kamil 
111258eb238fSKowalski, Kamil         std::shared_ptr<CertificateFile> certFile =
111358eb238fSKowalski, Kamil             std::make_shared<CertificateFile>(certFileBody);
111458eb238fSKowalski, Kamil 
111537cce918SMarri Devender Rao         crow::connections::systemBus->async_method_call(
1116656ec7e3SZbigniew Kurzynski             [asyncResp, certFile](const boost::system::error_code ec,
1117656ec7e3SZbigniew Kurzynski                                   const std::string& objectPath) {
111837cce918SMarri Devender Rao             if (ec)
111937cce918SMarri Devender Rao             {
112037cce918SMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
112137cce918SMarri Devender Rao                 messages::internalError(asyncResp->res);
112237cce918SMarri Devender Rao                 return;
112337cce918SMarri Devender Rao             }
1124656ec7e3SZbigniew Kurzynski             long certId = getIDFromURL(objectPath);
1125656ec7e3SZbigniew Kurzynski             if (certId < 0)
1126656ec7e3SZbigniew Kurzynski             {
1127002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath;
1128656ec7e3SZbigniew Kurzynski                 messages::internalError(asyncResp->res);
1129656ec7e3SZbigniew Kurzynski                 return;
1130656ec7e3SZbigniew Kurzynski             }
113137cce918SMarri Devender Rao             std::string certURL =
113237cce918SMarri Devender Rao                 "/redfish/v1/AccountService/LDAP/Certificates/" +
113337cce918SMarri Devender Rao                 std::to_string(certId);
113437cce918SMarri Devender Rao             getCertificateProperties(asyncResp, objectPath,
1135002d39b4SEd Tanous                                      certs::ldapServiceName, certId, certURL,
1136002d39b4SEd Tanous                                      "LDAP Certificate");
113737cce918SMarri Devender Rao             BMCWEB_LOG_DEBUG << "LDAP certificate install file="
113837cce918SMarri Devender Rao                              << certFile->getCertFilePath();
113937cce918SMarri Devender Rao             },
114037cce918SMarri Devender Rao             certs::ldapServiceName, certs::ldapObjectPath,
1141002d39b4SEd Tanous             certs::certInstallIntf, "Install", certFile->getCertFilePath());
11427e860f15SJohn Edward Broadbent         });
11437e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificateCollection
114437cce918SMarri Devender Rao 
114537cce918SMarri Devender Rao /**
114637cce918SMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
114737cce918SMarri Devender Rao  * of a component, account or service.
114837cce918SMarri Devender Rao  */
11497e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificate(App& app)
115037cce918SMarri Devender Rao {
11517e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1152ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
11537e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
115445ca1b86SEd Tanous             [&app](const crow::Request& req,
11557e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11567e860f15SJohn Edward Broadbent                    const std::string&) {
11573ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
115845ca1b86SEd Tanous         {
115945ca1b86SEd Tanous             return;
116045ca1b86SEd Tanous         }
116137cce918SMarri Devender Rao         long id = getIDFromURL(req.url);
116237cce918SMarri Devender Rao         if (id < 0)
116337cce918SMarri Devender Rao         {
116437cce918SMarri Devender Rao             BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
116537cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
116637cce918SMarri Devender Rao             return;
116737cce918SMarri Devender Rao         }
1168002d39b4SEd Tanous         BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << std::to_string(id);
1169002d39b4SEd Tanous         std::string certURL = "/redfish/v1/AccountService/LDAP/Certificates/" +
117037cce918SMarri Devender Rao                               std::to_string(id);
117137cce918SMarri Devender Rao         std::string objectPath = certs::ldapObjectPath;
117237cce918SMarri Devender Rao         objectPath += "/";
117337cce918SMarri Devender Rao         objectPath += std::to_string(id);
1174002d39b4SEd Tanous         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1175002d39b4SEd Tanous                                  id, certURL, "LDAP Certificate");
11767e860f15SJohn Edward Broadbent         });
11777e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificate
1178cfcd5f6bSMarri Devender Rao /**
1179cfcd5f6bSMarri Devender Rao  * Collection of TrustStoreCertificate certificates
1180cfcd5f6bSMarri Devender Rao  */
11817e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificateCollection(App& app)
1182cfcd5f6bSMarri Devender Rao {
11837e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1184ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1185002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1186002d39b4SEd Tanous             [&app](const crow::Request& req,
1187002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
11883ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
118945ca1b86SEd Tanous         {
119045ca1b86SEd Tanous             return;
119145ca1b86SEd Tanous         }
11921476687dSEd Tanous 
11931476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
11941476687dSEd Tanous             "/redfish/v1/Managers/bmc/Truststore/Certificates/";
11951476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
11961476687dSEd Tanous             "#CertificateCollection.CertificateCollection";
1197002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11981476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
11991476687dSEd Tanous             "A Collection of TrustStore certificate instances";
12008d1b46d7Szhanghch05 
1201cfcd5f6bSMarri Devender Rao         crow::connections::systemBus->async_method_call(
1202cfcd5f6bSMarri Devender Rao             [asyncResp](const boost::system::error_code ec,
1203711ac7a9SEd Tanous                         const dbus::utility::ManagedObjectType& certs) {
1204cfcd5f6bSMarri Devender Rao             if (ec)
1205cfcd5f6bSMarri Devender Rao             {
1206cfcd5f6bSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1207cfcd5f6bSMarri Devender Rao                 messages::internalError(asyncResp->res);
1208cfcd5f6bSMarri Devender Rao                 return;
1209cfcd5f6bSMarri Devender Rao             }
1210002d39b4SEd Tanous             nlohmann::json& members = asyncResp->res.jsonValue["Members"];
1211cfcd5f6bSMarri Devender Rao             members = nlohmann::json::array();
1212cfcd5f6bSMarri Devender Rao             for (const auto& cert : certs)
1213cfcd5f6bSMarri Devender Rao             {
1214cfcd5f6bSMarri Devender Rao                 long id = getIDFromURL(cert.first.str);
1215cfcd5f6bSMarri Devender Rao                 if (id >= 0)
1216cfcd5f6bSMarri Devender Rao                 {
12171476687dSEd Tanous                     nlohmann::json::object_t member;
12181476687dSEd Tanous                     member["@odata.id"] =
12190fda0f12SGeorge Liu                         "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
12201476687dSEd Tanous                         std::to_string(id);
12211476687dSEd Tanous                     members.push_back(std::move(member));
1222cfcd5f6bSMarri Devender Rao                 }
1223cfcd5f6bSMarri Devender Rao             }
1224002d39b4SEd Tanous             asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1225cfcd5f6bSMarri Devender Rao             },
1226cfcd5f6bSMarri Devender Rao             certs::authorityServiceName, certs::authorityObjectPath,
1227cfcd5f6bSMarri Devender Rao             certs::dbusObjManagerIntf, "GetManagedObjects");
12287e860f15SJohn Edward Broadbent         });
1229cfcd5f6bSMarri Devender Rao 
12307e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1231ed398213SEd Tanous         .privileges(redfish::privileges::postCertificateCollection)
1232002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
1233002d39b4SEd Tanous             [&app](const crow::Request& req,
12347e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
12353ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
123645ca1b86SEd Tanous         {
123745ca1b86SEd Tanous             return;
123845ca1b86SEd Tanous         }
1239002d39b4SEd Tanous         std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1240a08752f5SZbigniew Kurzynski 
1241a08752f5SZbigniew Kurzynski         if (certFileBody.empty())
1242a08752f5SZbigniew Kurzynski         {
12430fda0f12SGeorge Liu             BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1244a08752f5SZbigniew Kurzynski             messages::unrecognizedRequestBody(asyncResp->res);
1245a08752f5SZbigniew Kurzynski             return;
1246a08752f5SZbigniew Kurzynski         }
1247a08752f5SZbigniew Kurzynski 
1248a08752f5SZbigniew Kurzynski         std::shared_ptr<CertificateFile> certFile =
1249a08752f5SZbigniew Kurzynski             std::make_shared<CertificateFile>(certFileBody);
1250cfcd5f6bSMarri Devender Rao         crow::connections::systemBus->async_method_call(
1251656ec7e3SZbigniew Kurzynski             [asyncResp, certFile](const boost::system::error_code ec,
1252656ec7e3SZbigniew Kurzynski                                   const std::string& objectPath) {
1253cfcd5f6bSMarri Devender Rao             if (ec)
1254cfcd5f6bSMarri Devender Rao             {
1255cfcd5f6bSMarri Devender Rao                 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1256cfcd5f6bSMarri Devender Rao                 messages::internalError(asyncResp->res);
1257cfcd5f6bSMarri Devender Rao                 return;
1258cfcd5f6bSMarri Devender Rao             }
1259656ec7e3SZbigniew Kurzynski             long certId = getIDFromURL(objectPath);
1260656ec7e3SZbigniew Kurzynski             if (certId < 0)
1261656ec7e3SZbigniew Kurzynski             {
1262002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath;
1263656ec7e3SZbigniew Kurzynski                 messages::internalError(asyncResp->res);
1264656ec7e3SZbigniew Kurzynski                 return;
1265656ec7e3SZbigniew Kurzynski             }
12660fda0f12SGeorge Liu             std::string certURL =
12670fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1268cfcd5f6bSMarri Devender Rao                 std::to_string(certId);
1269656ec7e3SZbigniew Kurzynski 
1270002d39b4SEd Tanous             getCertificateProperties(asyncResp, objectPath,
1271002d39b4SEd Tanous                                      certs::authorityServiceName, certId,
1272002d39b4SEd Tanous                                      certURL, "TrustStore Certificate");
12730fda0f12SGeorge Liu             BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1274cfcd5f6bSMarri Devender Rao                              << certFile->getCertFilePath();
1275cfcd5f6bSMarri Devender Rao             },
1276cfcd5f6bSMarri Devender Rao             certs::authorityServiceName, certs::authorityObjectPath,
12770fda0f12SGeorge Liu             certs::certInstallIntf, "Install", certFile->getCertFilePath());
12787e860f15SJohn Edward Broadbent         });
12797e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificateCollection
1280cfcd5f6bSMarri Devender Rao 
1281cfcd5f6bSMarri Devender Rao /**
1282cfcd5f6bSMarri Devender Rao  * Certificate resource describes a certificate used to prove the identity
1283cfcd5f6bSMarri Devender Rao  * of a component, account or service.
1284cfcd5f6bSMarri Devender Rao  */
12857e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificate(App& app)
1286cfcd5f6bSMarri Devender Rao {
12877e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1288ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
12897e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
129045ca1b86SEd Tanous             [&app](const crow::Request& req,
12917e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12927e860f15SJohn Edward Broadbent                    const std::string&) {
12933ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
129445ca1b86SEd Tanous         {
129545ca1b86SEd Tanous             return;
129645ca1b86SEd Tanous         }
1297cfcd5f6bSMarri Devender Rao         long id = getIDFromURL(req.url);
1298cfcd5f6bSMarri Devender Rao         if (id < 0)
1299cfcd5f6bSMarri Devender Rao         {
1300cfcd5f6bSMarri Devender Rao             BMCWEB_LOG_ERROR << "Invalid url value" << req.url;
1301cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1302cfcd5f6bSMarri Devender Rao             return;
1303cfcd5f6bSMarri Devender Rao         }
1304cfcd5f6bSMarri Devender Rao         BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID="
1305cfcd5f6bSMarri Devender Rao                          << std::to_string(id);
1306cfcd5f6bSMarri Devender Rao         std::string certURL =
1307cfcd5f6bSMarri Devender Rao             "/redfish/v1/Managers/bmc/Truststore/Certificates/" +
1308cfcd5f6bSMarri Devender Rao             std::to_string(id);
1309cfcd5f6bSMarri Devender Rao         std::string objectPath = certs::authorityObjectPath;
1310cfcd5f6bSMarri Devender Rao         objectPath += "/";
1311cfcd5f6bSMarri Devender Rao         objectPath += std::to_string(id);
1312cfcd5f6bSMarri Devender Rao         getCertificateProperties(asyncResp, objectPath,
1313002d39b4SEd Tanous                                  certs::authorityServiceName, id, certURL,
1314002d39b4SEd Tanous                                  "TrustStore Certificate");
13157e860f15SJohn Edward Broadbent         });
131607a60299SZbigniew Kurzynski 
13177e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1318ed398213SEd Tanous         .privileges(redfish::privileges::deleteCertificate)
13197e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
132045ca1b86SEd Tanous             [&app](const crow::Request& req,
13217e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
13227e860f15SJohn Edward Broadbent                    const std::string& param) {
13233ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
132445ca1b86SEd Tanous         {
132545ca1b86SEd Tanous             return;
132645ca1b86SEd Tanous         }
13277e860f15SJohn Edward Broadbent         if (param.empty())
132807a60299SZbigniew Kurzynski         {
132907a60299SZbigniew Kurzynski             messages::internalError(asyncResp->res);
133007a60299SZbigniew Kurzynski             return;
133107a60299SZbigniew Kurzynski         }
133207a60299SZbigniew Kurzynski 
133307a60299SZbigniew Kurzynski         long id = getIDFromURL(req.url);
133407a60299SZbigniew Kurzynski         if (id < 0)
133507a60299SZbigniew Kurzynski         {
133607a60299SZbigniew Kurzynski             BMCWEB_LOG_ERROR << "Invalid url value: " << req.url;
1337002d39b4SEd Tanous             messages::resourceNotFound(asyncResp->res, "TrustStore Certificate",
133807a60299SZbigniew Kurzynski                                        std::string(req.url));
133907a60299SZbigniew Kurzynski             return;
134007a60299SZbigniew Kurzynski         }
134107a60299SZbigniew Kurzynski         BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID="
134207a60299SZbigniew Kurzynski                          << std::to_string(id);
134307a60299SZbigniew Kurzynski         std::string certPath = certs::authorityObjectPath;
134407a60299SZbigniew Kurzynski         certPath += "/";
134507a60299SZbigniew Kurzynski         certPath += std::to_string(id);
134607a60299SZbigniew Kurzynski 
134707a60299SZbigniew Kurzynski         crow::connections::systemBus->async_method_call(
134807a60299SZbigniew Kurzynski             [asyncResp, id](const boost::system::error_code ec) {
134907a60299SZbigniew Kurzynski             if (ec)
135007a60299SZbigniew Kurzynski             {
135107a60299SZbigniew Kurzynski                 messages::resourceNotFound(asyncResp->res,
135207a60299SZbigniew Kurzynski                                            "TrustStore Certificate",
135307a60299SZbigniew Kurzynski                                            std::to_string(id));
135407a60299SZbigniew Kurzynski                 return;
135507a60299SZbigniew Kurzynski             }
135607a60299SZbigniew Kurzynski             BMCWEB_LOG_INFO << "Certificate deleted";
1357002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::no_content);
135807a60299SZbigniew Kurzynski             },
135907a60299SZbigniew Kurzynski             certs::authorityServiceName, certPath, certs::objDeleteIntf,
136007a60299SZbigniew Kurzynski             "Delete");
13617e860f15SJohn Edward Broadbent         });
13627e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
13635968caeeSMarri Devender Rao } // namespace redfish
1364