xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
35968caeeSMarri Devender Rao #pragma once
45968caeeSMarri Devender Rao 
53ccb3adbSEd Tanous #include "app.hpp"
63ccb3adbSEd Tanous #include "async_resp.hpp"
77a1dbc48SGeorge Liu #include "dbus_utility.hpp"
81aa0c2b8SEd Tanous #include "http/parsing.hpp"
93ccb3adbSEd Tanous #include "http_response.hpp"
103ccb3adbSEd Tanous #include "query.hpp"
113ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
129b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp"
133ccb3adbSEd Tanous #include "utils/json_utils.hpp"
143ccb3adbSEd Tanous #include "utils/time_utils.hpp"
159b12d1f9SKrzysztof Grobelny 
1690d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp>
17ef4c65b7SEd Tanous #include <boost/url/format.hpp>
189b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
193ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
209b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
211214b7e7SGunnar Mills 
227a1dbc48SGeorge Liu #include <array>
233ccb3adbSEd Tanous #include <memory>
247a1dbc48SGeorge Liu #include <string_view>
257a1dbc48SGeorge Liu 
265968caeeSMarri Devender Rao namespace redfish
275968caeeSMarri Devender Rao {
285968caeeSMarri Devender Rao namespace certs
295968caeeSMarri Devender Rao {
3089492a15SPatrick Williams constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install";
3189492a15SPatrick Williams constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
3289492a15SPatrick Williams constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
3389492a15SPatrick Williams constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
3489492a15SPatrick Williams constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties";
3589492a15SPatrick Williams constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
3689492a15SPatrick Williams constexpr const char* httpsServiceName =
3737cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
3889492a15SPatrick Williams constexpr const char* ldapServiceName =
3937cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
4089492a15SPatrick Williams constexpr const char* authorityServiceName =
41b2254ccdSMichal Orzel     "xyz.openbmc_project.Certs.Manager.Authority.Truststore";
4289492a15SPatrick Williams constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs";
4389492a15SPatrick Williams constexpr const char* httpsObjectPath =
44c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
4589492a15SPatrick Williams constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
4689492a15SPatrick Williams constexpr const char* authorityObjectPath =
47b2254ccdSMichal Orzel     "/xyz/openbmc_project/certs/authority/truststore";
485968caeeSMarri Devender Rao } // namespace certs
495968caeeSMarri Devender Rao 
505968caeeSMarri Devender Rao /**
515968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
525968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
535968caeeSMarri Devender Rao  * are installed.
545968caeeSMarri Devender Rao  */
557e860f15SJohn Edward Broadbent 
568d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
578d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5858eb238fSKowalski, Kamil     const crow::Request& req)
5958eb238fSKowalski, Kamil {
601aa0c2b8SEd Tanous     nlohmann::json reqJson;
611aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, reqJson);
621aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
6358eb238fSKowalski, Kamil     {
6458eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
6533c6b580SEd Tanous         return req.body();
6658eb238fSKowalski, Kamil     }
6758eb238fSKowalski, Kamil 
6858eb238fSKowalski, Kamil     std::string certificate;
6958eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
7058eb238fSKowalski, Kamil 
71afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
72afc474aeSMyung Bae             req, asyncResp->res, //
73afc474aeSMyung Bae             "CertificateString", certificate, //
74afc474aeSMyung Bae             "CertificateType", certificateType //
75afc474aeSMyung Bae             ))
7658eb238fSKowalski, Kamil     {
7762598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
7858eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
79abb93cddSEd Tanous         return {};
8058eb238fSKowalski, Kamil     }
8158eb238fSKowalski, Kamil 
8258eb238fSKowalski, Kamil     if (*certificateType != "PEM")
8358eb238fSKowalski, Kamil     {
8458eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
8558eb238fSKowalski, Kamil                                          "CertificateType");
86abb93cddSEd Tanous         return {};
8758eb238fSKowalski, Kamil     }
8858eb238fSKowalski, Kamil 
8958eb238fSKowalski, Kamil     return certificate;
9058eb238fSKowalski, Kamil }
9158eb238fSKowalski, Kamil 
925968caeeSMarri Devender Rao /**
935968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
945968caeeSMarri Devender Rao  */
955968caeeSMarri Devender Rao class CertificateFile
965968caeeSMarri Devender Rao {
975968caeeSMarri Devender Rao   public:
985968caeeSMarri Devender Rao     CertificateFile() = delete;
995968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
1005968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
1015968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
1025968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
1034e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
1045968caeeSMarri Devender Rao     {
10572d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1065207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1075207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1085207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
109e662eae8SEd Tanous         if (tempDirectory != nullptr)
1105968caeeSMarri Devender Rao         {
1115968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1125968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
113bd79bce8SPatrick Williams             std::ofstream out(certificateFile,
114bd79bce8SPatrick Williams                               std::ofstream::out | std::ofstream::binary |
1155968caeeSMarri Devender Rao                                   std::ofstream::trunc);
1165968caeeSMarri Devender Rao             out << certString;
1175968caeeSMarri Devender Rao             out.close();
11862598e31SEd Tanous             BMCWEB_LOG_DEBUG("Creating certificate file{}",
11962598e31SEd Tanous                              certificateFile.string());
1205968caeeSMarri Devender Rao         }
1215968caeeSMarri Devender Rao     }
1225968caeeSMarri Devender Rao     ~CertificateFile()
1235968caeeSMarri Devender Rao     {
1245968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1255968caeeSMarri Devender Rao         {
12662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Removing certificate file{}",
12762598e31SEd Tanous                              certificateFile.string());
12823a21a1cSEd Tanous             std::error_code ec;
12923a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
13023a21a1cSEd Tanous             if (ec)
1315968caeeSMarri Devender Rao             {
13262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to remove temp directory{}",
13362598e31SEd Tanous                                  certDirectory.string());
1345968caeeSMarri Devender Rao             }
1355968caeeSMarri Devender Rao         }
1365968caeeSMarri Devender Rao     }
1375968caeeSMarri Devender Rao     std::string getCertFilePath()
1385968caeeSMarri Devender Rao     {
1395968caeeSMarri Devender Rao         return certificateFile;
1405968caeeSMarri Devender Rao     }
1415968caeeSMarri Devender Rao 
1425968caeeSMarri Devender Rao   private:
1435968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1445968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1455968caeeSMarri Devender Rao };
1465968caeeSMarri Devender Rao 
1475968caeeSMarri Devender Rao /**
1484e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1495968caeeSMarri Devender Rao  *
1505968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1515968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1525968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1535968caeeSMarri Devender Rao  * @return None
1545968caeeSMarri Devender Rao  */
1554ff0f1f4SEd Tanous inline void updateCertIssuerOrSubject(nlohmann::json& out,
15626ccae32SEd Tanous                                       std::string_view value)
1575968caeeSMarri Devender Rao {
1585968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1595968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1605968caeeSMarri Devender Rao     while (i != value.end())
1615968caeeSMarri Devender Rao     {
1625968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1635968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1645968caeeSMarri Devender Rao         {
1656da47babSPatrick Williams             std::advance(i, 1);
1665968caeeSMarri Devender Rao         }
1675968caeeSMarri Devender Rao         if (i == value.end())
1685968caeeSMarri Devender Rao         {
1695968caeeSMarri Devender Rao             break;
1705968caeeSMarri Devender Rao         }
17126ccae32SEd Tanous         std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin));
1726da47babSPatrick Williams         std::advance(i, 1);
1735968caeeSMarri Devender Rao         tokenBegin = i;
1745968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
1755968caeeSMarri Devender Rao         {
1766da47babSPatrick Williams             std::advance(i, 1);
1775968caeeSMarri Devender Rao         }
17826ccae32SEd Tanous         std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin));
1795968caeeSMarri Devender Rao         if (key == "L")
1805968caeeSMarri Devender Rao         {
1815968caeeSMarri Devender Rao             out["City"] = val;
1825968caeeSMarri Devender Rao         }
1835968caeeSMarri Devender Rao         else if (key == "CN")
1845968caeeSMarri Devender Rao         {
1855968caeeSMarri Devender Rao             out["CommonName"] = val;
1865968caeeSMarri Devender Rao         }
1875968caeeSMarri Devender Rao         else if (key == "C")
1885968caeeSMarri Devender Rao         {
1895968caeeSMarri Devender Rao             out["Country"] = val;
1905968caeeSMarri Devender Rao         }
1915968caeeSMarri Devender Rao         else if (key == "O")
1925968caeeSMarri Devender Rao         {
1935968caeeSMarri Devender Rao             out["Organization"] = val;
1945968caeeSMarri Devender Rao         }
1955968caeeSMarri Devender Rao         else if (key == "OU")
1965968caeeSMarri Devender Rao         {
1975968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
1985968caeeSMarri Devender Rao         }
1995968caeeSMarri Devender Rao         else if (key == "ST")
2005968caeeSMarri Devender Rao         {
2015968caeeSMarri Devender Rao             out["State"] = val;
2025968caeeSMarri Devender Rao         }
2035968caeeSMarri Devender Rao         // skip comma character
2045968caeeSMarri Devender Rao         if (i != value.end())
2055968caeeSMarri Devender Rao         {
2066da47babSPatrick Williams             std::advance(i, 1);
2075968caeeSMarri Devender Rao         }
2085968caeeSMarri Devender Rao     }
2095968caeeSMarri Devender Rao }
2105968caeeSMarri Devender Rao 
2115968caeeSMarri Devender Rao /**
212d3f92ce7SJiaqing Zhao  * @brief Retrieve the installed certificate list
213d3f92ce7SJiaqing Zhao  *
214d3f92ce7SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
215d3f92ce7SJiaqing Zhao  * @param[in] basePath DBus object path to search
216d3f92ce7SJiaqing Zhao  * @param[in] listPtr Json pointer to the list in asyncResp
217d3f92ce7SJiaqing Zhao  * @param[in] countPtr Json pointer to the count in asyncResp
218d3f92ce7SJiaqing Zhao  * @return None
219d3f92ce7SJiaqing Zhao  */
2204ff0f1f4SEd Tanous inline void getCertificateList(
221bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
222bd79bce8SPatrick Williams     const std::string& basePath, const nlohmann::json::json_pointer& listPtr,
223d3f92ce7SJiaqing Zhao     const nlohmann::json::json_pointer& countPtr)
224d3f92ce7SJiaqing Zhao {
2257a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2267a1dbc48SGeorge Liu         certs::certPropIntf};
2277a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
2287a1dbc48SGeorge Liu         basePath, 0, interfaces,
229d3f92ce7SJiaqing Zhao         [asyncResp, listPtr, countPtr](
2307a1dbc48SGeorge Liu             const boost::system::error_code& ec,
231d3f92ce7SJiaqing Zhao             const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
232d3f92ce7SJiaqing Zhao             if (ec)
233d3f92ce7SJiaqing Zhao             {
23462598e31SEd Tanous                 BMCWEB_LOG_ERROR("Certificate collection query failed: {}", ec);
235d3f92ce7SJiaqing Zhao                 messages::internalError(asyncResp->res);
236d3f92ce7SJiaqing Zhao                 return;
237d3f92ce7SJiaqing Zhao             }
238d3f92ce7SJiaqing Zhao 
239d3f92ce7SJiaqing Zhao             nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
240d3f92ce7SJiaqing Zhao             links = nlohmann::json::array();
241d3f92ce7SJiaqing Zhao             for (const auto& certPath : certPaths)
242d3f92ce7SJiaqing Zhao             {
243d3f92ce7SJiaqing Zhao                 sdbusplus::message::object_path objPath(certPath);
244d3f92ce7SJiaqing Zhao                 std::string certId = objPath.filename();
245d3f92ce7SJiaqing Zhao                 if (certId.empty())
246d3f92ce7SJiaqing Zhao                 {
247bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR("Invalid certificate objPath {}",
248bd79bce8SPatrick Williams                                      certPath);
249d3f92ce7SJiaqing Zhao                     continue;
250d3f92ce7SJiaqing Zhao                 }
251d3f92ce7SJiaqing Zhao 
252d3f92ce7SJiaqing Zhao                 boost::urls::url certURL;
253d3f92ce7SJiaqing Zhao                 if (objPath.parent_path() == certs::httpsObjectPath)
254d3f92ce7SJiaqing Zhao                 {
255ef4c65b7SEd Tanous                     certURL = boost::urls::format(
256253f11b8SEd Tanous                         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
257253f11b8SEd Tanous                         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
258d3f92ce7SJiaqing Zhao                 }
259d3f92ce7SJiaqing Zhao                 else if (objPath.parent_path() == certs::ldapObjectPath)
260d3f92ce7SJiaqing Zhao                 {
261ef4c65b7SEd Tanous                     certURL = boost::urls::format(
262bd79bce8SPatrick Williams                         "/redfish/v1/AccountService/LDAP/Certificates/{}",
263bd79bce8SPatrick Williams                         certId);
264d3f92ce7SJiaqing Zhao                 }
265d3f92ce7SJiaqing Zhao                 else if (objPath.parent_path() == certs::authorityObjectPath)
266d3f92ce7SJiaqing Zhao                 {
267ef4c65b7SEd Tanous                     certURL = boost::urls::format(
268253f11b8SEd Tanous                         "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
269253f11b8SEd Tanous                         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
270d3f92ce7SJiaqing Zhao                 }
271d3f92ce7SJiaqing Zhao                 else
272d3f92ce7SJiaqing Zhao                 {
273d3f92ce7SJiaqing Zhao                     continue;
274d3f92ce7SJiaqing Zhao                 }
275d3f92ce7SJiaqing Zhao 
276d3f92ce7SJiaqing Zhao                 nlohmann::json::object_t link;
277d3f92ce7SJiaqing Zhao                 link["@odata.id"] = certURL;
278d3f92ce7SJiaqing Zhao                 links.emplace_back(std::move(link));
279d3f92ce7SJiaqing Zhao             }
280d3f92ce7SJiaqing Zhao 
281d3f92ce7SJiaqing Zhao             asyncResp->res.jsonValue[countPtr] = links.size();
2827a1dbc48SGeorge Liu         });
283d3f92ce7SJiaqing Zhao }
284d3f92ce7SJiaqing Zhao 
285d3f92ce7SJiaqing Zhao /**
2865968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
2875968caeeSMarri Devender Rao  * message
2885968caeeSMarri Devender Rao  *
2895968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
2905968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
2915968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
2925968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
2935968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
2945968caeeSMarri Devender Rao  * @return None
2955968caeeSMarri Devender Rao  */
2964ff0f1f4SEd Tanous inline void getCertificateProperties(
2978d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
298e19e97e2SJiaqing Zhao     const std::string& objectPath, const std::string& service,
2991e312598SJiaqing Zhao     const std::string& certId, const boost::urls::url& certURL,
300e19e97e2SJiaqing Zhao     const std::string& name)
3015968caeeSMarri Devender Rao {
30262598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}",
30362598e31SEd Tanous                      objectPath, certId, certURL);
304deae6a78SEd Tanous     dbus::utility::getAllProperties(
305deae6a78SEd Tanous         service, objectPath, certs::certPropIntf,
306b9d36b47SEd Tanous         [asyncResp, certURL, certId,
3075e7e2dc5SEd Tanous          name](const boost::system::error_code& ec,
308b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
3095968caeeSMarri Devender Rao             if (ec)
3105968caeeSMarri Devender Rao             {
31162598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
312bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Certificate",
313bd79bce8SPatrick Williams                                            certId);
3145968caeeSMarri Devender Rao                 return;
3155968caeeSMarri Devender Rao             }
3169b12d1f9SKrzysztof Grobelny 
3179b12d1f9SKrzysztof Grobelny             const std::string* certificateString = nullptr;
3189b12d1f9SKrzysztof Grobelny             const std::vector<std::string>* keyUsage = nullptr;
3199b12d1f9SKrzysztof Grobelny             const std::string* issuer = nullptr;
3209b12d1f9SKrzysztof Grobelny             const std::string* subject = nullptr;
3219b12d1f9SKrzysztof Grobelny             const uint64_t* validNotAfter = nullptr;
3229b12d1f9SKrzysztof Grobelny             const uint64_t* validNotBefore = nullptr;
3239b12d1f9SKrzysztof Grobelny 
3249b12d1f9SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
325bd79bce8SPatrick Williams                 dbus_utils::UnpackErrorPrinter(), properties,
326bd79bce8SPatrick Williams                 "CertificateString", certificateString, "KeyUsage", keyUsage,
327bd79bce8SPatrick Williams                 "Issuer", issuer, "Subject", subject, "ValidNotAfter",
328bd79bce8SPatrick Williams                 validNotAfter, "ValidNotBefore", validNotBefore);
3299b12d1f9SKrzysztof Grobelny 
3309b12d1f9SKrzysztof Grobelny             if (!success)
3319b12d1f9SKrzysztof Grobelny             {
3329b12d1f9SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
3339b12d1f9SKrzysztof Grobelny                 return;
3349b12d1f9SKrzysztof Grobelny             }
3359b12d1f9SKrzysztof Grobelny 
3361476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = certURL;
3371476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
3381476687dSEd Tanous                 "#Certificate.v1_0_0.Certificate";
339e19e97e2SJiaqing Zhao             asyncResp->res.jsonValue["Id"] = certId;
3401476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = name;
3411476687dSEd Tanous             asyncResp->res.jsonValue["Description"] = name;
3425968caeeSMarri Devender Rao             asyncResp->res.jsonValue["CertificateString"] = "";
3439b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
3449b12d1f9SKrzysztof Grobelny 
3459b12d1f9SKrzysztof Grobelny             if (certificateString != nullptr)
3465968caeeSMarri Devender Rao             {
347bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["CertificateString"] =
348bd79bce8SPatrick Williams                     *certificateString;
3495968caeeSMarri Devender Rao             }
3509b12d1f9SKrzysztof Grobelny 
3519b12d1f9SKrzysztof Grobelny             if (keyUsage != nullptr)
3525968caeeSMarri Devender Rao             {
3539b12d1f9SKrzysztof Grobelny                 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
3545968caeeSMarri Devender Rao             }
3559b12d1f9SKrzysztof Grobelny 
3569b12d1f9SKrzysztof Grobelny             if (issuer != nullptr)
3575968caeeSMarri Devender Rao             {
3589b12d1f9SKrzysztof Grobelny                 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
3599b12d1f9SKrzysztof Grobelny                                           *issuer);
3605968caeeSMarri Devender Rao             }
3619b12d1f9SKrzysztof Grobelny 
3629b12d1f9SKrzysztof Grobelny             if (subject != nullptr)
3635968caeeSMarri Devender Rao             {
3649b12d1f9SKrzysztof Grobelny                 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
3659b12d1f9SKrzysztof Grobelny                                           *subject);
3665968caeeSMarri Devender Rao             }
3679b12d1f9SKrzysztof Grobelny 
3689b12d1f9SKrzysztof Grobelny             if (validNotAfter != nullptr)
3695968caeeSMarri Devender Rao             {
3705968caeeSMarri Devender Rao                 asyncResp->res.jsonValue["ValidNotAfter"] =
3719b12d1f9SKrzysztof Grobelny                     redfish::time_utils::getDateTimeUint(*validNotAfter);
3725968caeeSMarri Devender Rao             }
3739b12d1f9SKrzysztof Grobelny 
3749b12d1f9SKrzysztof Grobelny             if (validNotBefore != nullptr)
3755968caeeSMarri Devender Rao             {
3765968caeeSMarri Devender Rao                 asyncResp->res.jsonValue["ValidNotBefore"] =
3779b12d1f9SKrzysztof Grobelny                     redfish::time_utils::getDateTimeUint(*validNotBefore);
3785968caeeSMarri Devender Rao             }
3799b12d1f9SKrzysztof Grobelny 
3801e312598SJiaqing Zhao             asyncResp->res.addHeader(
381d9f6c621SEd Tanous                 boost::beast::http::field::location,
382d9f6c621SEd Tanous                 std::string_view(certURL.data(), certURL.size()));
3839b12d1f9SKrzysztof Grobelny         });
3845968caeeSMarri Devender Rao }
3855968caeeSMarri Devender Rao 
3864ff0f1f4SEd Tanous inline void
3877a3a8f7aSJiaqing Zhao     deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3887a3a8f7aSJiaqing Zhao                       const std::string& service,
3897a3a8f7aSJiaqing Zhao                       const sdbusplus::message::object_path& objectPath)
3907a3a8f7aSJiaqing Zhao {
3917a3a8f7aSJiaqing Zhao     crow::connections::systemBus->async_method_call(
3927a3a8f7aSJiaqing Zhao         [asyncResp,
3935e7e2dc5SEd Tanous          id{objectPath.filename()}](const boost::system::error_code& ec) {
3947a3a8f7aSJiaqing Zhao             if (ec)
3957a3a8f7aSJiaqing Zhao             {
3967a3a8f7aSJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
3977a3a8f7aSJiaqing Zhao                 return;
3987a3a8f7aSJiaqing Zhao             }
39962598e31SEd Tanous             BMCWEB_LOG_INFO("Certificate deleted");
4007a3a8f7aSJiaqing Zhao             asyncResp->res.result(boost::beast::http::status::no_content);
4017a3a8f7aSJiaqing Zhao         },
4027a3a8f7aSJiaqing Zhao         service, objectPath, certs::objDeleteIntf, "Delete");
4037a3a8f7aSJiaqing Zhao }
4047a3a8f7aSJiaqing Zhao 
405828252d5SJiaqing Zhao inline void handleCertificateServiceGet(
406828252d5SJiaqing Zhao     App& app, const crow::Request& req,
407828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4085968caeeSMarri Devender Rao {
409828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
410828252d5SJiaqing Zhao     {
411828252d5SJiaqing Zhao         return;
412828252d5SJiaqing Zhao     }
413828252d5SJiaqing Zhao 
4143e72c202SNinad Palsule     if (req.session == nullptr)
4153e72c202SNinad Palsule     {
4163e72c202SNinad Palsule         messages::internalError(asyncResp->res);
4173e72c202SNinad Palsule         return;
4183e72c202SNinad Palsule     }
4193e72c202SNinad Palsule 
420828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
421828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
422828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
423828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
424828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
425828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
426828252d5SJiaqing Zhao         "Actions available to manage certificates";
427828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
428828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
429828252d5SJiaqing Zhao     // has permissions ConfigureManager
430828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
4313e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
432828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
433828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
434828252d5SJiaqing Zhao     {
435828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
436828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
437828252d5SJiaqing Zhao     }
438828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
439828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
440828252d5SJiaqing Zhao     replace["target"] =
441828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
442828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
443ad539545SPatrick Williams     allowed.emplace_back("PEM");
444828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
445828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
446828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
447828252d5SJiaqing Zhao }
448828252d5SJiaqing Zhao 
449828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
450828252d5SJiaqing Zhao     App& app, const crow::Request& req,
451828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
452828252d5SJiaqing Zhao {
453828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
454828252d5SJiaqing Zhao     {
455828252d5SJiaqing Zhao         return;
456828252d5SJiaqing Zhao     }
457828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
458828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
459828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
460828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
461828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
462828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
463828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
464828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
465828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
466828252d5SJiaqing Zhao 
467828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
468828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
469828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
470828252d5SJiaqing Zhao }
471828252d5SJiaqing Zhao 
47226d3b0fbSChandra Harkude inline void handleError(const std::string_view dbusErrorName,
47326d3b0fbSChandra Harkude                         const std::string& id, const std::string& certificate,
47426d3b0fbSChandra Harkude                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
47526d3b0fbSChandra Harkude {
47626d3b0fbSChandra Harkude     if (dbusErrorName == "org.freedesktop.DBus.Error.UnknownObject")
47726d3b0fbSChandra Harkude     {
47826d3b0fbSChandra Harkude         messages::resourceNotFound(asyncResp->res, "Certificate", id);
47926d3b0fbSChandra Harkude     }
48026d3b0fbSChandra Harkude     else if (dbusErrorName ==
48126d3b0fbSChandra Harkude              "xyz.openbmc_project.Certs.Error.InvalidCertificate")
48226d3b0fbSChandra Harkude     {
48326d3b0fbSChandra Harkude         messages::propertyValueIncorrect(asyncResp->res, "Certificate",
48426d3b0fbSChandra Harkude                                          certificate);
48526d3b0fbSChandra Harkude     }
48626d3b0fbSChandra Harkude     else
48726d3b0fbSChandra Harkude     {
48826d3b0fbSChandra Harkude         messages::internalError(asyncResp->res);
48926d3b0fbSChandra Harkude     }
49026d3b0fbSChandra Harkude }
49126d3b0fbSChandra Harkude 
492828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
493828252d5SJiaqing Zhao     App& app, const crow::Request& req,
494828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
495828252d5SJiaqing Zhao {
4963ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
49745ca1b86SEd Tanous     {
49845ca1b86SEd Tanous         return;
49945ca1b86SEd Tanous     }
5005968caeeSMarri Devender Rao     std::string certificate;
5017a31e336SEd Tanous     std::string certURI;
5025968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
5038d1b46d7Szhanghch05 
504afc474aeSMyung Bae     if (!json_util::readJsonAction( //
505afc474aeSMyung Bae             req, asyncResp->res, //
506afc474aeSMyung Bae             "CertificateString", certificate, //
507afc474aeSMyung Bae             "CertificateType", certificateType, //
508afc474aeSMyung Bae             "CertificateUri/@odata.id", certURI //
509afc474aeSMyung Bae             ))
5105968caeeSMarri Devender Rao     {
51162598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
5125968caeeSMarri Devender Rao         return;
5135968caeeSMarri Devender Rao     }
5145968caeeSMarri Devender Rao 
5155968caeeSMarri Devender Rao     if (!certificateType)
5165968caeeSMarri Devender Rao     {
5175968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
5185968caeeSMarri Devender Rao         return;
5195968caeeSMarri Devender Rao     }
5205968caeeSMarri Devender Rao     if (certificateType != "PEM")
5215968caeeSMarri Devender Rao     {
522828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
523828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5245968caeeSMarri Devender Rao         return;
5255968caeeSMarri Devender Rao     }
5265968caeeSMarri Devender Rao 
52762598e31SEd Tanous     BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI);
5285968caeeSMarri Devender Rao 
5296fd29553SEd Tanous     boost::system::result<boost::urls::url> parsedUrl =
53075b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
53175b63a2cSJiaqing Zhao     if (!parsedUrl)
5325968caeeSMarri Devender Rao     {
533828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
534828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
5355968caeeSMarri Devender Rao         return;
5365968caeeSMarri Devender Rao     }
53775b63a2cSJiaqing Zhao 
53875b63a2cSJiaqing Zhao     std::string id;
53975b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
5405968caeeSMarri Devender Rao     std::string name;
54137cce918SMarri Devender Rao     std::string service;
542828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
543828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
544828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5455968caeeSMarri Devender Rao     {
54689492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) /
54789492a15SPatrick Williams                      id;
5485968caeeSMarri Devender Rao         name = "HTTPS certificate";
54937cce918SMarri Devender Rao         service = certs::httpsServiceName;
55037cce918SMarri Devender Rao     }
55175b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
55275b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
55375b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
55437cce918SMarri Devender Rao     {
55589492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) /
55689492a15SPatrick Williams                      id;
55737cce918SMarri Devender Rao         name = "LDAP certificate";
55837cce918SMarri Devender Rao         service = certs::ldapServiceName;
5595968caeeSMarri Devender Rao     }
56075b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
56175b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
56275b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
563cfcd5f6bSMarri Devender Rao     {
56475b63a2cSJiaqing Zhao         objectPath =
565828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
566cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
567cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
568cfcd5f6bSMarri Devender Rao     }
5695968caeeSMarri Devender Rao     else
5705968caeeSMarri Devender Rao     {
571828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
572828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5735968caeeSMarri Devender Rao         return;
5745968caeeSMarri Devender Rao     }
5755968caeeSMarri Devender Rao 
5765968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
5775968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
5785968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
57926d3b0fbSChandra Harkude         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, name,
58026d3b0fbSChandra Harkude          certificate](const boost::system::error_code& ec,
581d3e0859cSPatrick Williams                       sdbusplus::message_t& m) {
5825968caeeSMarri Devender Rao             if (ec)
5835968caeeSMarri Devender Rao             {
58462598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
58526d3b0fbSChandra Harkude                 const sd_bus_error* dbusError = m.get_error();
58626d3b0fbSChandra Harkude                 if ((dbusError != nullptr) && (dbusError->name != nullptr))
58790d2d1e8SJiaqing Zhao                 {
58826d3b0fbSChandra Harkude                     handleError(dbusError->name, id, certificate, asyncResp);
5895968caeeSMarri Devender Rao                 }
59026d3b0fbSChandra Harkude                 else
59126d3b0fbSChandra Harkude                 {
59290d2d1e8SJiaqing Zhao                     messages::internalError(asyncResp->res);
59326d3b0fbSChandra Harkude                 }
59490d2d1e8SJiaqing Zhao                 return;
59590d2d1e8SJiaqing Zhao             }
596bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath, service, id, url,
597bd79bce8SPatrick Williams                                      name);
59862598e31SEd Tanous             BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
59962598e31SEd Tanous                              certFile->getCertFilePath());
6005968caeeSMarri Devender Rao         },
6015968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
6025968caeeSMarri Devender Rao         certFile->getCertFilePath());
603828252d5SJiaqing Zhao }
6045968caeeSMarri Devender Rao 
605cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
606828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
6075968caeeSMarri Devender Rao /**
608828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
609828252d5SJiaqing Zhao  *
610828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
6118ece0e45SEd Tanous  * @param[in] certURI Link to certificate collection URI
612828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
613828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
614828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
615828252d5SJiaqing Zhao  * @return None
6165968caeeSMarri Devender Rao  */
6174ff0f1f4SEd Tanous inline void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
618828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
619828252d5SJiaqing Zhao                    const std::string& certObjPath,
620828252d5SJiaqing Zhao                    const std::string& csrObjPath)
6215968caeeSMarri Devender Rao {
62262598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}",
62362598e31SEd Tanous                      certObjPath, csrObjPath, service);
624828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
625bd79bce8SPatrick Williams         [asyncResp,
626bd79bce8SPatrick Williams          certURI](const boost::system::error_code& ec, const std::string& csr) {
627828252d5SJiaqing Zhao             if (ec)
628828252d5SJiaqing Zhao             {
62962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
630828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
631828252d5SJiaqing Zhao                 return;
632828252d5SJiaqing Zhao             }
633828252d5SJiaqing Zhao             if (csr.empty())
634828252d5SJiaqing Zhao             {
63562598e31SEd Tanous                 BMCWEB_LOG_ERROR("CSR read is empty");
636828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
637828252d5SJiaqing Zhao                 return;
638828252d5SJiaqing Zhao             }
639828252d5SJiaqing Zhao             asyncResp->res.jsonValue["CSRString"] = csr;
640828252d5SJiaqing Zhao             asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
641828252d5SJiaqing Zhao                 certURI;
642828252d5SJiaqing Zhao         },
643828252d5SJiaqing Zhao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
644828252d5SJiaqing Zhao }
645828252d5SJiaqing Zhao 
646828252d5SJiaqing Zhao inline void
647828252d5SJiaqing Zhao     handleGenerateCSRAction(App& app, const crow::Request& req,
648828252d5SJiaqing Zhao                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
649828252d5SJiaqing Zhao {
6503ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
65145ca1b86SEd Tanous     {
65245ca1b86SEd Tanous         return;
65345ca1b86SEd Tanous     }
654828252d5SJiaqing Zhao     static const int rsaKeyBitLength = 2048;
6555968caeeSMarri Devender Rao 
656828252d5SJiaqing Zhao     // Required parameters
657828252d5SJiaqing Zhao     std::string city;
658828252d5SJiaqing Zhao     std::string commonName;
659828252d5SJiaqing Zhao     std::string country;
660828252d5SJiaqing Zhao     std::string organization;
661828252d5SJiaqing Zhao     std::string organizationalUnit;
662828252d5SJiaqing Zhao     std::string state;
6637a31e336SEd Tanous     std::string certURI;
664828252d5SJiaqing Zhao 
665828252d5SJiaqing Zhao     // Optional parameters
666828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optAlternativeNames =
667828252d5SJiaqing Zhao         std::vector<std::string>();
668828252d5SJiaqing Zhao     std::optional<std::string> optContactPerson = "";
669828252d5SJiaqing Zhao     std::optional<std::string> optChallengePassword = "";
670828252d5SJiaqing Zhao     std::optional<std::string> optEmail = "";
671828252d5SJiaqing Zhao     std::optional<std::string> optGivenName = "";
672828252d5SJiaqing Zhao     std::optional<std::string> optInitials = "";
673828252d5SJiaqing Zhao     std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
674828252d5SJiaqing Zhao     std::optional<std::string> optKeyCurveId = "secp384r1";
675828252d5SJiaqing Zhao     std::optional<std::string> optKeyPairAlgorithm = "EC";
676828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optKeyUsage =
677828252d5SJiaqing Zhao         std::vector<std::string>();
678828252d5SJiaqing Zhao     std::optional<std::string> optSurname = "";
679828252d5SJiaqing Zhao     std::optional<std::string> optUnstructuredName = "";
680afc474aeSMyung Bae     if (!json_util::readJsonAction( //
681afc474aeSMyung Bae             req, asyncResp->res, //
682afc474aeSMyung Bae             "AlternativeNames", optAlternativeNames, //
683afc474aeSMyung Bae             "CertificateCollection/@odata.id", certURI, //
684afc474aeSMyung Bae             "ChallengePassword", optChallengePassword, //
685afc474aeSMyung Bae             "City", city, //
686afc474aeSMyung Bae             "CommonName", commonName, //
687afc474aeSMyung Bae             "ContactPerson", optContactPerson, //
688afc474aeSMyung Bae             "Country", country, //
689afc474aeSMyung Bae             "Email", optEmail, //
690afc474aeSMyung Bae             "GivenName", optGivenName, //
691afc474aeSMyung Bae             "Initials", optInitials, //
692afc474aeSMyung Bae             "KeyBitLength", optKeyBitLength, //
693afc474aeSMyung Bae             "KeyCurveId", optKeyCurveId, //
694afc474aeSMyung Bae             "KeyPairAlgorithm", optKeyPairAlgorithm, //
695afc474aeSMyung Bae             "KeyUsage", optKeyUsage, //
696afc474aeSMyung Bae             "Organization", organization, //
697afc474aeSMyung Bae             "OrganizationalUnit", organizationalUnit, //
698afc474aeSMyung Bae             "State", state, //
699afc474aeSMyung Bae             "Surname", optSurname, //
700afc474aeSMyung Bae             "UnstructuredName", optUnstructuredName //
701afc474aeSMyung Bae             ))
702828252d5SJiaqing Zhao     {
703828252d5SJiaqing Zhao         return;
7045968caeeSMarri Devender Rao     }
7055968caeeSMarri Devender Rao 
706828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
707828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
708828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
709828252d5SJiaqing Zhao     // value
710828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
7115968caeeSMarri Devender Rao     {
712828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
713828252d5SJiaqing Zhao                                               "ChallengePassword");
714828252d5SJiaqing Zhao         return;
715828252d5SJiaqing Zhao     }
716828252d5SJiaqing Zhao 
717828252d5SJiaqing Zhao     std::string objectPath;
718828252d5SJiaqing Zhao     std::string service;
719253f11b8SEd Tanous     if (certURI.starts_with(std::format(
720253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
721253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
722828252d5SJiaqing Zhao     {
723828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
724828252d5SJiaqing Zhao         service = certs::httpsServiceName;
725828252d5SJiaqing Zhao     }
726828252d5SJiaqing Zhao     else if (certURI.starts_with(
727828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
728828252d5SJiaqing Zhao     {
729828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
730828252d5SJiaqing Zhao         service = certs::ldapServiceName;
731828252d5SJiaqing Zhao     }
732828252d5SJiaqing Zhao     else
733828252d5SJiaqing Zhao     {
734828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
735828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
736828252d5SJiaqing Zhao         return;
737828252d5SJiaqing Zhao     }
738828252d5SJiaqing Zhao 
739828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
740828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
741828252d5SJiaqing Zhao     {
742828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
743828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
744828252d5SJiaqing Zhao         return;
745828252d5SJiaqing Zhao     }
746828252d5SJiaqing Zhao 
747828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
748828252d5SJiaqing Zhao     // time consumed in generating private key
749828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
750828252d5SJiaqing Zhao     {
751e2616cc5SEd Tanous         messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
752e2616cc5SEd Tanous                                          "KeyBitLength");
753828252d5SJiaqing Zhao         return;
754828252d5SJiaqing Zhao     }
755828252d5SJiaqing Zhao 
756828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
757253f11b8SEd Tanous     if (certURI.starts_with(std::format(
758253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
759253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
760828252d5SJiaqing Zhao     {
761828252d5SJiaqing Zhao         if (optKeyUsage->empty())
762828252d5SJiaqing Zhao         {
763b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ServerAuthentication");
764828252d5SJiaqing Zhao         }
765828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
766828252d5SJiaqing Zhao         {
767828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
768828252d5SJiaqing Zhao             {
769828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
770828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
771828252d5SJiaqing Zhao                 return;
772828252d5SJiaqing Zhao             }
773828252d5SJiaqing Zhao         }
774828252d5SJiaqing Zhao         else
775828252d5SJiaqing Zhao         {
776828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
777828252d5SJiaqing Zhao                                                   "GenerateCSR");
778828252d5SJiaqing Zhao             return;
779828252d5SJiaqing Zhao         }
780828252d5SJiaqing Zhao     }
781828252d5SJiaqing Zhao     else if (certURI.starts_with(
782828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
783828252d5SJiaqing Zhao     {
784828252d5SJiaqing Zhao         if (optKeyUsage->empty())
785828252d5SJiaqing Zhao         {
786b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ClientAuthentication");
787828252d5SJiaqing Zhao         }
788828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
789828252d5SJiaqing Zhao         {
790828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
791828252d5SJiaqing Zhao             {
792828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
793828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
794828252d5SJiaqing Zhao                 return;
795828252d5SJiaqing Zhao             }
796828252d5SJiaqing Zhao         }
797828252d5SJiaqing Zhao         else
798828252d5SJiaqing Zhao         {
799828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
800828252d5SJiaqing Zhao                                                   "GenerateCSR");
801828252d5SJiaqing Zhao             return;
802828252d5SJiaqing Zhao         }
803828252d5SJiaqing Zhao     }
804828252d5SJiaqing Zhao 
805828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
806828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
807828252d5SJiaqing Zhao     static const int timeOut = 10;
808828252d5SJiaqing Zhao     if (csrMatcher)
809828252d5SJiaqing Zhao     {
810828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
811828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
812828252d5SJiaqing Zhao         return;
813828252d5SJiaqing Zhao     }
814828252d5SJiaqing Zhao 
8158e8245dbSEd Tanous     if (req.ioService == nullptr)
8168e8245dbSEd Tanous     {
8178e8245dbSEd Tanous         messages::internalError(asyncResp->res);
8188e8245dbSEd Tanous         return;
8198e8245dbSEd Tanous     }
8208e8245dbSEd Tanous 
821828252d5SJiaqing Zhao     // Make this static so it survives outside this method
822828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
823828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
824828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
825828252d5SJiaqing Zhao         csrMatcher = nullptr;
826828252d5SJiaqing Zhao         if (ec)
827828252d5SJiaqing Zhao         {
828828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
829828252d5SJiaqing Zhao             // before completion.
830828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
831828252d5SJiaqing Zhao             {
83262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
833828252d5SJiaqing Zhao             }
834828252d5SJiaqing Zhao             return;
835828252d5SJiaqing Zhao         }
83662598e31SEd Tanous         BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
837828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
838828252d5SJiaqing Zhao     });
839828252d5SJiaqing Zhao 
840828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
84162598e31SEd Tanous     BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
842828252d5SJiaqing Zhao     std::string match("type='signal',"
843828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
844828252d5SJiaqing Zhao                       "path='" +
845828252d5SJiaqing Zhao                       objectPath +
846828252d5SJiaqing Zhao                       "',"
847828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
848828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
849828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
850828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
851828252d5SJiaqing Zhao             timeout.cancel();
852828252d5SJiaqing Zhao             if (m.is_method_error())
853828252d5SJiaqing Zhao             {
85462598e31SEd Tanous                 BMCWEB_LOG_ERROR("Dbus method error!!!");
855828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
856828252d5SJiaqing Zhao                 return;
857828252d5SJiaqing Zhao             }
858828252d5SJiaqing Zhao 
85980f79a40SMichael Shen             dbus::utility::DBusInterfacesMap interfacesProperties;
860828252d5SJiaqing Zhao 
861828252d5SJiaqing Zhao             sdbusplus::message::object_path csrObjectPath;
862828252d5SJiaqing Zhao             m.read(csrObjectPath, interfacesProperties);
86362598e31SEd Tanous             BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
864828252d5SJiaqing Zhao             for (const auto& interface : interfacesProperties)
865828252d5SJiaqing Zhao             {
866828252d5SJiaqing Zhao                 if (interface.first == "xyz.openbmc_project.Certs.CSR")
867828252d5SJiaqing Zhao                 {
868828252d5SJiaqing Zhao                     getCSR(asyncResp, certURI, service, objectPath,
869828252d5SJiaqing Zhao                            csrObjectPath.str);
870828252d5SJiaqing Zhao                     break;
871828252d5SJiaqing Zhao                 }
872828252d5SJiaqing Zhao             }
873828252d5SJiaqing Zhao         });
874828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
8755e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec, const std::string&) {
876828252d5SJiaqing Zhao             if (ec)
877828252d5SJiaqing Zhao             {
87862598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
879828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
880828252d5SJiaqing Zhao                 return;
881828252d5SJiaqing Zhao             }
882828252d5SJiaqing Zhao         },
883828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
884828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
885828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
886828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
887828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
888828252d5SJiaqing Zhao         *optUnstructuredName);
889828252d5SJiaqing Zhao }
890828252d5SJiaqing Zhao 
891828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
892828252d5SJiaqing Zhao {
893828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
894828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
895002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
896828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
897828252d5SJiaqing Zhao 
898828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
899828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
900828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
901828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
902828252d5SJiaqing Zhao 
903828252d5SJiaqing Zhao     BMCWEB_ROUTE(
904828252d5SJiaqing Zhao         app,
905828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
906828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
907828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
908828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
909828252d5SJiaqing Zhao 
910828252d5SJiaqing Zhao     BMCWEB_ROUTE(
911828252d5SJiaqing Zhao         app,
912828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
913828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
914828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
915828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
916828252d5SJiaqing Zhao } // requestRoutesCertificateService
917828252d5SJiaqing Zhao 
918828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
919828252d5SJiaqing Zhao     App& app, const crow::Request& req,
920253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
921253f11b8SEd Tanous     const std::string& managerId)
922828252d5SJiaqing Zhao {
9233ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
92445ca1b86SEd Tanous     {
92545ca1b86SEd Tanous         return;
92645ca1b86SEd Tanous     }
9271476687dSEd Tanous 
928253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
929253f11b8SEd Tanous     {
930253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
931253f11b8SEd Tanous         return;
932253f11b8SEd Tanous     }
933253f11b8SEd Tanous 
934253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
935253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
936253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME);
9371476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
9381476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
9391476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
9401476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
9411476687dSEd Tanous         "A Collection of HTTPS certificate instances";
9428d1b46d7Szhanghch05 
943d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
944d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
945d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
946828252d5SJiaqing Zhao }
9475968caeeSMarri Devender Rao 
948828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
949828252d5SJiaqing Zhao     App& app, const crow::Request& req,
950253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
951253f11b8SEd Tanous     const std::string& managerId)
952828252d5SJiaqing Zhao {
9533ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
95445ca1b86SEd Tanous     {
95545ca1b86SEd Tanous         return;
95645ca1b86SEd Tanous     }
957253f11b8SEd Tanous 
958253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
959253f11b8SEd Tanous     {
960253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
961253f11b8SEd Tanous         return;
962253f11b8SEd Tanous     }
963253f11b8SEd Tanous 
96462598e31SEd Tanous     BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
9658d1b46d7Szhanghch05 
9661476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
9671476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
9685968caeeSMarri Devender Rao 
969b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
97058eb238fSKowalski, Kamil 
971b2896149SEd Tanous     if (certHttpBody.empty())
97258eb238fSKowalski, Kamil     {
97362598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
974a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
97558eb238fSKowalski, Kamil         return;
97658eb238fSKowalski, Kamil     }
97758eb238fSKowalski, Kamil 
9785968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
979b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
9805968caeeSMarri Devender Rao 
9815968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
9825e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
983656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9845968caeeSMarri Devender Rao             if (ec)
9855968caeeSMarri Devender Rao             {
98662598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
9875968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
9885968caeeSMarri Devender Rao                 return;
9895968caeeSMarri Devender Rao             }
990717b9802SJiaqing Zhao 
991717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
992717b9802SJiaqing Zhao             std::string certId = path.filename();
993ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
994253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
995253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
996bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath,
997bd79bce8SPatrick Williams                                      certs::httpsServiceName, certId, certURL,
998bd79bce8SPatrick Williams                                      "HTTPS Certificate");
99962598e31SEd Tanous             BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
100062598e31SEd Tanous                              certFile->getCertFilePath());
10015968caeeSMarri Devender Rao         },
1002828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
1003828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1004828252d5SJiaqing Zhao }
10055968caeeSMarri Devender Rao 
1006828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
1007828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1008253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1009253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
10107e860f15SJohn Edward Broadbent {
10113ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101245ca1b86SEd Tanous     {
101345ca1b86SEd Tanous         return;
101445ca1b86SEd Tanous     }
10157e860f15SJohn Edward Broadbent 
1016253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1017253f11b8SEd Tanous     {
1018253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1019253f11b8SEd Tanous         return;
1020253f11b8SEd Tanous     }
1021253f11b8SEd Tanous 
1022253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId);
1023ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1024253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
1025253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1026828252d5SJiaqing Zhao     std::string objPath =
1027253f11b8SEd Tanous         sdbusplus::message::object_path(certs::httpsObjectPath) / certId;
1028253f11b8SEd Tanous     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName,
1029253f11b8SEd Tanous                              certId, certURL, "HTTPS Certificate");
10307e860f15SJohn Edward Broadbent }
103137cce918SMarri Devender Rao 
1032828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
103337cce918SMarri Devender Rao {
1034253f11b8SEd Tanous     BMCWEB_ROUTE(
1035253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
1036ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
1037828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1038828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
1039828252d5SJiaqing Zhao 
1040253f11b8SEd Tanous     BMCWEB_ROUTE(
1041253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
1042828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1043828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1044828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
1045828252d5SJiaqing Zhao 
1046828252d5SJiaqing Zhao     BMCWEB_ROUTE(
1047828252d5SJiaqing Zhao         app,
1048253f11b8SEd Tanous         "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/")
1049828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1050002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1051828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
1052828252d5SJiaqing Zhao }
1053828252d5SJiaqing Zhao 
1054828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
1055828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1056828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1057828252d5SJiaqing Zhao {
10583ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
105945ca1b86SEd Tanous     {
106045ca1b86SEd Tanous         return;
106145ca1b86SEd Tanous     }
10621476687dSEd Tanous 
10631476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
10641476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
10651476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
10661476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
10671476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10681476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
10691476687dSEd Tanous         "A Collection of LDAP certificate instances";
10708d1b46d7Szhanghch05 
1071d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
1072d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1073d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1074828252d5SJiaqing Zhao }
107537cce918SMarri Devender Rao 
1076828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1077828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1078828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1079828252d5SJiaqing Zhao {
10803ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
108145ca1b86SEd Tanous     {
108245ca1b86SEd Tanous         return;
108345ca1b86SEd Tanous     }
1084b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
108558eb238fSKowalski, Kamil 
1086b2896149SEd Tanous     if (certHttpBody.empty())
108758eb238fSKowalski, Kamil     {
108862598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1089a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
109058eb238fSKowalski, Kamil         return;
109158eb238fSKowalski, Kamil     }
109258eb238fSKowalski, Kamil 
109358eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
1094b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
109558eb238fSKowalski, Kamil 
109637cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
10975e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1098656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
109937cce918SMarri Devender Rao             if (ec)
110037cce918SMarri Devender Rao             {
110162598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
110237cce918SMarri Devender Rao                 messages::internalError(asyncResp->res);
110337cce918SMarri Devender Rao                 return;
110437cce918SMarri Devender Rao             }
1105717b9802SJiaqing Zhao 
1106717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
1107717b9802SJiaqing Zhao             std::string certId = path.filename();
1108ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
1109ef4c65b7SEd Tanous                 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
1110bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath,
1111bd79bce8SPatrick Williams                                      certs::ldapServiceName, certId, certURL,
1112bd79bce8SPatrick Williams                                      "LDAP Certificate");
111362598e31SEd Tanous             BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
111462598e31SEd Tanous                              certFile->getCertFilePath());
111537cce918SMarri Devender Rao         },
1116828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1117828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1118828252d5SJiaqing Zhao }
111937cce918SMarri Devender Rao 
1120828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1121828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1122828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
112337cce918SMarri Devender Rao {
11243ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
112545ca1b86SEd Tanous     {
112645ca1b86SEd Tanous         return;
112745ca1b86SEd Tanous     }
1128717b9802SJiaqing Zhao 
112962598e31SEd Tanous     BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
1130ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1131ef4c65b7SEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
1132717b9802SJiaqing Zhao     std::string objPath =
1133717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1134717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1135717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1136828252d5SJiaqing Zhao }
1137828252d5SJiaqing Zhao 
113899612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
113999612247SJiaqing Zhao     App& app, const crow::Request& req,
114099612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
114199612247SJiaqing Zhao {
114299612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
114399612247SJiaqing Zhao     {
114499612247SJiaqing Zhao         return;
114599612247SJiaqing Zhao     }
114699612247SJiaqing Zhao 
114762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
114899612247SJiaqing Zhao     std::string objPath =
114999612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
115099612247SJiaqing Zhao 
115199612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
115299612247SJiaqing Zhao }
115399612247SJiaqing Zhao 
1154828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1155cfcd5f6bSMarri Devender Rao {
1156828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1157828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1158828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1159828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1160828252d5SJiaqing Zhao 
1161828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1162828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1163828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1164828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1165828252d5SJiaqing Zhao 
1166828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1167ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1168002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1169828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
117099612247SJiaqing Zhao 
117199612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
117299612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
117399612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
117499612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1175828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1176828252d5SJiaqing Zhao 
1177828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1178828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1179253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1180253f11b8SEd Tanous     const std::string& managerId)
1181828252d5SJiaqing Zhao {
11823ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
118345ca1b86SEd Tanous     {
118445ca1b86SEd Tanous         return;
118545ca1b86SEd Tanous     }
11861476687dSEd Tanous 
1187253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1188253f11b8SEd Tanous     {
1189253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1190253f11b8SEd Tanous         return;
1191253f11b8SEd Tanous     }
1192253f11b8SEd Tanous 
11931476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
1194253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/",
1195253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
11961476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11971476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1198002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11991476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
12001476687dSEd Tanous         "A Collection of TrustStore certificate instances";
12018d1b46d7Szhanghch05 
1202d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1203d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1204d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1205828252d5SJiaqing Zhao }
1206cfcd5f6bSMarri Devender Rao 
1207828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1208828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1209253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1210253f11b8SEd Tanous     const std::string& managerId)
1211828252d5SJiaqing Zhao {
12123ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
121345ca1b86SEd Tanous     {
121445ca1b86SEd Tanous         return;
121545ca1b86SEd Tanous     }
1216253f11b8SEd Tanous 
1217253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1218253f11b8SEd Tanous     {
1219253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1220253f11b8SEd Tanous         return;
1221253f11b8SEd Tanous     }
1222253f11b8SEd Tanous 
1223b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
1224a08752f5SZbigniew Kurzynski 
1225b2896149SEd Tanous     if (certHttpBody.empty())
1226a08752f5SZbigniew Kurzynski     {
122762598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1228a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1229a08752f5SZbigniew Kurzynski         return;
1230a08752f5SZbigniew Kurzynski     }
1231a08752f5SZbigniew Kurzynski 
1232a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1233b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
1234cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
12355e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1236656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1237cfcd5f6bSMarri Devender Rao             if (ec)
1238cfcd5f6bSMarri Devender Rao             {
123962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
1240cfcd5f6bSMarri Devender Rao                 messages::internalError(asyncResp->res);
1241cfcd5f6bSMarri Devender Rao                 return;
1242cfcd5f6bSMarri Devender Rao             }
1243656ec7e3SZbigniew Kurzynski 
1244717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
1245717b9802SJiaqing Zhao             std::string certId = path.filename();
1246ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
1247253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1248253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1249717b9802SJiaqing Zhao             getCertificateProperties(asyncResp, objectPath,
1250bd79bce8SPatrick Williams                                      certs::authorityServiceName, certId,
1251bd79bce8SPatrick Williams                                      certURL, "TrustStore Certificate");
125262598e31SEd Tanous             BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
125362598e31SEd Tanous                              certFile->getCertFilePath());
1254cfcd5f6bSMarri Devender Rao         },
1255cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
12560fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1257828252d5SJiaqing Zhao }
1258cfcd5f6bSMarri Devender Rao 
1259828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1260828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1261253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1262253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1263cfcd5f6bSMarri Devender Rao {
12643ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
126545ca1b86SEd Tanous     {
126645ca1b86SEd Tanous         return;
126745ca1b86SEd Tanous     }
1268717b9802SJiaqing Zhao 
1269253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1270253f11b8SEd Tanous     {
1271253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1272253f11b8SEd Tanous         return;
1273253f11b8SEd Tanous     }
1274253f11b8SEd Tanous 
1275253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId);
1276ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1277253f11b8SEd Tanous         "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1278253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1279717b9802SJiaqing Zhao     std::string objPath =
1280253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
1281828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1282253f11b8SEd Tanous                              certId, certURL, "TrustStore Certificate");
1283828252d5SJiaqing Zhao }
128407a60299SZbigniew Kurzynski 
1285828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1286828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1287253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1288253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1289828252d5SJiaqing Zhao {
12903ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
129145ca1b86SEd Tanous     {
129245ca1b86SEd Tanous         return;
129345ca1b86SEd Tanous     }
129407a60299SZbigniew Kurzynski 
1295253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1296253f11b8SEd Tanous     {
1297253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1298253f11b8SEd Tanous         return;
1299253f11b8SEd Tanous     }
1300253f11b8SEd Tanous 
1301253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId);
1302717b9802SJiaqing Zhao     std::string objPath =
1303253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
130407a60299SZbigniew Kurzynski 
13057a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1306828252d5SJiaqing Zhao }
1307828252d5SJiaqing Zhao 
1308828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1309828252d5SJiaqing Zhao {
1310253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1311828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1312828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1313828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1314828252d5SJiaqing Zhao 
1315253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1316828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1317828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1318828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1319828252d5SJiaqing Zhao 
1320253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1321253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1322828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1323828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1324828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1325828252d5SJiaqing Zhao 
1326253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1327253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1328828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1329828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1330828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
13317e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
13325968caeeSMarri Devender Rao } // namespace redfish
1333