xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 7a31e336bd151aebd6175663021acd8608e3a97e)
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(
252ef4c65b7SEd Tanous                     "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}",
253ef4c65b7SEd Tanous                     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(
263ef4c65b7SEd Tanous                     "/redfish/v1/Managers/bmc/Truststore/Certificates/{}",
264ef4c65b7SEd Tanous                     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;
474*7a31e336SEd Tanous     std::string certURI;
4755968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
4768d1b46d7Szhanghch05 
477002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
478*7a31e336SEd Tanous                                    certificate, "CertificateUri/@odata.id",
479*7a31e336SEd 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;
629*7a31e336SEd 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",
650*7a31e336SEd Tanous             organizationalUnit, "State", state,
651*7a31e336SEd Tanous             "CertificateCollection/@odata.id", certURI, "AlternativeNames",
652*7a31e336SEd Tanous             optAlternativeNames, "ChallengePassword", optChallengePassword,
653*7a31e336SEd Tanous             "Email", optEmail, "GivenName", optGivenName, "Initials",
654*7a31e336SEd Tanous             optInitials, "KeyBitLength", optKeyBitLength, "KeyCurveId",
655*7a31e336SEd Tanous             optKeyCurveId, "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
656*7a31e336SEd Tanous             optKeyUsage, "Surname", optSurname, "UnstructuredName",
657*7a31e336SEd 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;
675828252d5SJiaqing Zhao     if (certURI.starts_with(
676828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
677828252d5SJiaqing Zhao     {
678828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
679828252d5SJiaqing Zhao         service = certs::httpsServiceName;
680828252d5SJiaqing Zhao     }
681828252d5SJiaqing Zhao     else if (certURI.starts_with(
682828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
683828252d5SJiaqing Zhao     {
684828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
685828252d5SJiaqing Zhao         service = certs::ldapServiceName;
686828252d5SJiaqing Zhao     }
687828252d5SJiaqing Zhao     else
688828252d5SJiaqing Zhao     {
689828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
690828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
691828252d5SJiaqing Zhao         return;
692828252d5SJiaqing Zhao     }
693828252d5SJiaqing Zhao 
694828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
695828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
696828252d5SJiaqing Zhao     {
697828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
698828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
699828252d5SJiaqing Zhao         return;
700828252d5SJiaqing Zhao     }
701828252d5SJiaqing Zhao 
702828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
703828252d5SJiaqing Zhao     // time consumed in generating private key
704828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
705828252d5SJiaqing Zhao     {
706e2616cc5SEd Tanous         messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
707e2616cc5SEd Tanous                                          "KeyBitLength");
708828252d5SJiaqing Zhao         return;
709828252d5SJiaqing Zhao     }
710828252d5SJiaqing Zhao 
711828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
712828252d5SJiaqing Zhao     if (certURI.starts_with(
713828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
714828252d5SJiaqing Zhao     {
715828252d5SJiaqing Zhao         if (optKeyUsage->empty())
716828252d5SJiaqing Zhao         {
717b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ServerAuthentication");
718828252d5SJiaqing Zhao         }
719828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
720828252d5SJiaqing Zhao         {
721828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
722828252d5SJiaqing Zhao             {
723828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
724828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
725828252d5SJiaqing Zhao                 return;
726828252d5SJiaqing Zhao             }
727828252d5SJiaqing Zhao         }
728828252d5SJiaqing Zhao         else
729828252d5SJiaqing Zhao         {
730828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
731828252d5SJiaqing Zhao                                                   "GenerateCSR");
732828252d5SJiaqing Zhao             return;
733828252d5SJiaqing Zhao         }
734828252d5SJiaqing Zhao     }
735828252d5SJiaqing Zhao     else if (certURI.starts_with(
736828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
737828252d5SJiaqing Zhao     {
738828252d5SJiaqing Zhao         if (optKeyUsage->empty())
739828252d5SJiaqing Zhao         {
740b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ClientAuthentication");
741828252d5SJiaqing Zhao         }
742828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
743828252d5SJiaqing Zhao         {
744828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
745828252d5SJiaqing Zhao             {
746828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
747828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
748828252d5SJiaqing Zhao                 return;
749828252d5SJiaqing Zhao             }
750828252d5SJiaqing Zhao         }
751828252d5SJiaqing Zhao         else
752828252d5SJiaqing Zhao         {
753828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
754828252d5SJiaqing Zhao                                                   "GenerateCSR");
755828252d5SJiaqing Zhao             return;
756828252d5SJiaqing Zhao         }
757828252d5SJiaqing Zhao     }
758828252d5SJiaqing Zhao 
759828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
760828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
761828252d5SJiaqing Zhao     static const int timeOut = 10;
762828252d5SJiaqing Zhao     if (csrMatcher)
763828252d5SJiaqing Zhao     {
764828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
765828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
766828252d5SJiaqing Zhao         return;
767828252d5SJiaqing Zhao     }
768828252d5SJiaqing Zhao 
769828252d5SJiaqing Zhao     // Make this static so it survives outside this method
770828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
771828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
772828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
773828252d5SJiaqing Zhao         csrMatcher = nullptr;
774828252d5SJiaqing Zhao         if (ec)
775828252d5SJiaqing Zhao         {
776828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
777828252d5SJiaqing Zhao             // before completion.
778828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
779828252d5SJiaqing Zhao             {
78062598e31SEd Tanous                 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
781828252d5SJiaqing Zhao             }
782828252d5SJiaqing Zhao             return;
783828252d5SJiaqing Zhao         }
78462598e31SEd Tanous         BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
785828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
786828252d5SJiaqing Zhao     });
787828252d5SJiaqing Zhao 
788828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
78962598e31SEd Tanous     BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
790828252d5SJiaqing Zhao     std::string match("type='signal',"
791828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
792828252d5SJiaqing Zhao                       "path='" +
793828252d5SJiaqing Zhao                       objectPath +
794828252d5SJiaqing Zhao                       "',"
795828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
796828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
797828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
798828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
799828252d5SJiaqing Zhao         timeout.cancel();
800828252d5SJiaqing Zhao         if (m.is_method_error())
801828252d5SJiaqing Zhao         {
80262598e31SEd Tanous             BMCWEB_LOG_ERROR("Dbus method error!!!");
803828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
804828252d5SJiaqing Zhao             return;
805828252d5SJiaqing Zhao         }
806828252d5SJiaqing Zhao 
80780f79a40SMichael Shen         dbus::utility::DBusInterfacesMap interfacesProperties;
808828252d5SJiaqing Zhao 
809828252d5SJiaqing Zhao         sdbusplus::message::object_path csrObjectPath;
810828252d5SJiaqing Zhao         m.read(csrObjectPath, interfacesProperties);
81162598e31SEd Tanous         BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
812828252d5SJiaqing Zhao         for (const auto& interface : interfacesProperties)
813828252d5SJiaqing Zhao         {
814828252d5SJiaqing Zhao             if (interface.first == "xyz.openbmc_project.Certs.CSR")
815828252d5SJiaqing Zhao             {
816828252d5SJiaqing Zhao                 getCSR(asyncResp, certURI, service, objectPath,
817828252d5SJiaqing Zhao                        csrObjectPath.str);
818828252d5SJiaqing Zhao                 break;
819828252d5SJiaqing Zhao             }
820828252d5SJiaqing Zhao         }
821828252d5SJiaqing Zhao     });
822828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
8235e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec, const std::string&) {
824828252d5SJiaqing Zhao         if (ec)
825828252d5SJiaqing Zhao         {
82662598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
827828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
828828252d5SJiaqing Zhao             return;
829828252d5SJiaqing Zhao         }
830828252d5SJiaqing Zhao     },
831828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
832828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
833828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
834828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
835828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
836828252d5SJiaqing Zhao         *optUnstructuredName);
837828252d5SJiaqing Zhao }
838828252d5SJiaqing Zhao 
839828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
840828252d5SJiaqing Zhao {
841828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
842828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
843002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
844828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
845828252d5SJiaqing Zhao 
846828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
847828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
848828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
849828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
850828252d5SJiaqing Zhao 
851828252d5SJiaqing Zhao     BMCWEB_ROUTE(
852828252d5SJiaqing Zhao         app,
853828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
854828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
855828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
856828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
857828252d5SJiaqing Zhao 
858828252d5SJiaqing Zhao     BMCWEB_ROUTE(
859828252d5SJiaqing Zhao         app,
860828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
861828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
862828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
863828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
864828252d5SJiaqing Zhao } // requestRoutesCertificateService
865828252d5SJiaqing Zhao 
866828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
867828252d5SJiaqing Zhao     App& app, const crow::Request& req,
868828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
869828252d5SJiaqing Zhao {
8703ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
87145ca1b86SEd Tanous     {
87245ca1b86SEd Tanous         return;
87345ca1b86SEd Tanous     }
8741476687dSEd Tanous 
8751476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
8761476687dSEd Tanous         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
8771476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
8781476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
8791476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8801476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
8811476687dSEd Tanous         "A Collection of HTTPS certificate instances";
8828d1b46d7Szhanghch05 
883d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
884d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
885d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
886828252d5SJiaqing Zhao }
8875968caeeSMarri Devender Rao 
888828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
889828252d5SJiaqing Zhao     App& app, const crow::Request& req,
890828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
891828252d5SJiaqing Zhao {
8923ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
89345ca1b86SEd Tanous     {
89445ca1b86SEd Tanous         return;
89545ca1b86SEd Tanous     }
89662598e31SEd Tanous     BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
8978d1b46d7Szhanghch05 
8981476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
8991476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
9005968caeeSMarri Devender Rao 
901b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
90258eb238fSKowalski, Kamil 
903b2896149SEd Tanous     if (certHttpBody.empty())
90458eb238fSKowalski, Kamil     {
90562598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
906a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
90758eb238fSKowalski, Kamil         return;
90858eb238fSKowalski, Kamil     }
90958eb238fSKowalski, Kamil 
9105968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
911b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
9125968caeeSMarri Devender Rao 
9135968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
9145e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
915656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9165968caeeSMarri Devender Rao         if (ec)
9175968caeeSMarri Devender Rao         {
91862598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
9195968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
9205968caeeSMarri Devender Rao             return;
9215968caeeSMarri Devender Rao         }
922717b9802SJiaqing Zhao 
923717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
924717b9802SJiaqing Zhao         std::string certId = path.filename();
925ef4c65b7SEd Tanous         const boost::urls::url certURL = boost::urls::format(
926ef4c65b7SEd Tanous             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}",
927ef4c65b7SEd Tanous             certId);
928828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
929828252d5SJiaqing Zhao                                  certId, certURL, "HTTPS Certificate");
93062598e31SEd Tanous         BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
93162598e31SEd Tanous                          certFile->getCertFilePath());
9325968caeeSMarri Devender Rao     },
933828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
934828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
935828252d5SJiaqing Zhao }
9365968caeeSMarri Devender Rao 
937828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
938828252d5SJiaqing Zhao     App& app, const crow::Request& req,
939828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
9407e860f15SJohn Edward Broadbent {
9413ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
94245ca1b86SEd Tanous     {
94345ca1b86SEd Tanous         return;
94445ca1b86SEd Tanous     }
9457e860f15SJohn Edward Broadbent 
94662598e31SEd Tanous     BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", id);
947ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
948ef4c65b7SEd Tanous         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}", id);
949828252d5SJiaqing Zhao     std::string objPath =
950828252d5SJiaqing Zhao         sdbusplus::message::object_path(certs::httpsObjectPath) / id;
951828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
952828252d5SJiaqing Zhao                              certURL, "HTTPS Certificate");
9537e860f15SJohn Edward Broadbent }
95437cce918SMarri Devender Rao 
955828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
95637cce918SMarri Devender Rao {
957828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
958828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
959ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
960828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
961828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
962828252d5SJiaqing Zhao 
963828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
964828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
965828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
966828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
967828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
968828252d5SJiaqing Zhao 
969828252d5SJiaqing Zhao     BMCWEB_ROUTE(
970828252d5SJiaqing Zhao         app,
971828252d5SJiaqing Zhao         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
972828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
973002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
974828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
975828252d5SJiaqing Zhao }
976828252d5SJiaqing Zhao 
977828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
978828252d5SJiaqing Zhao     App& app, const crow::Request& req,
979828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
980828252d5SJiaqing Zhao {
9813ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
98245ca1b86SEd Tanous     {
98345ca1b86SEd Tanous         return;
98445ca1b86SEd Tanous     }
9851476687dSEd Tanous 
9861476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
9871476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
9881476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
9891476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
9901476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
9911476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
9921476687dSEd Tanous         "A Collection of LDAP certificate instances";
9938d1b46d7Szhanghch05 
994d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
995d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
996d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
997828252d5SJiaqing Zhao }
99837cce918SMarri Devender Rao 
999828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1000828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1001828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1002828252d5SJiaqing Zhao {
10033ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
100445ca1b86SEd Tanous     {
100545ca1b86SEd Tanous         return;
100645ca1b86SEd Tanous     }
1007b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
100858eb238fSKowalski, Kamil 
1009b2896149SEd Tanous     if (certHttpBody.empty())
101058eb238fSKowalski, Kamil     {
101162598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1012a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
101358eb238fSKowalski, Kamil         return;
101458eb238fSKowalski, Kamil     }
101558eb238fSKowalski, Kamil 
101658eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
1017b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
101858eb238fSKowalski, Kamil 
101937cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
10205e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1021656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
102237cce918SMarri Devender Rao         if (ec)
102337cce918SMarri Devender Rao         {
102462598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
102537cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
102637cce918SMarri Devender Rao             return;
102737cce918SMarri Devender Rao         }
1028717b9802SJiaqing Zhao 
1029717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1030717b9802SJiaqing Zhao         std::string certId = path.filename();
1031ef4c65b7SEd Tanous         const boost::urls::url certURL = boost::urls::format(
1032ef4c65b7SEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
1033828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1034828252d5SJiaqing Zhao                                  certId, certURL, "LDAP Certificate");
103562598e31SEd Tanous         BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
103662598e31SEd Tanous                          certFile->getCertFilePath());
103737cce918SMarri Devender Rao     },
1038828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1039828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1040828252d5SJiaqing Zhao }
104137cce918SMarri Devender Rao 
1042828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1043828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1044828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
104537cce918SMarri Devender Rao {
10463ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
104745ca1b86SEd Tanous     {
104845ca1b86SEd Tanous         return;
104945ca1b86SEd Tanous     }
1050717b9802SJiaqing Zhao 
105162598e31SEd Tanous     BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
1052ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1053ef4c65b7SEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
1054717b9802SJiaqing Zhao     std::string objPath =
1055717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1056717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1057717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1058828252d5SJiaqing Zhao }
1059828252d5SJiaqing Zhao 
106099612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
106199612247SJiaqing Zhao     App& app, const crow::Request& req,
106299612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
106399612247SJiaqing Zhao {
106499612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
106599612247SJiaqing Zhao     {
106699612247SJiaqing Zhao         return;
106799612247SJiaqing Zhao     }
106899612247SJiaqing Zhao 
106962598e31SEd Tanous     BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
107099612247SJiaqing Zhao     std::string objPath =
107199612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
107299612247SJiaqing Zhao 
107399612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
107499612247SJiaqing Zhao }
107599612247SJiaqing Zhao 
1076828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1077cfcd5f6bSMarri Devender Rao {
1078828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1079828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1080828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1081828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1082828252d5SJiaqing Zhao 
1083828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1084828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1085828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1086828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1087828252d5SJiaqing Zhao 
1088828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1089ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1090002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1091828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
109299612247SJiaqing Zhao 
109399612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
109499612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
109599612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
109699612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1097828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1098828252d5SJiaqing Zhao 
1099828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1100828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1101828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1102828252d5SJiaqing Zhao {
11033ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
110445ca1b86SEd Tanous     {
110545ca1b86SEd Tanous         return;
110645ca1b86SEd Tanous     }
11071476687dSEd Tanous 
11081476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
11091476687dSEd Tanous         "/redfish/v1/Managers/bmc/Truststore/Certificates/";
11101476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11111476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1112002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11131476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
11141476687dSEd Tanous         "A Collection of TrustStore certificate instances";
11158d1b46d7Szhanghch05 
1116d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1117d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1118d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1119828252d5SJiaqing Zhao }
1120cfcd5f6bSMarri Devender Rao 
1121828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1122828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1123828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1124828252d5SJiaqing Zhao {
11253ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
112645ca1b86SEd Tanous     {
112745ca1b86SEd Tanous         return;
112845ca1b86SEd Tanous     }
1129b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
1130a08752f5SZbigniew Kurzynski 
1131b2896149SEd Tanous     if (certHttpBody.empty())
1132a08752f5SZbigniew Kurzynski     {
113362598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1134a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1135a08752f5SZbigniew Kurzynski         return;
1136a08752f5SZbigniew Kurzynski     }
1137a08752f5SZbigniew Kurzynski 
1138a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1139b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
1140cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
11415e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1142656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1143cfcd5f6bSMarri Devender Rao         if (ec)
1144cfcd5f6bSMarri Devender Rao         {
114562598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
1146cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1147cfcd5f6bSMarri Devender Rao             return;
1148cfcd5f6bSMarri Devender Rao         }
1149656ec7e3SZbigniew Kurzynski 
1150717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1151717b9802SJiaqing Zhao         std::string certId = path.filename();
1152ef4c65b7SEd Tanous         const boost::urls::url certURL = boost::urls::format(
1153ef4c65b7SEd Tanous             "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", certId);
1154717b9802SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath,
1155828252d5SJiaqing Zhao                                  certs::authorityServiceName, certId, certURL,
1156828252d5SJiaqing Zhao                                  "TrustStore Certificate");
115762598e31SEd Tanous         BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
115862598e31SEd Tanous                          certFile->getCertFilePath());
1159cfcd5f6bSMarri Devender Rao     },
1160cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
11610fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1162828252d5SJiaqing Zhao }
1163cfcd5f6bSMarri Devender Rao 
1164828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1165828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1166828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1167cfcd5f6bSMarri Devender Rao {
11683ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
116945ca1b86SEd Tanous     {
117045ca1b86SEd Tanous         return;
117145ca1b86SEd Tanous     }
1172717b9802SJiaqing Zhao 
117362598e31SEd Tanous     BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", id);
1174ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1175ef4c65b7SEd Tanous         "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", id);
1176717b9802SJiaqing Zhao     std::string objPath =
1177717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1178828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1179828252d5SJiaqing Zhao                              id, certURL, "TrustStore Certificate");
1180828252d5SJiaqing Zhao }
118107a60299SZbigniew Kurzynski 
1182828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1183828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1184828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1185828252d5SJiaqing Zhao {
11863ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
118745ca1b86SEd Tanous     {
118845ca1b86SEd Tanous         return;
118945ca1b86SEd Tanous     }
119007a60299SZbigniew Kurzynski 
119162598e31SEd Tanous     BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", id);
1192717b9802SJiaqing Zhao     std::string objPath =
1193717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
119407a60299SZbigniew Kurzynski 
11957a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1196828252d5SJiaqing Zhao }
1197828252d5SJiaqing Zhao 
1198828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1199828252d5SJiaqing Zhao {
1200828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1201828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1202828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1203828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1204828252d5SJiaqing Zhao 
1205828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1206828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1207828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1208828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1209828252d5SJiaqing Zhao 
1210828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1211828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1212828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1213828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1214828252d5SJiaqing Zhao 
1215828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1216828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1217828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1218828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
12197e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
12205968caeeSMarri Devender Rao } // namespace redfish
1221