xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 253f11b84347de6bff7c6b624bef270fefae5f5a)
15968caeeSMarri Devender Rao #pragma once
25968caeeSMarri Devender Rao 
33ccb3adbSEd Tanous #include "app.hpp"
43ccb3adbSEd Tanous #include "async_resp.hpp"
57a1dbc48SGeorge Liu #include "dbus_utility.hpp"
61aa0c2b8SEd Tanous #include "http/parsing.hpp"
73ccb3adbSEd Tanous #include "http_response.hpp"
83ccb3adbSEd Tanous #include "query.hpp"
93ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
109b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp"
113ccb3adbSEd Tanous #include "utils/json_utils.hpp"
123ccb3adbSEd Tanous #include "utils/time_utils.hpp"
139b12d1f9SKrzysztof Grobelny 
1490d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp>
15ef4c65b7SEd Tanous #include <boost/url/format.hpp>
169b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
173ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
189b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
191214b7e7SGunnar Mills 
207a1dbc48SGeorge Liu #include <array>
213ccb3adbSEd Tanous #include <memory>
227a1dbc48SGeorge Liu #include <string_view>
237a1dbc48SGeorge Liu 
245968caeeSMarri Devender Rao namespace redfish
255968caeeSMarri Devender Rao {
265968caeeSMarri Devender Rao namespace certs
275968caeeSMarri Devender Rao {
2889492a15SPatrick Williams constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install";
2989492a15SPatrick Williams constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
3089492a15SPatrick Williams constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
3189492a15SPatrick Williams constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
3289492a15SPatrick Williams constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties";
3389492a15SPatrick Williams constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
3489492a15SPatrick Williams constexpr const char* httpsServiceName =
3537cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
3689492a15SPatrick Williams constexpr const char* ldapServiceName =
3737cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
3889492a15SPatrick Williams constexpr const char* authorityServiceName =
39b2254ccdSMichal Orzel     "xyz.openbmc_project.Certs.Manager.Authority.Truststore";
4089492a15SPatrick Williams constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs";
4189492a15SPatrick Williams constexpr const char* httpsObjectPath =
42c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
4389492a15SPatrick Williams constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
4489492a15SPatrick Williams constexpr const char* authorityObjectPath =
45b2254ccdSMichal Orzel     "/xyz/openbmc_project/certs/authority/truststore";
465968caeeSMarri Devender Rao } // namespace certs
475968caeeSMarri Devender Rao 
485968caeeSMarri Devender Rao /**
495968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
505968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
515968caeeSMarri Devender Rao  * are installed.
525968caeeSMarri Devender Rao  */
537e860f15SJohn Edward Broadbent 
548d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
558d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5658eb238fSKowalski, Kamil     const crow::Request& req)
5758eb238fSKowalski, Kamil {
581aa0c2b8SEd Tanous     nlohmann::json reqJson;
591aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, reqJson);
601aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
6158eb238fSKowalski, Kamil     {
6258eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
6333c6b580SEd Tanous         return req.body();
6458eb238fSKowalski, Kamil     }
6558eb238fSKowalski, Kamil 
6658eb238fSKowalski, Kamil     std::string certificate;
6758eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
6858eb238fSKowalski, Kamil 
6915ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
7015ed6780SWilly Tu                                   certificate, "CertificateType",
7115ed6780SWilly Tu                                   certificateType))
7258eb238fSKowalski, Kamil     {
7362598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
7458eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
75abb93cddSEd Tanous         return {};
7658eb238fSKowalski, Kamil     }
7758eb238fSKowalski, Kamil 
7858eb238fSKowalski, Kamil     if (*certificateType != "PEM")
7958eb238fSKowalski, Kamil     {
8058eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
8158eb238fSKowalski, Kamil                                          "CertificateType");
82abb93cddSEd Tanous         return {};
8358eb238fSKowalski, Kamil     }
8458eb238fSKowalski, Kamil 
8558eb238fSKowalski, Kamil     return certificate;
8658eb238fSKowalski, Kamil }
8758eb238fSKowalski, Kamil 
885968caeeSMarri Devender Rao /**
895968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
905968caeeSMarri Devender Rao  */
915968caeeSMarri Devender Rao class CertificateFile
925968caeeSMarri Devender Rao {
935968caeeSMarri Devender Rao   public:
945968caeeSMarri Devender Rao     CertificateFile() = delete;
955968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
965968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
975968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
985968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
994e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
1005968caeeSMarri Devender Rao     {
10172d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1025207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1035207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1045207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
105e662eae8SEd Tanous         if (tempDirectory != nullptr)
1065968caeeSMarri Devender Rao         {
1075968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1085968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1095968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1105968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1115968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1125968caeeSMarri Devender Rao             out << certString;
1135968caeeSMarri Devender Rao             out.close();
11462598e31SEd Tanous             BMCWEB_LOG_DEBUG("Creating certificate file{}",
11562598e31SEd Tanous                              certificateFile.string());
1165968caeeSMarri Devender Rao         }
1175968caeeSMarri Devender Rao     }
1185968caeeSMarri Devender Rao     ~CertificateFile()
1195968caeeSMarri Devender Rao     {
1205968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1215968caeeSMarri Devender Rao         {
12262598e31SEd Tanous             BMCWEB_LOG_DEBUG("Removing certificate file{}",
12362598e31SEd Tanous                              certificateFile.string());
12423a21a1cSEd Tanous             std::error_code ec;
12523a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
12623a21a1cSEd Tanous             if (ec)
1275968caeeSMarri Devender Rao             {
12862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to remove temp directory{}",
12962598e31SEd Tanous                                  certDirectory.string());
1305968caeeSMarri Devender Rao             }
1315968caeeSMarri Devender Rao         }
1325968caeeSMarri Devender Rao     }
1335968caeeSMarri Devender Rao     std::string getCertFilePath()
1345968caeeSMarri Devender Rao     {
1355968caeeSMarri Devender Rao         return certificateFile;
1365968caeeSMarri Devender Rao     }
1375968caeeSMarri Devender Rao 
1385968caeeSMarri Devender Rao   private:
1395968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1405968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1415968caeeSMarri Devender Rao };
1425968caeeSMarri Devender Rao 
1435968caeeSMarri Devender Rao /**
1444e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1455968caeeSMarri Devender Rao  *
1465968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1475968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1485968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1495968caeeSMarri Devender Rao  * @return None
1505968caeeSMarri Devender Rao  */
1515968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
15226ccae32SEd Tanous                                       std::string_view value)
1535968caeeSMarri Devender Rao {
1545968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1555968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1565968caeeSMarri Devender Rao     while (i != value.end())
1575968caeeSMarri Devender Rao     {
1585968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1595968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1605968caeeSMarri Devender Rao         {
1616da47babSPatrick Williams             std::advance(i, 1);
1625968caeeSMarri Devender Rao         }
1635968caeeSMarri Devender Rao         if (i == value.end())
1645968caeeSMarri Devender Rao         {
1655968caeeSMarri Devender Rao             break;
1665968caeeSMarri Devender Rao         }
16726ccae32SEd Tanous         std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin));
1686da47babSPatrick Williams         std::advance(i, 1);
1695968caeeSMarri Devender Rao         tokenBegin = i;
1705968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
1715968caeeSMarri Devender Rao         {
1726da47babSPatrick Williams             std::advance(i, 1);
1735968caeeSMarri Devender Rao         }
17426ccae32SEd Tanous         std::string_view val(tokenBegin, 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         {
2026da47babSPatrick Williams             std::advance(i, 1);
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         {
23162598e31SEd Tanous             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             {
24462598e31SEd Tanous                 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             {
251ef4c65b7SEd Tanous                 certURL = boost::urls::format(
252*253f11b8SEd Tanous                     "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
253*253f11b8SEd Tanous                     BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
254d3f92ce7SJiaqing Zhao             }
255d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::ldapObjectPath)
256d3f92ce7SJiaqing Zhao             {
257ef4c65b7SEd Tanous                 certURL = boost::urls::format(
258ef4c65b7SEd Tanous                     "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
259d3f92ce7SJiaqing Zhao             }
260d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::authorityObjectPath)
261d3f92ce7SJiaqing Zhao             {
262ef4c65b7SEd Tanous                 certURL = boost::urls::format(
263*253f11b8SEd Tanous                     "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
264*253f11b8SEd Tanous                     BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
265d3f92ce7SJiaqing Zhao             }
266d3f92ce7SJiaqing Zhao             else
267d3f92ce7SJiaqing Zhao             {
268d3f92ce7SJiaqing Zhao                 continue;
269d3f92ce7SJiaqing Zhao             }
270d3f92ce7SJiaqing Zhao 
271d3f92ce7SJiaqing Zhao             nlohmann::json::object_t link;
272d3f92ce7SJiaqing Zhao             link["@odata.id"] = certURL;
273d3f92ce7SJiaqing Zhao             links.emplace_back(std::move(link));
274d3f92ce7SJiaqing Zhao         }
275d3f92ce7SJiaqing Zhao 
276d3f92ce7SJiaqing Zhao         asyncResp->res.jsonValue[countPtr] = links.size();
2777a1dbc48SGeorge Liu     });
278d3f92ce7SJiaqing Zhao }
279d3f92ce7SJiaqing Zhao 
280d3f92ce7SJiaqing Zhao /**
2815968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
2825968caeeSMarri Devender Rao  * message
2835968caeeSMarri Devender Rao  *
2845968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
2855968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
2865968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
2875968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
2885968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
2895968caeeSMarri Devender Rao  * @return None
2905968caeeSMarri Devender Rao  */
2915968caeeSMarri Devender Rao static void getCertificateProperties(
2928d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
293e19e97e2SJiaqing Zhao     const std::string& objectPath, const std::string& service,
2941e312598SJiaqing Zhao     const std::string& certId, const boost::urls::url& certURL,
295e19e97e2SJiaqing Zhao     const std::string& name)
2965968caeeSMarri Devender Rao {
29762598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}",
29862598e31SEd Tanous                      objectPath, certId, certURL);
2999b12d1f9SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
3009b12d1f9SKrzysztof Grobelny         *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
301b9d36b47SEd Tanous         [asyncResp, certURL, certId,
3025e7e2dc5SEd Tanous          name](const boost::system::error_code& ec,
303b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
3045968caeeSMarri Devender Rao         if (ec)
3055968caeeSMarri Devender Rao         {
30662598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
307d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", certId);
3085968caeeSMarri Devender Rao             return;
3095968caeeSMarri Devender Rao         }
3109b12d1f9SKrzysztof Grobelny 
3119b12d1f9SKrzysztof Grobelny         const std::string* certificateString = nullptr;
3129b12d1f9SKrzysztof Grobelny         const std::vector<std::string>* keyUsage = nullptr;
3139b12d1f9SKrzysztof Grobelny         const std::string* issuer = nullptr;
3149b12d1f9SKrzysztof Grobelny         const std::string* subject = nullptr;
3159b12d1f9SKrzysztof Grobelny         const uint64_t* validNotAfter = nullptr;
3169b12d1f9SKrzysztof Grobelny         const uint64_t* validNotBefore = nullptr;
3179b12d1f9SKrzysztof Grobelny 
3189b12d1f9SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
3199b12d1f9SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "CertificateString",
3209b12d1f9SKrzysztof Grobelny             certificateString, "KeyUsage", keyUsage, "Issuer", issuer,
3219b12d1f9SKrzysztof Grobelny             "Subject", subject, "ValidNotAfter", validNotAfter,
3229b12d1f9SKrzysztof Grobelny             "ValidNotBefore", validNotBefore);
3239b12d1f9SKrzysztof Grobelny 
3249b12d1f9SKrzysztof Grobelny         if (!success)
3259b12d1f9SKrzysztof Grobelny         {
3269b12d1f9SKrzysztof Grobelny             messages::internalError(asyncResp->res);
3279b12d1f9SKrzysztof Grobelny             return;
3289b12d1f9SKrzysztof Grobelny         }
3299b12d1f9SKrzysztof Grobelny 
3301476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = certURL;
3311476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
3321476687dSEd Tanous             "#Certificate.v1_0_0.Certificate";
333e19e97e2SJiaqing Zhao         asyncResp->res.jsonValue["Id"] = certId;
3341476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = name;
3351476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = name;
3365968caeeSMarri Devender Rao         asyncResp->res.jsonValue["CertificateString"] = "";
3379b12d1f9SKrzysztof Grobelny         asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
3389b12d1f9SKrzysztof Grobelny 
3399b12d1f9SKrzysztof Grobelny         if (certificateString != nullptr)
3405968caeeSMarri Devender Rao         {
3419b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["CertificateString"] = *certificateString;
3425968caeeSMarri Devender Rao         }
3439b12d1f9SKrzysztof Grobelny 
3449b12d1f9SKrzysztof Grobelny         if (keyUsage != nullptr)
3455968caeeSMarri Devender Rao         {
3469b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
3475968caeeSMarri Devender Rao         }
3489b12d1f9SKrzysztof Grobelny 
3499b12d1f9SKrzysztof Grobelny         if (issuer != nullptr)
3505968caeeSMarri Devender Rao         {
3519b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
3529b12d1f9SKrzysztof Grobelny                                       *issuer);
3535968caeeSMarri Devender Rao         }
3549b12d1f9SKrzysztof Grobelny 
3559b12d1f9SKrzysztof Grobelny         if (subject != nullptr)
3565968caeeSMarri Devender Rao         {
3579b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
3589b12d1f9SKrzysztof Grobelny                                       *subject);
3595968caeeSMarri Devender Rao         }
3609b12d1f9SKrzysztof Grobelny 
3619b12d1f9SKrzysztof Grobelny         if (validNotAfter != nullptr)
3625968caeeSMarri Devender Rao         {
3635968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotAfter"] =
3649b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotAfter);
3655968caeeSMarri Devender Rao         }
3669b12d1f9SKrzysztof Grobelny 
3679b12d1f9SKrzysztof Grobelny         if (validNotBefore != nullptr)
3685968caeeSMarri Devender Rao         {
3695968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotBefore"] =
3709b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotBefore);
3715968caeeSMarri Devender Rao         }
3729b12d1f9SKrzysztof Grobelny 
3731e312598SJiaqing Zhao         asyncResp->res.addHeader(
374d9f6c621SEd Tanous             boost::beast::http::field::location,
375d9f6c621SEd Tanous             std::string_view(certURL.data(), certURL.size()));
3769b12d1f9SKrzysztof Grobelny     });
3775968caeeSMarri Devender Rao }
3785968caeeSMarri Devender Rao 
3797a3a8f7aSJiaqing Zhao static void
3807a3a8f7aSJiaqing Zhao     deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3817a3a8f7aSJiaqing Zhao                       const std::string& service,
3827a3a8f7aSJiaqing Zhao                       const sdbusplus::message::object_path& objectPath)
3837a3a8f7aSJiaqing Zhao {
3847a3a8f7aSJiaqing Zhao     crow::connections::systemBus->async_method_call(
3857a3a8f7aSJiaqing Zhao         [asyncResp,
3865e7e2dc5SEd Tanous          id{objectPath.filename()}](const boost::system::error_code& ec) {
3877a3a8f7aSJiaqing Zhao         if (ec)
3887a3a8f7aSJiaqing Zhao         {
3897a3a8f7aSJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", id);
3907a3a8f7aSJiaqing Zhao             return;
3917a3a8f7aSJiaqing Zhao         }
39262598e31SEd Tanous         BMCWEB_LOG_INFO("Certificate deleted");
3937a3a8f7aSJiaqing Zhao         asyncResp->res.result(boost::beast::http::status::no_content);
3947a3a8f7aSJiaqing Zhao     },
3957a3a8f7aSJiaqing Zhao         service, objectPath, certs::objDeleteIntf, "Delete");
3967a3a8f7aSJiaqing Zhao }
3977a3a8f7aSJiaqing Zhao 
398828252d5SJiaqing Zhao inline void handleCertificateServiceGet(
399828252d5SJiaqing Zhao     App& app, const crow::Request& req,
400828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4015968caeeSMarri Devender Rao {
402828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
403828252d5SJiaqing Zhao     {
404828252d5SJiaqing Zhao         return;
405828252d5SJiaqing Zhao     }
406828252d5SJiaqing Zhao 
4073e72c202SNinad Palsule     if (req.session == nullptr)
4083e72c202SNinad Palsule     {
4093e72c202SNinad Palsule         messages::internalError(asyncResp->res);
4103e72c202SNinad Palsule         return;
4113e72c202SNinad Palsule     }
4123e72c202SNinad Palsule 
413828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
414828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
415828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
416828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
417828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
418828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
419828252d5SJiaqing Zhao         "Actions available to manage certificates";
420828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
421828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
422828252d5SJiaqing Zhao     // has permissions ConfigureManager
423828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
4243e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
425828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
426828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
427828252d5SJiaqing Zhao     {
428828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
429828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
430828252d5SJiaqing Zhao     }
431828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
432828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
433828252d5SJiaqing Zhao     replace["target"] =
434828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
435828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
436ad539545SPatrick Williams     allowed.emplace_back("PEM");
437828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
438828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
439828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
440828252d5SJiaqing Zhao }
441828252d5SJiaqing Zhao 
442828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
443828252d5SJiaqing Zhao     App& app, const crow::Request& req,
444828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
445828252d5SJiaqing Zhao {
446828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
447828252d5SJiaqing Zhao     {
448828252d5SJiaqing Zhao         return;
449828252d5SJiaqing Zhao     }
450828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
451828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
452828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
453828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
454828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
455828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
456828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
457828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
458828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
459828252d5SJiaqing Zhao 
460828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
461828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
462828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
463828252d5SJiaqing Zhao }
464828252d5SJiaqing Zhao 
465828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
466828252d5SJiaqing Zhao     App& app, const crow::Request& req,
467828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
468828252d5SJiaqing Zhao {
4693ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
47045ca1b86SEd Tanous     {
47145ca1b86SEd Tanous         return;
47245ca1b86SEd Tanous     }
4735968caeeSMarri Devender Rao     std::string certificate;
4747a31e336SEd Tanous     std::string certURI;
4755968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
4768d1b46d7Szhanghch05 
477002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
4787a31e336SEd Tanous                                    certificate, "CertificateUri/@odata.id",
4797a31e336SEd Tanous                                    certURI, "CertificateType", certificateType))
4805968caeeSMarri Devender Rao     {
48162598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
4825968caeeSMarri Devender Rao         return;
4835968caeeSMarri Devender Rao     }
4845968caeeSMarri Devender Rao 
4855968caeeSMarri Devender Rao     if (!certificateType)
4865968caeeSMarri Devender Rao     {
4875968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
4885968caeeSMarri Devender Rao         return;
4895968caeeSMarri Devender Rao     }
4905968caeeSMarri Devender Rao     if (certificateType != "PEM")
4915968caeeSMarri Devender Rao     {
492828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
493828252d5SJiaqing Zhao                                               "ReplaceCertificate");
4945968caeeSMarri Devender Rao         return;
4955968caeeSMarri Devender Rao     }
4965968caeeSMarri Devender Rao 
49762598e31SEd Tanous     BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI);
4985968caeeSMarri Devender Rao 
4996fd29553SEd Tanous     boost::system::result<boost::urls::url> parsedUrl =
50075b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
50175b63a2cSJiaqing Zhao     if (!parsedUrl)
5025968caeeSMarri Devender Rao     {
503828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
504828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
5055968caeeSMarri Devender Rao         return;
5065968caeeSMarri Devender Rao     }
50775b63a2cSJiaqing Zhao 
50875b63a2cSJiaqing Zhao     std::string id;
50975b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
5105968caeeSMarri Devender Rao     std::string name;
51137cce918SMarri Devender Rao     std::string service;
512828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
513828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
514828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5155968caeeSMarri Devender Rao     {
51689492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) /
51789492a15SPatrick Williams                      id;
5185968caeeSMarri Devender Rao         name = "HTTPS certificate";
51937cce918SMarri Devender Rao         service = certs::httpsServiceName;
52037cce918SMarri Devender Rao     }
52175b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
52275b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
52375b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
52437cce918SMarri Devender Rao     {
52589492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) /
52689492a15SPatrick Williams                      id;
52737cce918SMarri Devender Rao         name = "LDAP certificate";
52837cce918SMarri Devender Rao         service = certs::ldapServiceName;
5295968caeeSMarri Devender Rao     }
53075b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
53175b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
53275b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
533cfcd5f6bSMarri Devender Rao     {
53475b63a2cSJiaqing Zhao         objectPath =
535828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
536cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
537cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
538cfcd5f6bSMarri Devender Rao     }
5395968caeeSMarri Devender Rao     else
5405968caeeSMarri Devender Rao     {
541828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
542828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5435968caeeSMarri Devender Rao         return;
5445968caeeSMarri Devender Rao     }
5455968caeeSMarri Devender Rao 
5465968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
5475968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
5485968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
5491e312598SJiaqing Zhao         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
5505e7e2dc5SEd Tanous          name](const boost::system::error_code& ec) {
5515968caeeSMarri Devender Rao         if (ec)
5525968caeeSMarri Devender Rao         {
55362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
55490d2d1e8SJiaqing Zhao             if (ec.value() ==
55590d2d1e8SJiaqing Zhao                 boost::system::linux_error::bad_request_descriptor)
55690d2d1e8SJiaqing Zhao             {
557828252d5SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
5585968caeeSMarri Devender Rao                 return;
5595968caeeSMarri Devender Rao             }
56090d2d1e8SJiaqing Zhao             messages::internalError(asyncResp->res);
56190d2d1e8SJiaqing Zhao             return;
56290d2d1e8SJiaqing Zhao         }
563828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, service, id, url, name);
56462598e31SEd Tanous         BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
56562598e31SEd Tanous                          certFile->getCertFilePath());
5665968caeeSMarri Devender Rao     },
5675968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
5685968caeeSMarri Devender Rao         certFile->getCertFilePath());
569828252d5SJiaqing Zhao }
5705968caeeSMarri Devender Rao 
571cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
572828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
5735968caeeSMarri Devender Rao /**
574828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
575828252d5SJiaqing Zhao  *
576828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
5778ece0e45SEd Tanous  * @param[in] certURI Link to certificate collection URI
578828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
579828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
580828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
581828252d5SJiaqing Zhao  * @return None
5825968caeeSMarri Devender Rao  */
583828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
584828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
585828252d5SJiaqing Zhao                    const std::string& certObjPath,
586828252d5SJiaqing Zhao                    const std::string& csrObjPath)
5875968caeeSMarri Devender Rao {
58862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}",
58962598e31SEd Tanous                      certObjPath, csrObjPath, service);
590828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
5915e7e2dc5SEd Tanous         [asyncResp, certURI](const boost::system::error_code& ec,
592828252d5SJiaqing Zhao                              const std::string& csr) {
593828252d5SJiaqing Zhao         if (ec)
594828252d5SJiaqing Zhao         {
59562598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
596828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
597828252d5SJiaqing Zhao             return;
598828252d5SJiaqing Zhao         }
599828252d5SJiaqing Zhao         if (csr.empty())
600828252d5SJiaqing Zhao         {
60162598e31SEd Tanous             BMCWEB_LOG_ERROR("CSR read is empty");
602828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
603828252d5SJiaqing Zhao             return;
604828252d5SJiaqing Zhao         }
605828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CSRString"] = csr;
606828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
607828252d5SJiaqing Zhao             certURI;
608828252d5SJiaqing Zhao     },
609828252d5SJiaqing Zhao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
610828252d5SJiaqing Zhao }
611828252d5SJiaqing Zhao 
612828252d5SJiaqing Zhao inline void
613828252d5SJiaqing Zhao     handleGenerateCSRAction(App& app, const crow::Request& req,
614828252d5SJiaqing Zhao                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
615828252d5SJiaqing Zhao {
6163ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
61745ca1b86SEd Tanous     {
61845ca1b86SEd Tanous         return;
61945ca1b86SEd Tanous     }
620828252d5SJiaqing Zhao     static const int rsaKeyBitLength = 2048;
6215968caeeSMarri Devender Rao 
622828252d5SJiaqing Zhao     // Required parameters
623828252d5SJiaqing Zhao     std::string city;
624828252d5SJiaqing Zhao     std::string commonName;
625828252d5SJiaqing Zhao     std::string country;
626828252d5SJiaqing Zhao     std::string organization;
627828252d5SJiaqing Zhao     std::string organizationalUnit;
628828252d5SJiaqing Zhao     std::string state;
6297a31e336SEd Tanous     std::string certURI;
630828252d5SJiaqing Zhao 
631828252d5SJiaqing Zhao     // Optional parameters
632828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optAlternativeNames =
633828252d5SJiaqing Zhao         std::vector<std::string>();
634828252d5SJiaqing Zhao     std::optional<std::string> optContactPerson = "";
635828252d5SJiaqing Zhao     std::optional<std::string> optChallengePassword = "";
636828252d5SJiaqing Zhao     std::optional<std::string> optEmail = "";
637828252d5SJiaqing Zhao     std::optional<std::string> optGivenName = "";
638828252d5SJiaqing Zhao     std::optional<std::string> optInitials = "";
639828252d5SJiaqing Zhao     std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
640828252d5SJiaqing Zhao     std::optional<std::string> optKeyCurveId = "secp384r1";
641828252d5SJiaqing Zhao     std::optional<std::string> optKeyPairAlgorithm = "EC";
642828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optKeyUsage =
643828252d5SJiaqing Zhao         std::vector<std::string>();
644828252d5SJiaqing Zhao     std::optional<std::string> optSurname = "";
645828252d5SJiaqing Zhao     std::optional<std::string> optUnstructuredName = "";
646828252d5SJiaqing Zhao     if (!json_util::readJsonAction(
647828252d5SJiaqing Zhao             req, asyncResp->res, "City", city, "CommonName", commonName,
648828252d5SJiaqing Zhao             "ContactPerson", optContactPerson, "Country", country,
649828252d5SJiaqing Zhao             "Organization", organization, "OrganizationalUnit",
6507a31e336SEd Tanous             organizationalUnit, "State", state,
6517a31e336SEd Tanous             "CertificateCollection/@odata.id", certURI, "AlternativeNames",
6527a31e336SEd Tanous             optAlternativeNames, "ChallengePassword", optChallengePassword,
6537a31e336SEd Tanous             "Email", optEmail, "GivenName", optGivenName, "Initials",
6547a31e336SEd Tanous             optInitials, "KeyBitLength", optKeyBitLength, "KeyCurveId",
6557a31e336SEd Tanous             optKeyCurveId, "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
6567a31e336SEd Tanous             optKeyUsage, "Surname", optSurname, "UnstructuredName",
6577a31e336SEd Tanous             optUnstructuredName))
658828252d5SJiaqing Zhao     {
659828252d5SJiaqing Zhao         return;
6605968caeeSMarri Devender Rao     }
6615968caeeSMarri Devender Rao 
662828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
663828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
664828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
665828252d5SJiaqing Zhao     // value
666828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
6675968caeeSMarri Devender Rao     {
668828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
669828252d5SJiaqing Zhao                                               "ChallengePassword");
670828252d5SJiaqing Zhao         return;
671828252d5SJiaqing Zhao     }
672828252d5SJiaqing Zhao 
673828252d5SJiaqing Zhao     std::string objectPath;
674828252d5SJiaqing Zhao     std::string service;
675*253f11b8SEd Tanous     if (certURI.starts_with(std::format(
676*253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
677*253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
678828252d5SJiaqing Zhao     {
679828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
680828252d5SJiaqing Zhao         service = certs::httpsServiceName;
681828252d5SJiaqing Zhao     }
682828252d5SJiaqing Zhao     else if (certURI.starts_with(
683828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
684828252d5SJiaqing Zhao     {
685828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
686828252d5SJiaqing Zhao         service = certs::ldapServiceName;
687828252d5SJiaqing Zhao     }
688828252d5SJiaqing Zhao     else
689828252d5SJiaqing Zhao     {
690828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
691828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
692828252d5SJiaqing Zhao         return;
693828252d5SJiaqing Zhao     }
694828252d5SJiaqing Zhao 
695828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
696828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
697828252d5SJiaqing Zhao     {
698828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
699828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
700828252d5SJiaqing Zhao         return;
701828252d5SJiaqing Zhao     }
702828252d5SJiaqing Zhao 
703828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
704828252d5SJiaqing Zhao     // time consumed in generating private key
705828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
706828252d5SJiaqing Zhao     {
707e2616cc5SEd Tanous         messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
708e2616cc5SEd Tanous                                          "KeyBitLength");
709828252d5SJiaqing Zhao         return;
710828252d5SJiaqing Zhao     }
711828252d5SJiaqing Zhao 
712828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
713*253f11b8SEd Tanous     if (certURI.starts_with(std::format(
714*253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
715*253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
716828252d5SJiaqing Zhao     {
717828252d5SJiaqing Zhao         if (optKeyUsage->empty())
718828252d5SJiaqing Zhao         {
719b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ServerAuthentication");
720828252d5SJiaqing Zhao         }
721828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
722828252d5SJiaqing Zhao         {
723828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
724828252d5SJiaqing Zhao             {
725828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
726828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
727828252d5SJiaqing Zhao                 return;
728828252d5SJiaqing Zhao             }
729828252d5SJiaqing Zhao         }
730828252d5SJiaqing Zhao         else
731828252d5SJiaqing Zhao         {
732828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
733828252d5SJiaqing Zhao                                                   "GenerateCSR");
734828252d5SJiaqing Zhao             return;
735828252d5SJiaqing Zhao         }
736828252d5SJiaqing Zhao     }
737828252d5SJiaqing Zhao     else if (certURI.starts_with(
738828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
739828252d5SJiaqing Zhao     {
740828252d5SJiaqing Zhao         if (optKeyUsage->empty())
741828252d5SJiaqing Zhao         {
742b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ClientAuthentication");
743828252d5SJiaqing Zhao         }
744828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
745828252d5SJiaqing Zhao         {
746828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
747828252d5SJiaqing Zhao             {
748828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
749828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
750828252d5SJiaqing Zhao                 return;
751828252d5SJiaqing Zhao             }
752828252d5SJiaqing Zhao         }
753828252d5SJiaqing Zhao         else
754828252d5SJiaqing Zhao         {
755828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
756828252d5SJiaqing Zhao                                                   "GenerateCSR");
757828252d5SJiaqing Zhao             return;
758828252d5SJiaqing Zhao         }
759828252d5SJiaqing Zhao     }
760828252d5SJiaqing Zhao 
761828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
762828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
763828252d5SJiaqing Zhao     static const int timeOut = 10;
764828252d5SJiaqing Zhao     if (csrMatcher)
765828252d5SJiaqing Zhao     {
766828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
767828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
768828252d5SJiaqing Zhao         return;
769828252d5SJiaqing Zhao     }
770828252d5SJiaqing Zhao 
7718e8245dbSEd Tanous     if (req.ioService == nullptr)
7728e8245dbSEd Tanous     {
7738e8245dbSEd Tanous         messages::internalError(asyncResp->res);
7748e8245dbSEd Tanous         return;
7758e8245dbSEd Tanous     }
7768e8245dbSEd Tanous 
777828252d5SJiaqing Zhao     // Make this static so it survives outside this method
778828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
779828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
780828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
781828252d5SJiaqing Zhao         csrMatcher = nullptr;
782828252d5SJiaqing Zhao         if (ec)
783828252d5SJiaqing Zhao         {
784828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
785828252d5SJiaqing Zhao             // before completion.
786828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
787828252d5SJiaqing Zhao             {
78862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
789828252d5SJiaqing Zhao             }
790828252d5SJiaqing Zhao             return;
791828252d5SJiaqing Zhao         }
79262598e31SEd Tanous         BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
793828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
794828252d5SJiaqing Zhao     });
795828252d5SJiaqing Zhao 
796828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
79762598e31SEd Tanous     BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
798828252d5SJiaqing Zhao     std::string match("type='signal',"
799828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
800828252d5SJiaqing Zhao                       "path='" +
801828252d5SJiaqing Zhao                       objectPath +
802828252d5SJiaqing Zhao                       "',"
803828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
804828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
805828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
806828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
807828252d5SJiaqing Zhao         timeout.cancel();
808828252d5SJiaqing Zhao         if (m.is_method_error())
809828252d5SJiaqing Zhao         {
81062598e31SEd Tanous             BMCWEB_LOG_ERROR("Dbus method error!!!");
811828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
812828252d5SJiaqing Zhao             return;
813828252d5SJiaqing Zhao         }
814828252d5SJiaqing Zhao 
81580f79a40SMichael Shen         dbus::utility::DBusInterfacesMap interfacesProperties;
816828252d5SJiaqing Zhao 
817828252d5SJiaqing Zhao         sdbusplus::message::object_path csrObjectPath;
818828252d5SJiaqing Zhao         m.read(csrObjectPath, interfacesProperties);
81962598e31SEd Tanous         BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
820828252d5SJiaqing Zhao         for (const auto& interface : interfacesProperties)
821828252d5SJiaqing Zhao         {
822828252d5SJiaqing Zhao             if (interface.first == "xyz.openbmc_project.Certs.CSR")
823828252d5SJiaqing Zhao             {
824828252d5SJiaqing Zhao                 getCSR(asyncResp, certURI, service, objectPath,
825828252d5SJiaqing Zhao                        csrObjectPath.str);
826828252d5SJiaqing Zhao                 break;
827828252d5SJiaqing Zhao             }
828828252d5SJiaqing Zhao         }
829828252d5SJiaqing Zhao     });
830828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
8315e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec, const std::string&) {
832828252d5SJiaqing Zhao         if (ec)
833828252d5SJiaqing Zhao         {
83462598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
835828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
836828252d5SJiaqing Zhao             return;
837828252d5SJiaqing Zhao         }
838828252d5SJiaqing Zhao     },
839828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
840828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
841828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
842828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
843828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
844828252d5SJiaqing Zhao         *optUnstructuredName);
845828252d5SJiaqing Zhao }
846828252d5SJiaqing Zhao 
847828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
848828252d5SJiaqing Zhao {
849828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
850828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
851002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
852828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
853828252d5SJiaqing Zhao 
854828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
855828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
856828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
857828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
858828252d5SJiaqing Zhao 
859828252d5SJiaqing Zhao     BMCWEB_ROUTE(
860828252d5SJiaqing Zhao         app,
861828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
862828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
863828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
864828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
865828252d5SJiaqing Zhao 
866828252d5SJiaqing Zhao     BMCWEB_ROUTE(
867828252d5SJiaqing Zhao         app,
868828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
869828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
870828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
871828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
872828252d5SJiaqing Zhao } // requestRoutesCertificateService
873828252d5SJiaqing Zhao 
874828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
875828252d5SJiaqing Zhao     App& app, const crow::Request& req,
876*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
877*253f11b8SEd Tanous     const std::string& managerId)
878828252d5SJiaqing Zhao {
8793ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
88045ca1b86SEd Tanous     {
88145ca1b86SEd Tanous         return;
88245ca1b86SEd Tanous     }
8831476687dSEd Tanous 
884*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
885*253f11b8SEd Tanous     {
886*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
887*253f11b8SEd Tanous         return;
888*253f11b8SEd Tanous     }
889*253f11b8SEd Tanous 
890*253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
891*253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
892*253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME);
8931476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
8941476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
8951476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8961476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
8971476687dSEd Tanous         "A Collection of HTTPS certificate instances";
8988d1b46d7Szhanghch05 
899d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
900d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
901d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
902828252d5SJiaqing Zhao }
9035968caeeSMarri Devender Rao 
904828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
905828252d5SJiaqing Zhao     App& app, const crow::Request& req,
906*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
907*253f11b8SEd Tanous     const std::string& managerId)
908828252d5SJiaqing Zhao {
9093ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
91045ca1b86SEd Tanous     {
91145ca1b86SEd Tanous         return;
91245ca1b86SEd Tanous     }
913*253f11b8SEd Tanous 
914*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
915*253f11b8SEd Tanous     {
916*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
917*253f11b8SEd Tanous         return;
918*253f11b8SEd Tanous     }
919*253f11b8SEd Tanous 
92062598e31SEd Tanous     BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
9218d1b46d7Szhanghch05 
9221476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
9231476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
9245968caeeSMarri Devender Rao 
925b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
92658eb238fSKowalski, Kamil 
927b2896149SEd Tanous     if (certHttpBody.empty())
92858eb238fSKowalski, Kamil     {
92962598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
930a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
93158eb238fSKowalski, Kamil         return;
93258eb238fSKowalski, Kamil     }
93358eb238fSKowalski, Kamil 
9345968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
935b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
9365968caeeSMarri Devender Rao 
9375968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
9385e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
939656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9405968caeeSMarri Devender Rao         if (ec)
9415968caeeSMarri Devender Rao         {
94262598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
9435968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
9445968caeeSMarri Devender Rao             return;
9455968caeeSMarri Devender Rao         }
946717b9802SJiaqing Zhao 
947717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
948717b9802SJiaqing Zhao         std::string certId = path.filename();
949ef4c65b7SEd Tanous         const boost::urls::url certURL = boost::urls::format(
950*253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
951*253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
952828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
953828252d5SJiaqing Zhao                                  certId, certURL, "HTTPS Certificate");
95462598e31SEd Tanous         BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
95562598e31SEd Tanous                          certFile->getCertFilePath());
9565968caeeSMarri Devender Rao     },
957828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
958828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
959828252d5SJiaqing Zhao }
9605968caeeSMarri Devender Rao 
961828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
962828252d5SJiaqing Zhao     App& app, const crow::Request& req,
963*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
964*253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
9657e860f15SJohn Edward Broadbent {
9663ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
96745ca1b86SEd Tanous     {
96845ca1b86SEd Tanous         return;
96945ca1b86SEd Tanous     }
9707e860f15SJohn Edward Broadbent 
971*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
972*253f11b8SEd Tanous     {
973*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
974*253f11b8SEd Tanous         return;
975*253f11b8SEd Tanous     }
976*253f11b8SEd Tanous 
977*253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId);
978ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
979*253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
980*253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
981828252d5SJiaqing Zhao     std::string objPath =
982*253f11b8SEd Tanous         sdbusplus::message::object_path(certs::httpsObjectPath) / certId;
983*253f11b8SEd Tanous     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName,
984*253f11b8SEd Tanous                              certId, certURL, "HTTPS Certificate");
9857e860f15SJohn Edward Broadbent }
98637cce918SMarri Devender Rao 
987828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
98837cce918SMarri Devender Rao {
989*253f11b8SEd Tanous     BMCWEB_ROUTE(
990*253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
991ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
992828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
993828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
994828252d5SJiaqing Zhao 
995*253f11b8SEd Tanous     BMCWEB_ROUTE(
996*253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
997828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
998828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
999828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
1000828252d5SJiaqing Zhao 
1001828252d5SJiaqing Zhao     BMCWEB_ROUTE(
1002828252d5SJiaqing Zhao         app,
1003*253f11b8SEd Tanous         "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/")
1004828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1005002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1006828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
1007828252d5SJiaqing Zhao }
1008828252d5SJiaqing Zhao 
1009828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
1010828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1011828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1012828252d5SJiaqing Zhao {
10133ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101445ca1b86SEd Tanous     {
101545ca1b86SEd Tanous         return;
101645ca1b86SEd Tanous     }
10171476687dSEd Tanous 
10181476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
10191476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
10201476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
10211476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
10221476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10231476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
10241476687dSEd Tanous         "A Collection of LDAP certificate instances";
10258d1b46d7Szhanghch05 
1026d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
1027d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1028d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1029828252d5SJiaqing Zhao }
103037cce918SMarri Devender Rao 
1031828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1032828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1033828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1034828252d5SJiaqing Zhao {
10353ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
103645ca1b86SEd Tanous     {
103745ca1b86SEd Tanous         return;
103845ca1b86SEd Tanous     }
1039b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
104058eb238fSKowalski, Kamil 
1041b2896149SEd Tanous     if (certHttpBody.empty())
104258eb238fSKowalski, Kamil     {
104362598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1044a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
104558eb238fSKowalski, Kamil         return;
104658eb238fSKowalski, Kamil     }
104758eb238fSKowalski, Kamil 
104858eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
1049b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
105058eb238fSKowalski, Kamil 
105137cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
10525e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1053656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
105437cce918SMarri Devender Rao         if (ec)
105537cce918SMarri Devender Rao         {
105662598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
105737cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
105837cce918SMarri Devender Rao             return;
105937cce918SMarri Devender Rao         }
1060717b9802SJiaqing Zhao 
1061717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1062717b9802SJiaqing Zhao         std::string certId = path.filename();
1063ef4c65b7SEd Tanous         const boost::urls::url certURL = boost::urls::format(
1064ef4c65b7SEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
1065828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1066828252d5SJiaqing Zhao                                  certId, certURL, "LDAP Certificate");
106762598e31SEd Tanous         BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
106862598e31SEd Tanous                          certFile->getCertFilePath());
106937cce918SMarri Devender Rao     },
1070828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1071828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1072828252d5SJiaqing Zhao }
107337cce918SMarri Devender Rao 
1074828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1075828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1076828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
107737cce918SMarri Devender Rao {
10783ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
107945ca1b86SEd Tanous     {
108045ca1b86SEd Tanous         return;
108145ca1b86SEd Tanous     }
1082717b9802SJiaqing Zhao 
108362598e31SEd Tanous     BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
1084ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1085ef4c65b7SEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
1086717b9802SJiaqing Zhao     std::string objPath =
1087717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1088717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1089717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1090828252d5SJiaqing Zhao }
1091828252d5SJiaqing Zhao 
109299612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
109399612247SJiaqing Zhao     App& app, const crow::Request& req,
109499612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
109599612247SJiaqing Zhao {
109699612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
109799612247SJiaqing Zhao     {
109899612247SJiaqing Zhao         return;
109999612247SJiaqing Zhao     }
110099612247SJiaqing Zhao 
110162598e31SEd Tanous     BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
110299612247SJiaqing Zhao     std::string objPath =
110399612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
110499612247SJiaqing Zhao 
110599612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
110699612247SJiaqing Zhao }
110799612247SJiaqing Zhao 
1108828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1109cfcd5f6bSMarri Devender Rao {
1110828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1111828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1112828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1113828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1114828252d5SJiaqing Zhao 
1115828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1116828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1117828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1118828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1119828252d5SJiaqing Zhao 
1120828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1121ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1122002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1123828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
112499612247SJiaqing Zhao 
112599612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
112699612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
112799612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
112899612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1129828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1130828252d5SJiaqing Zhao 
1131828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1132828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1133*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1134*253f11b8SEd Tanous     const std::string& managerId)
1135828252d5SJiaqing Zhao {
11363ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
113745ca1b86SEd Tanous     {
113845ca1b86SEd Tanous         return;
113945ca1b86SEd Tanous     }
11401476687dSEd Tanous 
1141*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1142*253f11b8SEd Tanous     {
1143*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1144*253f11b8SEd Tanous         return;
1145*253f11b8SEd Tanous     }
1146*253f11b8SEd Tanous 
11471476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
1148*253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/",
1149*253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
11501476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11511476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1152002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11531476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
11541476687dSEd Tanous         "A Collection of TrustStore certificate instances";
11558d1b46d7Szhanghch05 
1156d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1157d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1158d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1159828252d5SJiaqing Zhao }
1160cfcd5f6bSMarri Devender Rao 
1161828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1162828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1163*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1164*253f11b8SEd Tanous     const std::string& managerId)
1165828252d5SJiaqing Zhao {
11663ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
116745ca1b86SEd Tanous     {
116845ca1b86SEd Tanous         return;
116945ca1b86SEd Tanous     }
1170*253f11b8SEd Tanous 
1171*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1172*253f11b8SEd Tanous     {
1173*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1174*253f11b8SEd Tanous         return;
1175*253f11b8SEd Tanous     }
1176*253f11b8SEd Tanous 
1177b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
1178a08752f5SZbigniew Kurzynski 
1179b2896149SEd Tanous     if (certHttpBody.empty())
1180a08752f5SZbigniew Kurzynski     {
118162598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1182a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1183a08752f5SZbigniew Kurzynski         return;
1184a08752f5SZbigniew Kurzynski     }
1185a08752f5SZbigniew Kurzynski 
1186a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1187b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
1188cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
11895e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1190656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1191cfcd5f6bSMarri Devender Rao         if (ec)
1192cfcd5f6bSMarri Devender Rao         {
119362598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
1194cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1195cfcd5f6bSMarri Devender Rao             return;
1196cfcd5f6bSMarri Devender Rao         }
1197656ec7e3SZbigniew Kurzynski 
1198717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1199717b9802SJiaqing Zhao         std::string certId = path.filename();
1200ef4c65b7SEd Tanous         const boost::urls::url certURL = boost::urls::format(
1201*253f11b8SEd Tanous             "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1202*253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1203717b9802SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath,
1204828252d5SJiaqing Zhao                                  certs::authorityServiceName, certId, certURL,
1205828252d5SJiaqing Zhao                                  "TrustStore Certificate");
120662598e31SEd Tanous         BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
120762598e31SEd Tanous                          certFile->getCertFilePath());
1208cfcd5f6bSMarri Devender Rao     },
1209cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
12100fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1211828252d5SJiaqing Zhao }
1212cfcd5f6bSMarri Devender Rao 
1213828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1214828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1215*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1216*253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1217cfcd5f6bSMarri Devender Rao {
12183ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
121945ca1b86SEd Tanous     {
122045ca1b86SEd Tanous         return;
122145ca1b86SEd Tanous     }
1222717b9802SJiaqing Zhao 
1223*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1224*253f11b8SEd Tanous     {
1225*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1226*253f11b8SEd Tanous         return;
1227*253f11b8SEd Tanous     }
1228*253f11b8SEd Tanous 
1229*253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId);
1230ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1231*253f11b8SEd Tanous         "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1232*253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1233717b9802SJiaqing Zhao     std::string objPath =
1234*253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
1235828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1236*253f11b8SEd Tanous                              certId, certURL, "TrustStore Certificate");
1237828252d5SJiaqing Zhao }
123807a60299SZbigniew Kurzynski 
1239828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1240828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1241*253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1242*253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1243828252d5SJiaqing Zhao {
12443ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
124545ca1b86SEd Tanous     {
124645ca1b86SEd Tanous         return;
124745ca1b86SEd Tanous     }
124807a60299SZbigniew Kurzynski 
1249*253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1250*253f11b8SEd Tanous     {
1251*253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1252*253f11b8SEd Tanous         return;
1253*253f11b8SEd Tanous     }
1254*253f11b8SEd Tanous 
1255*253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId);
1256717b9802SJiaqing Zhao     std::string objPath =
1257*253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
125807a60299SZbigniew Kurzynski 
12597a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1260828252d5SJiaqing Zhao }
1261828252d5SJiaqing Zhao 
1262828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1263828252d5SJiaqing Zhao {
1264*253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1265828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1266828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1267828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1268828252d5SJiaqing Zhao 
1269*253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1270828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1271828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1272828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1273828252d5SJiaqing Zhao 
1274*253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1275*253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1276828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1277828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1278828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1279828252d5SJiaqing Zhao 
1280*253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1281*253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1282828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1283828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1284828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
12857e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
12865968caeeSMarri Devender Rao } // namespace redfish
1287