xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 3ccb3adb9a14783f6bef601506de9f8bcae22d51)
15968caeeSMarri Devender Rao #pragma once
25968caeeSMarri Devender Rao 
3*3ccb3adbSEd Tanous #include "app.hpp"
4*3ccb3adbSEd Tanous #include "async_resp.hpp"
57a1dbc48SGeorge Liu #include "dbus_utility.hpp"
6*3ccb3adbSEd Tanous #include "http_response.hpp"
7*3ccb3adbSEd Tanous #include "query.hpp"
8*3ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
99b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp"
10*3ccb3adbSEd Tanous #include "utils/json_utils.hpp"
11*3ccb3adbSEd Tanous #include "utils/time_utils.hpp"
129b12d1f9SKrzysztof Grobelny 
1390d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp>
149b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
15*3ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
169b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
171214b7e7SGunnar Mills 
187a1dbc48SGeorge Liu #include <array>
19*3ccb3adbSEd Tanous #include <memory>
207a1dbc48SGeorge Liu #include <string_view>
217a1dbc48SGeorge Liu 
225968caeeSMarri Devender Rao namespace redfish
235968caeeSMarri Devender Rao {
245968caeeSMarri Devender Rao namespace certs
255968caeeSMarri Devender Rao {
265968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
275968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
2807a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
295968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
305968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
315968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
3237cce918SMarri Devender Rao constexpr char const* httpsServiceName =
3337cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
3437cce918SMarri Devender Rao constexpr char const* ldapServiceName =
3537cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
36cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
37cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
38c6a8dfb1SJiaqing Zhao constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
39c6a8dfb1SJiaqing Zhao constexpr char const* httpsObjectPath =
40c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
41c6a8dfb1SJiaqing Zhao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
42cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
43cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
445968caeeSMarri Devender Rao } // namespace certs
455968caeeSMarri Devender Rao 
465968caeeSMarri Devender Rao /**
475968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
485968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
495968caeeSMarri Devender Rao  * are installed.
505968caeeSMarri Devender Rao  */
517e860f15SJohn Edward Broadbent 
528d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
538d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5458eb238fSKowalski, Kamil     const crow::Request& req)
5558eb238fSKowalski, Kamil {
5658eb238fSKowalski, Kamil     nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
5758eb238fSKowalski, Kamil 
5858eb238fSKowalski, Kamil     if (reqJson.is_discarded())
5958eb238fSKowalski, Kamil     {
6058eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
6158eb238fSKowalski, Kamil         return req.body;
6258eb238fSKowalski, Kamil     }
6358eb238fSKowalski, Kamil 
6458eb238fSKowalski, Kamil     std::string certificate;
6558eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
6658eb238fSKowalski, Kamil 
6715ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
6815ed6780SWilly Tu                                   certificate, "CertificateType",
6915ed6780SWilly Tu                                   certificateType))
7058eb238fSKowalski, Kamil     {
7158eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
7258eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
73abb93cddSEd Tanous         return {};
7458eb238fSKowalski, Kamil     }
7558eb238fSKowalski, Kamil 
7658eb238fSKowalski, Kamil     if (*certificateType != "PEM")
7758eb238fSKowalski, Kamil     {
7858eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
7958eb238fSKowalski, Kamil                                          "CertificateType");
80abb93cddSEd Tanous         return {};
8158eb238fSKowalski, Kamil     }
8258eb238fSKowalski, Kamil 
8358eb238fSKowalski, Kamil     return certificate;
8458eb238fSKowalski, Kamil }
8558eb238fSKowalski, Kamil 
865968caeeSMarri Devender Rao /**
875968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
885968caeeSMarri Devender Rao  */
895968caeeSMarri Devender Rao class CertificateFile
905968caeeSMarri Devender Rao {
915968caeeSMarri Devender Rao   public:
925968caeeSMarri Devender Rao     CertificateFile() = delete;
935968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
945968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
955968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
965968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
974e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
985968caeeSMarri Devender Rao     {
9972d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1005207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1015207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1025207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
103e662eae8SEd Tanous         if (tempDirectory != nullptr)
1045968caeeSMarri Devender Rao         {
1055968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1065968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1075968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1085968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1095968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1105968caeeSMarri Devender Rao             out << certString;
1115968caeeSMarri Devender Rao             out.close();
1128cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Creating certificate file"
1138cc8edecSEd Tanous                              << certificateFile.string();
1145968caeeSMarri Devender Rao         }
1155968caeeSMarri Devender Rao     }
1165968caeeSMarri Devender Rao     ~CertificateFile()
1175968caeeSMarri Devender Rao     {
1185968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1195968caeeSMarri Devender Rao         {
1208cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Removing certificate file"
1218cc8edecSEd Tanous                              << certificateFile.string();
12223a21a1cSEd Tanous             std::error_code ec;
12323a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
12423a21a1cSEd Tanous             if (ec)
1255968caeeSMarri Devender Rao             {
1265968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1278cc8edecSEd Tanous                                  << certDirectory.string();
1285968caeeSMarri Devender Rao             }
1295968caeeSMarri Devender Rao         }
1305968caeeSMarri Devender Rao     }
1315968caeeSMarri Devender Rao     std::string getCertFilePath()
1325968caeeSMarri Devender Rao     {
1335968caeeSMarri Devender Rao         return certificateFile;
1345968caeeSMarri Devender Rao     }
1355968caeeSMarri Devender Rao 
1365968caeeSMarri Devender Rao   private:
1375968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1385968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1395968caeeSMarri Devender Rao };
1405968caeeSMarri Devender Rao 
1415968caeeSMarri Devender Rao /**
1424e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1435968caeeSMarri Devender Rao  *
1445968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1455968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1465968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1475968caeeSMarri Devender Rao  * @return None
1485968caeeSMarri Devender Rao  */
1495968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
1505968caeeSMarri Devender Rao                                       const std::string_view value)
1515968caeeSMarri Devender Rao {
1525968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1535968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1545968caeeSMarri Devender Rao     while (i != value.end())
1555968caeeSMarri Devender Rao     {
1565968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1575968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1585968caeeSMarri Devender Rao         {
15917a897dfSManojkiran Eda             ++i;
1605968caeeSMarri Devender Rao         }
1615968caeeSMarri Devender Rao         if (i == value.end())
1625968caeeSMarri Devender Rao         {
1635968caeeSMarri Devender Rao             break;
1645968caeeSMarri Devender Rao         }
165271584abSEd Tanous         const std::string_view key(tokenBegin,
166271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
16717a897dfSManojkiran Eda         ++i;
1685968caeeSMarri Devender Rao         tokenBegin = i;
1695968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
1705968caeeSMarri Devender Rao         {
17117a897dfSManojkiran Eda             ++i;
1725968caeeSMarri Devender Rao         }
173271584abSEd Tanous         const std::string_view val(tokenBegin,
174271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
1755968caeeSMarri Devender Rao         if (key == "L")
1765968caeeSMarri Devender Rao         {
1775968caeeSMarri Devender Rao             out["City"] = val;
1785968caeeSMarri Devender Rao         }
1795968caeeSMarri Devender Rao         else if (key == "CN")
1805968caeeSMarri Devender Rao         {
1815968caeeSMarri Devender Rao             out["CommonName"] = val;
1825968caeeSMarri Devender Rao         }
1835968caeeSMarri Devender Rao         else if (key == "C")
1845968caeeSMarri Devender Rao         {
1855968caeeSMarri Devender Rao             out["Country"] = val;
1865968caeeSMarri Devender Rao         }
1875968caeeSMarri Devender Rao         else if (key == "O")
1885968caeeSMarri Devender Rao         {
1895968caeeSMarri Devender Rao             out["Organization"] = val;
1905968caeeSMarri Devender Rao         }
1915968caeeSMarri Devender Rao         else if (key == "OU")
1925968caeeSMarri Devender Rao         {
1935968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
1945968caeeSMarri Devender Rao         }
1955968caeeSMarri Devender Rao         else if (key == "ST")
1965968caeeSMarri Devender Rao         {
1975968caeeSMarri Devender Rao             out["State"] = val;
1985968caeeSMarri Devender Rao         }
1995968caeeSMarri Devender Rao         // skip comma character
2005968caeeSMarri Devender Rao         if (i != value.end())
2015968caeeSMarri Devender Rao         {
20217a897dfSManojkiran Eda             ++i;
2035968caeeSMarri Devender Rao         }
2045968caeeSMarri Devender Rao     }
2055968caeeSMarri Devender Rao }
2065968caeeSMarri Devender Rao 
2075968caeeSMarri Devender Rao /**
208d3f92ce7SJiaqing Zhao  * @brief Retrieve the installed certificate list
209d3f92ce7SJiaqing Zhao  *
210d3f92ce7SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
211d3f92ce7SJiaqing Zhao  * @param[in] basePath DBus object path to search
212d3f92ce7SJiaqing Zhao  * @param[in] listPtr Json pointer to the list in asyncResp
213d3f92ce7SJiaqing Zhao  * @param[in] countPtr Json pointer to the count in asyncResp
214d3f92ce7SJiaqing Zhao  * @return None
215d3f92ce7SJiaqing Zhao  */
216d3f92ce7SJiaqing Zhao static void
217d3f92ce7SJiaqing Zhao     getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218d3f92ce7SJiaqing Zhao                        const std::string& basePath,
219d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& listPtr,
220d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& countPtr)
221d3f92ce7SJiaqing Zhao {
2227a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2237a1dbc48SGeorge Liu         certs::certPropIntf};
2247a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
2257a1dbc48SGeorge Liu         basePath, 0, interfaces,
226d3f92ce7SJiaqing Zhao         [asyncResp, listPtr, countPtr](
2277a1dbc48SGeorge Liu             const boost::system::error_code& ec,
228d3f92ce7SJiaqing Zhao             const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
229d3f92ce7SJiaqing Zhao         if (ec)
230d3f92ce7SJiaqing Zhao         {
231d3f92ce7SJiaqing Zhao             BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
232d3f92ce7SJiaqing Zhao             messages::internalError(asyncResp->res);
233d3f92ce7SJiaqing Zhao             return;
234d3f92ce7SJiaqing Zhao         }
235d3f92ce7SJiaqing Zhao 
236d3f92ce7SJiaqing Zhao         nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
237d3f92ce7SJiaqing Zhao         links = nlohmann::json::array();
238d3f92ce7SJiaqing Zhao         for (const auto& certPath : certPaths)
239d3f92ce7SJiaqing Zhao         {
240d3f92ce7SJiaqing Zhao             sdbusplus::message::object_path objPath(certPath);
241d3f92ce7SJiaqing Zhao             std::string certId = objPath.filename();
242d3f92ce7SJiaqing Zhao             if (certId.empty())
243d3f92ce7SJiaqing Zhao             {
244d3f92ce7SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
245d3f92ce7SJiaqing Zhao                 continue;
246d3f92ce7SJiaqing Zhao             }
247d3f92ce7SJiaqing Zhao 
248d3f92ce7SJiaqing Zhao             boost::urls::url certURL;
249d3f92ce7SJiaqing Zhao             if (objPath.parent_path() == certs::httpsObjectPath)
250d3f92ce7SJiaqing Zhao             {
251d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
252d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
253d3f92ce7SJiaqing Zhao                     "HTTPS", "Certificates", certId);
254d3f92ce7SJiaqing Zhao             }
255d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::ldapObjectPath)
256d3f92ce7SJiaqing Zhao             {
257d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces("redfish", "v1",
258d3f92ce7SJiaqing Zhao                                                        "AccountService", "LDAP",
259d3f92ce7SJiaqing Zhao                                                        "Certificates", certId);
260d3f92ce7SJiaqing Zhao             }
261d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::authorityObjectPath)
262d3f92ce7SJiaqing Zhao             {
263d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
264d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "Truststore",
265d3f92ce7SJiaqing Zhao                     "Certificates", certId);
266d3f92ce7SJiaqing Zhao             }
267d3f92ce7SJiaqing Zhao             else
268d3f92ce7SJiaqing Zhao             {
269d3f92ce7SJiaqing Zhao                 continue;
270d3f92ce7SJiaqing Zhao             }
271d3f92ce7SJiaqing Zhao 
272d3f92ce7SJiaqing Zhao             nlohmann::json::object_t link;
273d3f92ce7SJiaqing Zhao             link["@odata.id"] = certURL;
274d3f92ce7SJiaqing Zhao             links.emplace_back(std::move(link));
275d3f92ce7SJiaqing Zhao         }
276d3f92ce7SJiaqing Zhao 
277d3f92ce7SJiaqing Zhao         asyncResp->res.jsonValue[countPtr] = links.size();
2787a1dbc48SGeorge Liu         });
279d3f92ce7SJiaqing Zhao }
280d3f92ce7SJiaqing Zhao 
281d3f92ce7SJiaqing Zhao /**
2825968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
2835968caeeSMarri Devender Rao  * message
2845968caeeSMarri Devender Rao  *
2855968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
2865968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
2875968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
2885968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
2895968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
2905968caeeSMarri Devender Rao  * @return None
2915968caeeSMarri Devender Rao  */
2925968caeeSMarri Devender Rao static void getCertificateProperties(
2938d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
294e19e97e2SJiaqing Zhao     const std::string& objectPath, const std::string& service,
2951e312598SJiaqing Zhao     const std::string& certId, const boost::urls::url& certURL,
296e19e97e2SJiaqing Zhao     const std::string& name)
2975968caeeSMarri Devender Rao {
2985968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
2995968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
3009b12d1f9SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
3019b12d1f9SKrzysztof Grobelny         *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
302b9d36b47SEd Tanous         [asyncResp, certURL, certId,
303b9d36b47SEd Tanous          name](const boost::system::error_code ec,
304b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
3055968caeeSMarri Devender Rao         if (ec)
3065968caeeSMarri Devender Rao         {
3075968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
308d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", certId);
3095968caeeSMarri Devender Rao             return;
3105968caeeSMarri Devender Rao         }
3119b12d1f9SKrzysztof Grobelny 
3129b12d1f9SKrzysztof Grobelny         const std::string* certificateString = nullptr;
3139b12d1f9SKrzysztof Grobelny         const std::vector<std::string>* keyUsage = nullptr;
3149b12d1f9SKrzysztof Grobelny         const std::string* issuer = nullptr;
3159b12d1f9SKrzysztof Grobelny         const std::string* subject = nullptr;
3169b12d1f9SKrzysztof Grobelny         const uint64_t* validNotAfter = nullptr;
3179b12d1f9SKrzysztof Grobelny         const uint64_t* validNotBefore = nullptr;
3189b12d1f9SKrzysztof Grobelny 
3199b12d1f9SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
3209b12d1f9SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "CertificateString",
3219b12d1f9SKrzysztof Grobelny             certificateString, "KeyUsage", keyUsage, "Issuer", issuer,
3229b12d1f9SKrzysztof Grobelny             "Subject", subject, "ValidNotAfter", validNotAfter,
3239b12d1f9SKrzysztof Grobelny             "ValidNotBefore", validNotBefore);
3249b12d1f9SKrzysztof Grobelny 
3259b12d1f9SKrzysztof Grobelny         if (!success)
3269b12d1f9SKrzysztof Grobelny         {
3279b12d1f9SKrzysztof Grobelny             messages::internalError(asyncResp->res);
3289b12d1f9SKrzysztof Grobelny             return;
3299b12d1f9SKrzysztof Grobelny         }
3309b12d1f9SKrzysztof Grobelny 
3311476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = certURL;
3321476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
3331476687dSEd Tanous             "#Certificate.v1_0_0.Certificate";
334e19e97e2SJiaqing Zhao         asyncResp->res.jsonValue["Id"] = certId;
3351476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = name;
3361476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = name;
3375968caeeSMarri Devender Rao         asyncResp->res.jsonValue["CertificateString"] = "";
3389b12d1f9SKrzysztof Grobelny         asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
3399b12d1f9SKrzysztof Grobelny 
3409b12d1f9SKrzysztof Grobelny         if (certificateString != nullptr)
3415968caeeSMarri Devender Rao         {
3429b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["CertificateString"] = *certificateString;
3435968caeeSMarri Devender Rao         }
3449b12d1f9SKrzysztof Grobelny 
3459b12d1f9SKrzysztof Grobelny         if (keyUsage != nullptr)
3465968caeeSMarri Devender Rao         {
3479b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
3485968caeeSMarri Devender Rao         }
3499b12d1f9SKrzysztof Grobelny 
3509b12d1f9SKrzysztof Grobelny         if (issuer != nullptr)
3515968caeeSMarri Devender Rao         {
3529b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
3539b12d1f9SKrzysztof Grobelny                                       *issuer);
3545968caeeSMarri Devender Rao         }
3559b12d1f9SKrzysztof Grobelny 
3569b12d1f9SKrzysztof Grobelny         if (subject != nullptr)
3575968caeeSMarri Devender Rao         {
3589b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
3599b12d1f9SKrzysztof Grobelny                                       *subject);
3605968caeeSMarri Devender Rao         }
3619b12d1f9SKrzysztof Grobelny 
3629b12d1f9SKrzysztof Grobelny         if (validNotAfter != nullptr)
3635968caeeSMarri Devender Rao         {
3645968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotAfter"] =
3659b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotAfter);
3665968caeeSMarri Devender Rao         }
3679b12d1f9SKrzysztof Grobelny 
3689b12d1f9SKrzysztof Grobelny         if (validNotBefore != nullptr)
3695968caeeSMarri Devender Rao         {
3705968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotBefore"] =
3719b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotBefore);
3725968caeeSMarri Devender Rao         }
3739b12d1f9SKrzysztof Grobelny 
3741e312598SJiaqing Zhao         asyncResp->res.addHeader(
375d9f6c621SEd Tanous             boost::beast::http::field::location,
376d9f6c621SEd Tanous             std::string_view(certURL.data(), certURL.size()));
3779b12d1f9SKrzysztof Grobelny         });
3785968caeeSMarri Devender Rao }
3795968caeeSMarri Devender Rao 
3807a3a8f7aSJiaqing Zhao static void
3817a3a8f7aSJiaqing Zhao     deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3827a3a8f7aSJiaqing Zhao                       const std::string& service,
3837a3a8f7aSJiaqing Zhao                       const sdbusplus::message::object_path& objectPath)
3847a3a8f7aSJiaqing Zhao {
3857a3a8f7aSJiaqing Zhao     crow::connections::systemBus->async_method_call(
3867a3a8f7aSJiaqing Zhao         [asyncResp,
3877a3a8f7aSJiaqing Zhao          id{objectPath.filename()}](const boost::system::error_code ec) {
3887a3a8f7aSJiaqing Zhao         if (ec)
3897a3a8f7aSJiaqing Zhao         {
3907a3a8f7aSJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", id);
3917a3a8f7aSJiaqing Zhao             return;
3927a3a8f7aSJiaqing Zhao         }
3937a3a8f7aSJiaqing Zhao         BMCWEB_LOG_INFO << "Certificate deleted";
3947a3a8f7aSJiaqing Zhao         asyncResp->res.result(boost::beast::http::status::no_content);
3957a3a8f7aSJiaqing Zhao         },
3967a3a8f7aSJiaqing Zhao         service, objectPath, certs::objDeleteIntf, "Delete");
3977a3a8f7aSJiaqing Zhao }
3987a3a8f7aSJiaqing Zhao 
399828252d5SJiaqing Zhao inline void handleCertificateServiceGet(
400828252d5SJiaqing Zhao     App& app, const crow::Request& req,
401828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4025968caeeSMarri Devender Rao {
403828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
404828252d5SJiaqing Zhao     {
405828252d5SJiaqing Zhao         return;
406828252d5SJiaqing Zhao     }
407828252d5SJiaqing Zhao 
408828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
409828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
410828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
411828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
412828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
413828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
414828252d5SJiaqing Zhao         "Actions available to manage certificates";
415828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
416828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
417828252d5SJiaqing Zhao     // has permissions ConfigureManager
418828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
419828252d5SJiaqing Zhao         redfish::getUserPrivileges(req.userRole);
420828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
421828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
422828252d5SJiaqing Zhao     {
423828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
424828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
425828252d5SJiaqing Zhao     }
426828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
427828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
428828252d5SJiaqing Zhao     replace["target"] =
429828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
430828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
431828252d5SJiaqing Zhao     allowed.push_back("PEM");
432828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
433828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
434828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
435828252d5SJiaqing Zhao }
436828252d5SJiaqing Zhao 
437828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
438828252d5SJiaqing Zhao     App& app, const crow::Request& req,
439828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
440828252d5SJiaqing Zhao {
441828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
442828252d5SJiaqing Zhao     {
443828252d5SJiaqing Zhao         return;
444828252d5SJiaqing Zhao     }
445828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
446828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
447828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
448828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
449828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
450828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
451828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
452828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
453828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
454828252d5SJiaqing Zhao 
455828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
456828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
457828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
458828252d5SJiaqing Zhao }
459828252d5SJiaqing Zhao 
460828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
461828252d5SJiaqing Zhao     App& app, const crow::Request& req,
462828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
463828252d5SJiaqing Zhao {
4643ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
46545ca1b86SEd Tanous     {
46645ca1b86SEd Tanous         return;
46745ca1b86SEd Tanous     }
4685968caeeSMarri Devender Rao     std::string certificate;
4695968caeeSMarri Devender Rao     nlohmann::json certificateUri;
4705968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
4718d1b46d7Szhanghch05 
472002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
473002d39b4SEd Tanous                                    certificate, "CertificateUri",
474002d39b4SEd Tanous                                    certificateUri, "CertificateType",
475002d39b4SEd Tanous                                    certificateType))
4765968caeeSMarri Devender Rao     {
4775968caeeSMarri Devender Rao         BMCWEB_LOG_ERROR << "Required parameters are missing";
4785968caeeSMarri Devender Rao         messages::internalError(asyncResp->res);
4795968caeeSMarri Devender Rao         return;
4805968caeeSMarri Devender Rao     }
4815968caeeSMarri Devender Rao 
4825968caeeSMarri Devender Rao     if (!certificateType)
4835968caeeSMarri Devender Rao     {
4845968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
4855968caeeSMarri Devender Rao         return;
4865968caeeSMarri Devender Rao     }
4875968caeeSMarri Devender Rao     if (certificateType != "PEM")
4885968caeeSMarri Devender Rao     {
489828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
490828252d5SJiaqing Zhao                                               "ReplaceCertificate");
4915968caeeSMarri Devender Rao         return;
4925968caeeSMarri Devender Rao     }
4935968caeeSMarri Devender Rao 
4945968caeeSMarri Devender Rao     std::string certURI;
4955968caeeSMarri Devender Rao     if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
4965968caeeSMarri Devender Rao                                       "@odata.id", certURI))
4975968caeeSMarri Devender Rao     {
498828252d5SJiaqing Zhao         messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
499828252d5SJiaqing Zhao                                          "CertificateUri");
5005968caeeSMarri Devender Rao         return;
5015968caeeSMarri Devender Rao     }
50275b63a2cSJiaqing Zhao     BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI;
5035968caeeSMarri Devender Rao 
50475b63a2cSJiaqing Zhao     boost::urls::result<boost::urls::url_view> parsedUrl =
50575b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
50675b63a2cSJiaqing Zhao     if (!parsedUrl)
5075968caeeSMarri Devender Rao     {
508828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
509828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
5105968caeeSMarri Devender Rao         return;
5115968caeeSMarri Devender Rao     }
51275b63a2cSJiaqing Zhao 
51375b63a2cSJiaqing Zhao     std::string id;
51475b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
5155968caeeSMarri Devender Rao     std::string name;
51637cce918SMarri Devender Rao     std::string service;
517828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
518828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
519828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5205968caeeSMarri Devender Rao     {
521002d39b4SEd Tanous         objectPath =
52275b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::httpsObjectPath) / id;
5235968caeeSMarri Devender Rao         name = "HTTPS certificate";
52437cce918SMarri Devender Rao         service = certs::httpsServiceName;
52537cce918SMarri Devender Rao     }
52675b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
52775b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
52875b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
52937cce918SMarri Devender Rao     {
530002d39b4SEd Tanous         objectPath =
53175b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::ldapObjectPath) / id;
53237cce918SMarri Devender Rao         name = "LDAP certificate";
53337cce918SMarri Devender Rao         service = certs::ldapServiceName;
5345968caeeSMarri Devender Rao     }
53575b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
53675b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
53775b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
538cfcd5f6bSMarri Devender Rao     {
53975b63a2cSJiaqing Zhao         objectPath =
540828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
541cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
542cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
543cfcd5f6bSMarri Devender Rao     }
5445968caeeSMarri Devender Rao     else
5455968caeeSMarri Devender Rao     {
546828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
547828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5485968caeeSMarri Devender Rao         return;
5495968caeeSMarri Devender Rao     }
5505968caeeSMarri Devender Rao 
5515968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
5525968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
5535968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
5541e312598SJiaqing Zhao         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
5555968caeeSMarri Devender Rao          name](const boost::system::error_code ec) {
5565968caeeSMarri Devender Rao         if (ec)
5575968caeeSMarri Devender Rao         {
5585968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
55990d2d1e8SJiaqing Zhao             if (ec.value() ==
56090d2d1e8SJiaqing Zhao                 boost::system::linux_error::bad_request_descriptor)
56190d2d1e8SJiaqing Zhao             {
562828252d5SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
5635968caeeSMarri Devender Rao                 return;
5645968caeeSMarri Devender Rao             }
56590d2d1e8SJiaqing Zhao             messages::internalError(asyncResp->res);
56690d2d1e8SJiaqing Zhao             return;
56790d2d1e8SJiaqing Zhao         }
568828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, service, id, url, name);
5695968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
5705968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
5715968caeeSMarri Devender Rao         },
5725968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
5735968caeeSMarri Devender Rao         certFile->getCertFilePath());
574828252d5SJiaqing Zhao }
5755968caeeSMarri Devender Rao 
576cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
577828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
5785968caeeSMarri Devender Rao /**
579828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
580828252d5SJiaqing Zhao  *
581828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
582828252d5SJiaqing Zhao  * @param[in] certURI Link to certifiate collection URI
583828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
584828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
585828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
586828252d5SJiaqing Zhao  * @return None
5875968caeeSMarri Devender Rao  */
588828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
589828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
590828252d5SJiaqing Zhao                    const std::string& certObjPath,
591828252d5SJiaqing Zhao                    const std::string& csrObjPath)
5925968caeeSMarri Devender Rao {
593828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
594828252d5SJiaqing Zhao                      << " CSRObjectPath=" << csrObjPath
595828252d5SJiaqing Zhao                      << " service=" << service;
596828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
597828252d5SJiaqing Zhao         [asyncResp, certURI](const boost::system::error_code ec,
598828252d5SJiaqing Zhao                              const std::string& csr) {
599828252d5SJiaqing Zhao         if (ec)
600828252d5SJiaqing Zhao         {
601828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
602828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
603828252d5SJiaqing Zhao             return;
604828252d5SJiaqing Zhao         }
605828252d5SJiaqing Zhao         if (csr.empty())
606828252d5SJiaqing Zhao         {
607828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "CSR read is empty";
608828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
609828252d5SJiaqing Zhao             return;
610828252d5SJiaqing Zhao         }
611828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CSRString"] = csr;
612828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
613828252d5SJiaqing Zhao             certURI;
614828252d5SJiaqing Zhao         },
615828252d5SJiaqing Zhao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
616828252d5SJiaqing Zhao }
617828252d5SJiaqing Zhao 
618828252d5SJiaqing Zhao inline void
619828252d5SJiaqing Zhao     handleGenerateCSRAction(App& app, const crow::Request& req,
620828252d5SJiaqing Zhao                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
621828252d5SJiaqing Zhao {
6223ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
62345ca1b86SEd Tanous     {
62445ca1b86SEd Tanous         return;
62545ca1b86SEd Tanous     }
626828252d5SJiaqing Zhao     static const int rsaKeyBitLength = 2048;
6275968caeeSMarri Devender Rao 
628828252d5SJiaqing Zhao     // Required parameters
629828252d5SJiaqing Zhao     std::string city;
630828252d5SJiaqing Zhao     std::string commonName;
631828252d5SJiaqing Zhao     std::string country;
632828252d5SJiaqing Zhao     std::string organization;
633828252d5SJiaqing Zhao     std::string organizationalUnit;
634828252d5SJiaqing Zhao     std::string state;
635828252d5SJiaqing Zhao     nlohmann::json certificateCollection;
636828252d5SJiaqing Zhao 
637828252d5SJiaqing Zhao     // Optional parameters
638828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optAlternativeNames =
639828252d5SJiaqing Zhao         std::vector<std::string>();
640828252d5SJiaqing Zhao     std::optional<std::string> optContactPerson = "";
641828252d5SJiaqing Zhao     std::optional<std::string> optChallengePassword = "";
642828252d5SJiaqing Zhao     std::optional<std::string> optEmail = "";
643828252d5SJiaqing Zhao     std::optional<std::string> optGivenName = "";
644828252d5SJiaqing Zhao     std::optional<std::string> optInitials = "";
645828252d5SJiaqing Zhao     std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
646828252d5SJiaqing Zhao     std::optional<std::string> optKeyCurveId = "secp384r1";
647828252d5SJiaqing Zhao     std::optional<std::string> optKeyPairAlgorithm = "EC";
648828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optKeyUsage =
649828252d5SJiaqing Zhao         std::vector<std::string>();
650828252d5SJiaqing Zhao     std::optional<std::string> optSurname = "";
651828252d5SJiaqing Zhao     std::optional<std::string> optUnstructuredName = "";
652828252d5SJiaqing Zhao     if (!json_util::readJsonAction(
653828252d5SJiaqing Zhao             req, asyncResp->res, "City", city, "CommonName", commonName,
654828252d5SJiaqing Zhao             "ContactPerson", optContactPerson, "Country", country,
655828252d5SJiaqing Zhao             "Organization", organization, "OrganizationalUnit",
656828252d5SJiaqing Zhao             organizationalUnit, "State", state, "CertificateCollection",
657828252d5SJiaqing Zhao             certificateCollection, "AlternativeNames", optAlternativeNames,
658828252d5SJiaqing Zhao             "ChallengePassword", optChallengePassword, "Email", optEmail,
659828252d5SJiaqing Zhao             "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
660828252d5SJiaqing Zhao             optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
661828252d5SJiaqing Zhao             optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
662828252d5SJiaqing Zhao             "UnstructuredName", optUnstructuredName))
663828252d5SJiaqing Zhao     {
664828252d5SJiaqing Zhao         return;
6655968caeeSMarri Devender Rao     }
6665968caeeSMarri Devender Rao 
667828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
668828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
669828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
670828252d5SJiaqing Zhao     // value
671828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
6725968caeeSMarri Devender Rao     {
673828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
674828252d5SJiaqing Zhao                                               "ChallengePassword");
675828252d5SJiaqing Zhao         return;
676828252d5SJiaqing Zhao     }
677828252d5SJiaqing Zhao 
678828252d5SJiaqing Zhao     std::string certURI;
679828252d5SJiaqing Zhao     if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
680828252d5SJiaqing Zhao                                       "@odata.id", certURI))
681828252d5SJiaqing Zhao     {
682828252d5SJiaqing Zhao         return;
683828252d5SJiaqing Zhao     }
684828252d5SJiaqing Zhao 
685828252d5SJiaqing Zhao     std::string objectPath;
686828252d5SJiaqing Zhao     std::string service;
687828252d5SJiaqing Zhao     if (certURI.starts_with(
688828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
689828252d5SJiaqing Zhao     {
690828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
691828252d5SJiaqing Zhao         service = certs::httpsServiceName;
692828252d5SJiaqing Zhao     }
693828252d5SJiaqing Zhao     else if (certURI.starts_with(
694828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
695828252d5SJiaqing Zhao     {
696828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
697828252d5SJiaqing Zhao         service = certs::ldapServiceName;
698828252d5SJiaqing Zhao     }
699828252d5SJiaqing Zhao     else
700828252d5SJiaqing Zhao     {
701828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
702828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
703828252d5SJiaqing Zhao         return;
704828252d5SJiaqing Zhao     }
705828252d5SJiaqing Zhao 
706828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
707828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
708828252d5SJiaqing Zhao     {
709828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
710828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
711828252d5SJiaqing Zhao         return;
712828252d5SJiaqing Zhao     }
713828252d5SJiaqing Zhao 
714828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
715828252d5SJiaqing Zhao     // time consumed in generating private key
716828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
717828252d5SJiaqing Zhao     {
718828252d5SJiaqing Zhao         messages::propertyValueNotInList(
719828252d5SJiaqing Zhao             asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength");
720828252d5SJiaqing Zhao         return;
721828252d5SJiaqing Zhao     }
722828252d5SJiaqing Zhao 
723828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
724828252d5SJiaqing Zhao     if (certURI.starts_with(
725828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
726828252d5SJiaqing Zhao     {
727828252d5SJiaqing Zhao         if (optKeyUsage->empty())
728828252d5SJiaqing Zhao         {
729828252d5SJiaqing Zhao             optKeyUsage->push_back("ServerAuthentication");
730828252d5SJiaqing Zhao         }
731828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
732828252d5SJiaqing Zhao         {
733828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
734828252d5SJiaqing Zhao             {
735828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
736828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
737828252d5SJiaqing Zhao                 return;
738828252d5SJiaqing Zhao             }
739828252d5SJiaqing Zhao         }
740828252d5SJiaqing Zhao         else
741828252d5SJiaqing Zhao         {
742828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
743828252d5SJiaqing Zhao                                                   "GenerateCSR");
744828252d5SJiaqing Zhao             return;
745828252d5SJiaqing Zhao         }
746828252d5SJiaqing Zhao     }
747828252d5SJiaqing Zhao     else if (certURI.starts_with(
748828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
749828252d5SJiaqing Zhao     {
750828252d5SJiaqing Zhao         if (optKeyUsage->empty())
751828252d5SJiaqing Zhao         {
752828252d5SJiaqing Zhao             optKeyUsage->push_back("ClientAuthentication");
753828252d5SJiaqing Zhao         }
754828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
755828252d5SJiaqing Zhao         {
756828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
757828252d5SJiaqing Zhao             {
758828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
759828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
760828252d5SJiaqing Zhao                 return;
761828252d5SJiaqing Zhao             }
762828252d5SJiaqing Zhao         }
763828252d5SJiaqing Zhao         else
764828252d5SJiaqing Zhao         {
765828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
766828252d5SJiaqing Zhao                                                   "GenerateCSR");
767828252d5SJiaqing Zhao             return;
768828252d5SJiaqing Zhao         }
769828252d5SJiaqing Zhao     }
770828252d5SJiaqing Zhao 
771828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
772828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
773828252d5SJiaqing Zhao     static const int timeOut = 10;
774828252d5SJiaqing Zhao     if (csrMatcher)
775828252d5SJiaqing Zhao     {
776828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
777828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
778828252d5SJiaqing Zhao         return;
779828252d5SJiaqing Zhao     }
780828252d5SJiaqing Zhao 
781828252d5SJiaqing Zhao     // Make this static so it survives outside this method
782828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
783828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
784828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
785828252d5SJiaqing Zhao         csrMatcher = nullptr;
786828252d5SJiaqing Zhao         if (ec)
787828252d5SJiaqing Zhao         {
788828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
789828252d5SJiaqing Zhao             // before completion.
790828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
791828252d5SJiaqing Zhao             {
792828252d5SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
793828252d5SJiaqing Zhao             }
794828252d5SJiaqing Zhao             return;
795828252d5SJiaqing Zhao         }
796828252d5SJiaqing Zhao         BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
797828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
798828252d5SJiaqing Zhao     });
799828252d5SJiaqing Zhao 
800828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
801828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
802828252d5SJiaqing Zhao     std::string match("type='signal',"
803828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
804828252d5SJiaqing Zhao                       "path='" +
805828252d5SJiaqing Zhao                       objectPath +
806828252d5SJiaqing Zhao                       "',"
807828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
808828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
809828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
810828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
811828252d5SJiaqing Zhao         timeout.cancel();
812828252d5SJiaqing Zhao         if (m.is_method_error())
813828252d5SJiaqing Zhao         {
814828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "Dbus method error!!!";
815828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
816828252d5SJiaqing Zhao             return;
817828252d5SJiaqing Zhao         }
818828252d5SJiaqing Zhao 
819828252d5SJiaqing Zhao         dbus::utility::DBusInteracesMap interfacesProperties;
820828252d5SJiaqing Zhao 
821828252d5SJiaqing Zhao         sdbusplus::message::object_path csrObjectPath;
822828252d5SJiaqing Zhao         m.read(csrObjectPath, interfacesProperties);
823828252d5SJiaqing Zhao         BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
824828252d5SJiaqing Zhao         for (const auto& interface : interfacesProperties)
825828252d5SJiaqing Zhao         {
826828252d5SJiaqing Zhao             if (interface.first == "xyz.openbmc_project.Certs.CSR")
827828252d5SJiaqing Zhao             {
828828252d5SJiaqing Zhao                 getCSR(asyncResp, certURI, service, objectPath,
829828252d5SJiaqing Zhao                        csrObjectPath.str);
830828252d5SJiaqing Zhao                 break;
831828252d5SJiaqing Zhao             }
832828252d5SJiaqing Zhao         }
833828252d5SJiaqing Zhao         });
834828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
835828252d5SJiaqing Zhao         [asyncResp](const boost::system::error_code ec, const std::string&) {
836828252d5SJiaqing Zhao         if (ec)
837828252d5SJiaqing Zhao         {
838828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
839828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
840828252d5SJiaqing Zhao             return;
841828252d5SJiaqing Zhao         }
842828252d5SJiaqing Zhao         },
843828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
844828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
845828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
846828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
847828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
848828252d5SJiaqing Zhao         *optUnstructuredName);
849828252d5SJiaqing Zhao }
850828252d5SJiaqing Zhao 
851828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
852828252d5SJiaqing Zhao {
853828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
854828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
855002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
856828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
857828252d5SJiaqing Zhao 
858828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
859828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
860828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
861828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
862828252d5SJiaqing Zhao 
863828252d5SJiaqing Zhao     BMCWEB_ROUTE(
864828252d5SJiaqing Zhao         app,
865828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
866828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
867828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
868828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
869828252d5SJiaqing Zhao 
870828252d5SJiaqing Zhao     BMCWEB_ROUTE(
871828252d5SJiaqing Zhao         app,
872828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
873828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
874828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
875828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
876828252d5SJiaqing Zhao } // requestRoutesCertificateService
877828252d5SJiaqing Zhao 
878828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
879828252d5SJiaqing Zhao     App& app, const crow::Request& req,
880828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
881828252d5SJiaqing Zhao {
8823ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
88345ca1b86SEd Tanous     {
88445ca1b86SEd Tanous         return;
88545ca1b86SEd Tanous     }
8861476687dSEd Tanous 
8871476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
8881476687dSEd Tanous         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
8891476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
8901476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
8911476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8921476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
8931476687dSEd Tanous         "A Collection of HTTPS certificate instances";
8948d1b46d7Szhanghch05 
895d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
896d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
897d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
898828252d5SJiaqing Zhao }
8995968caeeSMarri Devender Rao 
900828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
901828252d5SJiaqing Zhao     App& app, const crow::Request& req,
902828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
903828252d5SJiaqing Zhao {
9043ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
90545ca1b86SEd Tanous     {
90645ca1b86SEd Tanous         return;
90745ca1b86SEd Tanous     }
9085968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
9098d1b46d7Szhanghch05 
9101476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
9111476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
9125968caeeSMarri Devender Rao 
913002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
91458eb238fSKowalski, Kamil 
91558eb238fSKowalski, Kamil     if (certFileBody.empty())
91658eb238fSKowalski, Kamil     {
9170fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
918a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
91958eb238fSKowalski, Kamil         return;
92058eb238fSKowalski, Kamil     }
92158eb238fSKowalski, Kamil 
9225968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
92358eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
9245968caeeSMarri Devender Rao 
9255968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
926656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
927656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9285968caeeSMarri Devender Rao         if (ec)
9295968caeeSMarri Devender Rao         {
9305968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9315968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
9325968caeeSMarri Devender Rao             return;
9335968caeeSMarri Devender Rao         }
934717b9802SJiaqing Zhao 
935717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
936717b9802SJiaqing Zhao         std::string certId = path.filename();
9371e312598SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
9381e312598SJiaqing Zhao             "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
9391e312598SJiaqing Zhao             "Certificates", certId);
940828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
941828252d5SJiaqing Zhao                                  certId, certURL, "HTTPS Certificate");
9425968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9435968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
9445968caeeSMarri Devender Rao         },
945828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
946828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
947828252d5SJiaqing Zhao }
9485968caeeSMarri Devender Rao 
949828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
950828252d5SJiaqing Zhao     App& app, const crow::Request& req,
951828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
9527e860f15SJohn Edward Broadbent {
9533ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
95445ca1b86SEd Tanous     {
95545ca1b86SEd Tanous         return;
95645ca1b86SEd Tanous     }
9577e860f15SJohn Edward Broadbent 
958828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id;
959828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
960828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
961828252d5SJiaqing Zhao         "Certificates", id);
962828252d5SJiaqing Zhao     std::string objPath =
963828252d5SJiaqing Zhao         sdbusplus::message::object_path(certs::httpsObjectPath) / id;
964828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
965828252d5SJiaqing Zhao                              certURL, "HTTPS Certificate");
9667e860f15SJohn Edward Broadbent }
96737cce918SMarri Devender Rao 
968828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
96937cce918SMarri Devender Rao {
970828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
971828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
972ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
973828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
974828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
975828252d5SJiaqing Zhao 
976828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
977828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
978828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
979828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
980828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
981828252d5SJiaqing Zhao 
982828252d5SJiaqing Zhao     BMCWEB_ROUTE(
983828252d5SJiaqing Zhao         app,
984828252d5SJiaqing Zhao         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
985828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
986002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
987828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
988828252d5SJiaqing Zhao }
989828252d5SJiaqing Zhao 
990828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
991828252d5SJiaqing Zhao     App& app, const crow::Request& req,
992828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
993828252d5SJiaqing Zhao {
9943ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
99545ca1b86SEd Tanous     {
99645ca1b86SEd Tanous         return;
99745ca1b86SEd Tanous     }
9981476687dSEd Tanous 
9991476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
10001476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
10011476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
10021476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
10031476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10041476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
10051476687dSEd Tanous         "A Collection of LDAP certificate instances";
10068d1b46d7Szhanghch05 
1007d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
1008d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1009d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1010828252d5SJiaqing Zhao }
101137cce918SMarri Devender Rao 
1012828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1013828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1014828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1015828252d5SJiaqing Zhao {
10163ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101745ca1b86SEd Tanous     {
101845ca1b86SEd Tanous         return;
101945ca1b86SEd Tanous     }
1020002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
102158eb238fSKowalski, Kamil 
102258eb238fSKowalski, Kamil     if (certFileBody.empty())
102358eb238fSKowalski, Kamil     {
1024002d39b4SEd Tanous         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1025a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
102658eb238fSKowalski, Kamil         return;
102758eb238fSKowalski, Kamil     }
102858eb238fSKowalski, Kamil 
102958eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
103058eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
103158eb238fSKowalski, Kamil 
103237cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
1033656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
1034656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
103537cce918SMarri Devender Rao         if (ec)
103637cce918SMarri Devender Rao         {
103737cce918SMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
103837cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
103937cce918SMarri Devender Rao             return;
104037cce918SMarri Devender Rao         }
1041717b9802SJiaqing Zhao 
1042717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1043717b9802SJiaqing Zhao         std::string certId = path.filename();
1044828252d5SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
1045828252d5SJiaqing Zhao             "redfish", "v1", "AccountService", "LDAP", "Certificates", certId);
1046828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1047828252d5SJiaqing Zhao                                  certId, certURL, "LDAP Certificate");
104837cce918SMarri Devender Rao         BMCWEB_LOG_DEBUG << "LDAP certificate install file="
104937cce918SMarri Devender Rao                          << certFile->getCertFilePath();
105037cce918SMarri Devender Rao         },
1051828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1052828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1053828252d5SJiaqing Zhao }
105437cce918SMarri Devender Rao 
1055828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1056828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1057828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
105837cce918SMarri Devender Rao {
10593ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
106045ca1b86SEd Tanous     {
106145ca1b86SEd Tanous         return;
106245ca1b86SEd Tanous     }
1063717b9802SJiaqing Zhao 
1064717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id;
10651e312598SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
10661e312598SJiaqing Zhao         "redfish", "v1", "AccountService", "LDAP", "Certificates", id);
1067717b9802SJiaqing Zhao     std::string objPath =
1068717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1069717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1070717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1071828252d5SJiaqing Zhao }
1072828252d5SJiaqing Zhao 
107399612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
107499612247SJiaqing Zhao     App& app, const crow::Request& req,
107599612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
107699612247SJiaqing Zhao {
107799612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
107899612247SJiaqing Zhao     {
107999612247SJiaqing Zhao         return;
108099612247SJiaqing Zhao     }
108199612247SJiaqing Zhao 
108299612247SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Delete LDAP Certificate ID=" << id;
108399612247SJiaqing Zhao     std::string objPath =
108499612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
108599612247SJiaqing Zhao 
108699612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
108799612247SJiaqing Zhao }
108899612247SJiaqing Zhao 
1089828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1090cfcd5f6bSMarri Devender Rao {
1091828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1092828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1093828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1094828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1095828252d5SJiaqing Zhao 
1096828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1097828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1098828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1099828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1100828252d5SJiaqing Zhao 
1101828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1102ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1103002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1104828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
110599612247SJiaqing Zhao 
110699612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
110799612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
110899612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
110999612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1110828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1111828252d5SJiaqing Zhao 
1112828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1113828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1114828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1115828252d5SJiaqing Zhao {
11163ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111745ca1b86SEd Tanous     {
111845ca1b86SEd Tanous         return;
111945ca1b86SEd Tanous     }
11201476687dSEd Tanous 
11211476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
11221476687dSEd Tanous         "/redfish/v1/Managers/bmc/Truststore/Certificates/";
11231476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11241476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1125002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11261476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
11271476687dSEd Tanous         "A Collection of TrustStore certificate instances";
11288d1b46d7Szhanghch05 
1129d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1130d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1131d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1132828252d5SJiaqing Zhao }
1133cfcd5f6bSMarri Devender Rao 
1134828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1135828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1136828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1137828252d5SJiaqing Zhao {
11383ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
113945ca1b86SEd Tanous     {
114045ca1b86SEd Tanous         return;
114145ca1b86SEd Tanous     }
1142002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1143a08752f5SZbigniew Kurzynski 
1144a08752f5SZbigniew Kurzynski     if (certFileBody.empty())
1145a08752f5SZbigniew Kurzynski     {
11460fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1147a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1148a08752f5SZbigniew Kurzynski         return;
1149a08752f5SZbigniew Kurzynski     }
1150a08752f5SZbigniew Kurzynski 
1151a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1152a08752f5SZbigniew Kurzynski         std::make_shared<CertificateFile>(certFileBody);
1153cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
1154656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
1155656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1156cfcd5f6bSMarri Devender Rao         if (ec)
1157cfcd5f6bSMarri Devender Rao         {
1158cfcd5f6bSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1159cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1160cfcd5f6bSMarri Devender Rao             return;
1161cfcd5f6bSMarri Devender Rao         }
1162656ec7e3SZbigniew Kurzynski 
1163717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1164717b9802SJiaqing Zhao         std::string certId = path.filename();
1165828252d5SJiaqing Zhao         const boost::urls::url certURL =
1166828252d5SJiaqing Zhao             crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1167828252d5SJiaqing Zhao                                          "Truststore", "Certificates", certId);
1168717b9802SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath,
1169828252d5SJiaqing Zhao                                  certs::authorityServiceName, certId, certURL,
1170828252d5SJiaqing Zhao                                  "TrustStore Certificate");
11710fda0f12SGeorge Liu         BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1172cfcd5f6bSMarri Devender Rao                          << certFile->getCertFilePath();
1173cfcd5f6bSMarri Devender Rao         },
1174cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
11750fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1176828252d5SJiaqing Zhao }
1177cfcd5f6bSMarri Devender Rao 
1178828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1179828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1180828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1181cfcd5f6bSMarri Devender Rao {
11823ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
118345ca1b86SEd Tanous     {
118445ca1b86SEd Tanous         return;
118545ca1b86SEd Tanous     }
1186717b9802SJiaqing Zhao 
1187717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id;
1188828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
1189828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id);
1190717b9802SJiaqing Zhao     std::string objPath =
1191717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1192828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1193828252d5SJiaqing Zhao                              id, certURL, "TrustStore Certificate");
1194828252d5SJiaqing Zhao }
119507a60299SZbigniew Kurzynski 
1196828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1197828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1198828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1199828252d5SJiaqing Zhao {
12003ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
120145ca1b86SEd Tanous     {
120245ca1b86SEd Tanous         return;
120345ca1b86SEd Tanous     }
120407a60299SZbigniew Kurzynski 
1205717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id;
1206717b9802SJiaqing Zhao     std::string objPath =
1207717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
120807a60299SZbigniew Kurzynski 
12097a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1210828252d5SJiaqing Zhao }
1211828252d5SJiaqing Zhao 
1212828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1213828252d5SJiaqing Zhao {
1214828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1215828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1216828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1217828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1218828252d5SJiaqing Zhao 
1219828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1220828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1221828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1222828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1223828252d5SJiaqing Zhao 
1224828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1225828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1226828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1227828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1228828252d5SJiaqing Zhao 
1229828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1230828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1231828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1232828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
12337e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
12345968caeeSMarri Devender Rao } // namespace redfish
1235