xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision 33c6b58026e5dd3bc600d152a07b95f863bfa1a7)
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>
159b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
163ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
179b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
181214b7e7SGunnar Mills 
197a1dbc48SGeorge Liu #include <array>
203ccb3adbSEd Tanous #include <memory>
217a1dbc48SGeorge Liu #include <string_view>
227a1dbc48SGeorge Liu 
235968caeeSMarri Devender Rao namespace redfish
245968caeeSMarri Devender Rao {
255968caeeSMarri Devender Rao namespace certs
265968caeeSMarri Devender Rao {
275968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
285968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
2907a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
305968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
315968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
325968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
3337cce918SMarri Devender Rao constexpr char const* httpsServiceName =
3437cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
3537cce918SMarri Devender Rao constexpr char const* ldapServiceName =
3637cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
37cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
38cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
39c6a8dfb1SJiaqing Zhao constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
40c6a8dfb1SJiaqing Zhao constexpr char const* httpsObjectPath =
41c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
42c6a8dfb1SJiaqing Zhao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
43cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
44cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
455968caeeSMarri Devender Rao } // namespace certs
465968caeeSMarri Devender Rao 
475968caeeSMarri Devender Rao /**
485968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
495968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
505968caeeSMarri Devender Rao  * are installed.
515968caeeSMarri Devender Rao  */
527e860f15SJohn Edward Broadbent 
538d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
548d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5558eb238fSKowalski, Kamil     const crow::Request& req)
5658eb238fSKowalski, Kamil {
571aa0c2b8SEd Tanous     nlohmann::json reqJson;
581aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, reqJson);
591aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
6058eb238fSKowalski, Kamil     {
6158eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
62*33c6b580SEd Tanous         return req.body();
6358eb238fSKowalski, Kamil     }
6458eb238fSKowalski, Kamil 
6558eb238fSKowalski, Kamil     std::string certificate;
6658eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
6758eb238fSKowalski, Kamil 
6815ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
6915ed6780SWilly Tu                                   certificate, "CertificateType",
7015ed6780SWilly Tu                                   certificateType))
7158eb238fSKowalski, Kamil     {
7258eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
7358eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
74abb93cddSEd Tanous         return {};
7558eb238fSKowalski, Kamil     }
7658eb238fSKowalski, Kamil 
7758eb238fSKowalski, Kamil     if (*certificateType != "PEM")
7858eb238fSKowalski, Kamil     {
7958eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
8058eb238fSKowalski, Kamil                                          "CertificateType");
81abb93cddSEd Tanous         return {};
8258eb238fSKowalski, Kamil     }
8358eb238fSKowalski, Kamil 
8458eb238fSKowalski, Kamil     return certificate;
8558eb238fSKowalski, Kamil }
8658eb238fSKowalski, Kamil 
875968caeeSMarri Devender Rao /**
885968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
895968caeeSMarri Devender Rao  */
905968caeeSMarri Devender Rao class CertificateFile
915968caeeSMarri Devender Rao {
925968caeeSMarri Devender Rao   public:
935968caeeSMarri Devender Rao     CertificateFile() = delete;
945968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
955968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
965968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
975968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
984e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
995968caeeSMarri Devender Rao     {
10072d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1015207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1025207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1035207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
104e662eae8SEd Tanous         if (tempDirectory != nullptr)
1055968caeeSMarri Devender Rao         {
1065968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1075968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1085968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1095968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1105968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1115968caeeSMarri Devender Rao             out << certString;
1125968caeeSMarri Devender Rao             out.close();
1138cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Creating certificate file"
1148cc8edecSEd Tanous                              << certificateFile.string();
1155968caeeSMarri Devender Rao         }
1165968caeeSMarri Devender Rao     }
1175968caeeSMarri Devender Rao     ~CertificateFile()
1185968caeeSMarri Devender Rao     {
1195968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1205968caeeSMarri Devender Rao         {
1218cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Removing certificate file"
1228cc8edecSEd Tanous                              << certificateFile.string();
12323a21a1cSEd Tanous             std::error_code ec;
12423a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
12523a21a1cSEd Tanous             if (ec)
1265968caeeSMarri Devender Rao             {
1275968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1288cc8edecSEd Tanous                                  << certDirectory.string();
1295968caeeSMarri Devender Rao             }
1305968caeeSMarri Devender Rao         }
1315968caeeSMarri Devender Rao     }
1325968caeeSMarri Devender Rao     std::string getCertFilePath()
1335968caeeSMarri Devender Rao     {
1345968caeeSMarri Devender Rao         return certificateFile;
1355968caeeSMarri Devender Rao     }
1365968caeeSMarri Devender Rao 
1375968caeeSMarri Devender Rao   private:
1385968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1395968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1405968caeeSMarri Devender Rao };
1415968caeeSMarri Devender Rao 
1425968caeeSMarri Devender Rao /**
1434e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1445968caeeSMarri Devender Rao  *
1455968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1465968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1475968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1485968caeeSMarri Devender Rao  * @return None
1495968caeeSMarri Devender Rao  */
1505968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
15126ccae32SEd Tanous                                       std::string_view value)
1525968caeeSMarri Devender Rao {
1535968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1545968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1555968caeeSMarri Devender Rao     while (i != value.end())
1565968caeeSMarri Devender Rao     {
1575968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1585968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1595968caeeSMarri Devender Rao         {
16017a897dfSManojkiran Eda             ++i;
1615968caeeSMarri Devender Rao         }
1625968caeeSMarri Devender Rao         if (i == value.end())
1635968caeeSMarri Devender Rao         {
1645968caeeSMarri Devender Rao             break;
1655968caeeSMarri Devender Rao         }
16626ccae32SEd Tanous         std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin));
16717a897dfSManojkiran Eda         ++i;
1685968caeeSMarri Devender Rao         tokenBegin = i;
1695968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
1705968caeeSMarri Devender Rao         {
17117a897dfSManojkiran Eda             ++i;
1725968caeeSMarri Devender Rao         }
17326ccae32SEd Tanous         std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin));
1745968caeeSMarri Devender Rao         if (key == "L")
1755968caeeSMarri Devender Rao         {
1765968caeeSMarri Devender Rao             out["City"] = val;
1775968caeeSMarri Devender Rao         }
1785968caeeSMarri Devender Rao         else if (key == "CN")
1795968caeeSMarri Devender Rao         {
1805968caeeSMarri Devender Rao             out["CommonName"] = val;
1815968caeeSMarri Devender Rao         }
1825968caeeSMarri Devender Rao         else if (key == "C")
1835968caeeSMarri Devender Rao         {
1845968caeeSMarri Devender Rao             out["Country"] = val;
1855968caeeSMarri Devender Rao         }
1865968caeeSMarri Devender Rao         else if (key == "O")
1875968caeeSMarri Devender Rao         {
1885968caeeSMarri Devender Rao             out["Organization"] = val;
1895968caeeSMarri Devender Rao         }
1905968caeeSMarri Devender Rao         else if (key == "OU")
1915968caeeSMarri Devender Rao         {
1925968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
1935968caeeSMarri Devender Rao         }
1945968caeeSMarri Devender Rao         else if (key == "ST")
1955968caeeSMarri Devender Rao         {
1965968caeeSMarri Devender Rao             out["State"] = val;
1975968caeeSMarri Devender Rao         }
1985968caeeSMarri Devender Rao         // skip comma character
1995968caeeSMarri Devender Rao         if (i != value.end())
2005968caeeSMarri Devender Rao         {
20117a897dfSManojkiran Eda             ++i;
2025968caeeSMarri Devender Rao         }
2035968caeeSMarri Devender Rao     }
2045968caeeSMarri Devender Rao }
2055968caeeSMarri Devender Rao 
2065968caeeSMarri Devender Rao /**
207d3f92ce7SJiaqing Zhao  * @brief Retrieve the installed certificate list
208d3f92ce7SJiaqing Zhao  *
209d3f92ce7SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
210d3f92ce7SJiaqing Zhao  * @param[in] basePath DBus object path to search
211d3f92ce7SJiaqing Zhao  * @param[in] listPtr Json pointer to the list in asyncResp
212d3f92ce7SJiaqing Zhao  * @param[in] countPtr Json pointer to the count in asyncResp
213d3f92ce7SJiaqing Zhao  * @return None
214d3f92ce7SJiaqing Zhao  */
215d3f92ce7SJiaqing Zhao static void
216d3f92ce7SJiaqing Zhao     getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
217d3f92ce7SJiaqing Zhao                        const std::string& basePath,
218d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& listPtr,
219d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& countPtr)
220d3f92ce7SJiaqing Zhao {
2217a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2227a1dbc48SGeorge Liu         certs::certPropIntf};
2237a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
2247a1dbc48SGeorge Liu         basePath, 0, interfaces,
225d3f92ce7SJiaqing Zhao         [asyncResp, listPtr, countPtr](
2267a1dbc48SGeorge Liu             const boost::system::error_code& ec,
227d3f92ce7SJiaqing Zhao             const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
228d3f92ce7SJiaqing Zhao         if (ec)
229d3f92ce7SJiaqing Zhao         {
230d3f92ce7SJiaqing Zhao             BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
231d3f92ce7SJiaqing Zhao             messages::internalError(asyncResp->res);
232d3f92ce7SJiaqing Zhao             return;
233d3f92ce7SJiaqing Zhao         }
234d3f92ce7SJiaqing Zhao 
235d3f92ce7SJiaqing Zhao         nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
236d3f92ce7SJiaqing Zhao         links = nlohmann::json::array();
237d3f92ce7SJiaqing Zhao         for (const auto& certPath : certPaths)
238d3f92ce7SJiaqing Zhao         {
239d3f92ce7SJiaqing Zhao             sdbusplus::message::object_path objPath(certPath);
240d3f92ce7SJiaqing Zhao             std::string certId = objPath.filename();
241d3f92ce7SJiaqing Zhao             if (certId.empty())
242d3f92ce7SJiaqing Zhao             {
243d3f92ce7SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
244d3f92ce7SJiaqing Zhao                 continue;
245d3f92ce7SJiaqing Zhao             }
246d3f92ce7SJiaqing Zhao 
247d3f92ce7SJiaqing Zhao             boost::urls::url certURL;
248d3f92ce7SJiaqing Zhao             if (objPath.parent_path() == certs::httpsObjectPath)
249d3f92ce7SJiaqing Zhao             {
250d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
251d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
252d3f92ce7SJiaqing Zhao                     "HTTPS", "Certificates", certId);
253d3f92ce7SJiaqing Zhao             }
254d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::ldapObjectPath)
255d3f92ce7SJiaqing Zhao             {
256d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces("redfish", "v1",
257d3f92ce7SJiaqing Zhao                                                        "AccountService", "LDAP",
258d3f92ce7SJiaqing Zhao                                                        "Certificates", certId);
259d3f92ce7SJiaqing Zhao             }
260d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::authorityObjectPath)
261d3f92ce7SJiaqing Zhao             {
262d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
263d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "Truststore",
264d3f92ce7SJiaqing Zhao                     "Certificates", 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 {
2975968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
2985968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << 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         {
3065968caeeSMarri Devender Rao             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         }
3927a3a8f7aSJiaqing Zhao         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 
407828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
408828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
409828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
410828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
411828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
412828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
413828252d5SJiaqing Zhao         "Actions available to manage certificates";
414828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
415828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
416828252d5SJiaqing Zhao     // has permissions ConfigureManager
417828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
418828252d5SJiaqing Zhao         redfish::getUserPrivileges(req.userRole);
419828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
420828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
421828252d5SJiaqing Zhao     {
422828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
423828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
424828252d5SJiaqing Zhao     }
425828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
426828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
427828252d5SJiaqing Zhao     replace["target"] =
428828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
429828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
430828252d5SJiaqing Zhao     allowed.push_back("PEM");
431828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
432828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
433828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
434828252d5SJiaqing Zhao }
435828252d5SJiaqing Zhao 
436828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
437828252d5SJiaqing Zhao     App& app, const crow::Request& req,
438828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
439828252d5SJiaqing Zhao {
440828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
441828252d5SJiaqing Zhao     {
442828252d5SJiaqing Zhao         return;
443828252d5SJiaqing Zhao     }
444828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
445828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
446828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
447828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
448828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
449828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
450828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
451828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
452828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
453828252d5SJiaqing Zhao 
454828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
455828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
456828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
457828252d5SJiaqing Zhao }
458828252d5SJiaqing Zhao 
459828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
460828252d5SJiaqing Zhao     App& app, const crow::Request& req,
461828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
462828252d5SJiaqing Zhao {
4633ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
46445ca1b86SEd Tanous     {
46545ca1b86SEd Tanous         return;
46645ca1b86SEd Tanous     }
4675968caeeSMarri Devender Rao     std::string certificate;
4685968caeeSMarri Devender Rao     nlohmann::json certificateUri;
4695968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
4708d1b46d7Szhanghch05 
471002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
472002d39b4SEd Tanous                                    certificate, "CertificateUri",
473002d39b4SEd Tanous                                    certificateUri, "CertificateType",
474002d39b4SEd Tanous                                    certificateType))
4755968caeeSMarri Devender Rao     {
4765968caeeSMarri Devender Rao         BMCWEB_LOG_ERROR << "Required parameters are missing";
4775968caeeSMarri Devender Rao         messages::internalError(asyncResp->res);
4785968caeeSMarri Devender Rao         return;
4795968caeeSMarri Devender Rao     }
4805968caeeSMarri Devender Rao 
4815968caeeSMarri Devender Rao     if (!certificateType)
4825968caeeSMarri Devender Rao     {
4835968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
4845968caeeSMarri Devender Rao         return;
4855968caeeSMarri Devender Rao     }
4865968caeeSMarri Devender Rao     if (certificateType != "PEM")
4875968caeeSMarri Devender Rao     {
488828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
489828252d5SJiaqing Zhao                                               "ReplaceCertificate");
4905968caeeSMarri Devender Rao         return;
4915968caeeSMarri Devender Rao     }
4925968caeeSMarri Devender Rao 
4935968caeeSMarri Devender Rao     std::string certURI;
4945968caeeSMarri Devender Rao     if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
4955968caeeSMarri Devender Rao                                       "@odata.id", certURI))
4965968caeeSMarri Devender Rao     {
497828252d5SJiaqing Zhao         messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
498828252d5SJiaqing Zhao                                          "CertificateUri");
4995968caeeSMarri Devender Rao         return;
5005968caeeSMarri Devender Rao     }
50175b63a2cSJiaqing Zhao     BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI;
5025968caeeSMarri Devender Rao 
50375b63a2cSJiaqing Zhao     boost::urls::result<boost::urls::url_view> parsedUrl =
50475b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
50575b63a2cSJiaqing Zhao     if (!parsedUrl)
5065968caeeSMarri Devender Rao     {
507828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
508828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
5095968caeeSMarri Devender Rao         return;
5105968caeeSMarri Devender Rao     }
51175b63a2cSJiaqing Zhao 
51275b63a2cSJiaqing Zhao     std::string id;
51375b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
5145968caeeSMarri Devender Rao     std::string name;
51537cce918SMarri Devender Rao     std::string service;
516828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
517828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
518828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5195968caeeSMarri Devender Rao     {
520002d39b4SEd Tanous         objectPath =
52175b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::httpsObjectPath) / id;
5225968caeeSMarri Devender Rao         name = "HTTPS certificate";
52337cce918SMarri Devender Rao         service = certs::httpsServiceName;
52437cce918SMarri Devender Rao     }
52575b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
52675b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
52775b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
52837cce918SMarri Devender Rao     {
529002d39b4SEd Tanous         objectPath =
53075b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::ldapObjectPath) / id;
53137cce918SMarri Devender Rao         name = "LDAP certificate";
53237cce918SMarri Devender Rao         service = certs::ldapServiceName;
5335968caeeSMarri Devender Rao     }
53475b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
53575b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
53675b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
537cfcd5f6bSMarri Devender Rao     {
53875b63a2cSJiaqing Zhao         objectPath =
539828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
540cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
541cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
542cfcd5f6bSMarri Devender Rao     }
5435968caeeSMarri Devender Rao     else
5445968caeeSMarri Devender Rao     {
545828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
546828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5475968caeeSMarri Devender Rao         return;
5485968caeeSMarri Devender Rao     }
5495968caeeSMarri Devender Rao 
5505968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
5515968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
5525968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
5531e312598SJiaqing Zhao         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
5545e7e2dc5SEd Tanous          name](const boost::system::error_code& ec) {
5555968caeeSMarri Devender Rao         if (ec)
5565968caeeSMarri Devender Rao         {
5575968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
55890d2d1e8SJiaqing Zhao             if (ec.value() ==
55990d2d1e8SJiaqing Zhao                 boost::system::linux_error::bad_request_descriptor)
56090d2d1e8SJiaqing Zhao             {
561828252d5SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
5625968caeeSMarri Devender Rao                 return;
5635968caeeSMarri Devender Rao             }
56490d2d1e8SJiaqing Zhao             messages::internalError(asyncResp->res);
56590d2d1e8SJiaqing Zhao             return;
56690d2d1e8SJiaqing Zhao         }
567828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, service, id, url, name);
5685968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
5695968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
5705968caeeSMarri Devender Rao         },
5715968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
5725968caeeSMarri Devender Rao         certFile->getCertFilePath());
573828252d5SJiaqing Zhao }
5745968caeeSMarri Devender Rao 
575cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
576828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
5775968caeeSMarri Devender Rao /**
578828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
579828252d5SJiaqing Zhao  *
580828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
581828252d5SJiaqing Zhao  * @param[in] certURI Link to certifiate collection URI
582828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
583828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
584828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
585828252d5SJiaqing Zhao  * @return None
5865968caeeSMarri Devender Rao  */
587828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
588828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
589828252d5SJiaqing Zhao                    const std::string& certObjPath,
590828252d5SJiaqing Zhao                    const std::string& csrObjPath)
5915968caeeSMarri Devender Rao {
592828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
593828252d5SJiaqing Zhao                      << " CSRObjectPath=" << csrObjPath
594828252d5SJiaqing Zhao                      << " service=" << service;
595828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
5965e7e2dc5SEd Tanous         [asyncResp, certURI](const boost::system::error_code& ec,
597828252d5SJiaqing Zhao                              const std::string& csr) {
598828252d5SJiaqing Zhao         if (ec)
599828252d5SJiaqing Zhao         {
600828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
601828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
602828252d5SJiaqing Zhao             return;
603828252d5SJiaqing Zhao         }
604828252d5SJiaqing Zhao         if (csr.empty())
605828252d5SJiaqing Zhao         {
606828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "CSR read is empty";
607828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
608828252d5SJiaqing Zhao             return;
609828252d5SJiaqing Zhao         }
610828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CSRString"] = csr;
611828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
612828252d5SJiaqing Zhao             certURI;
613828252d5SJiaqing Zhao         },
614828252d5SJiaqing Zhao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
615828252d5SJiaqing Zhao }
616828252d5SJiaqing Zhao 
617828252d5SJiaqing Zhao inline void
618828252d5SJiaqing Zhao     handleGenerateCSRAction(App& app, const crow::Request& req,
619828252d5SJiaqing Zhao                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
620828252d5SJiaqing Zhao {
6213ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
62245ca1b86SEd Tanous     {
62345ca1b86SEd Tanous         return;
62445ca1b86SEd Tanous     }
625828252d5SJiaqing Zhao     static const int rsaKeyBitLength = 2048;
6265968caeeSMarri Devender Rao 
627828252d5SJiaqing Zhao     // Required parameters
628828252d5SJiaqing Zhao     std::string city;
629828252d5SJiaqing Zhao     std::string commonName;
630828252d5SJiaqing Zhao     std::string country;
631828252d5SJiaqing Zhao     std::string organization;
632828252d5SJiaqing Zhao     std::string organizationalUnit;
633828252d5SJiaqing Zhao     std::string state;
634828252d5SJiaqing Zhao     nlohmann::json certificateCollection;
635828252d5SJiaqing Zhao 
636828252d5SJiaqing Zhao     // Optional parameters
637828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optAlternativeNames =
638828252d5SJiaqing Zhao         std::vector<std::string>();
639828252d5SJiaqing Zhao     std::optional<std::string> optContactPerson = "";
640828252d5SJiaqing Zhao     std::optional<std::string> optChallengePassword = "";
641828252d5SJiaqing Zhao     std::optional<std::string> optEmail = "";
642828252d5SJiaqing Zhao     std::optional<std::string> optGivenName = "";
643828252d5SJiaqing Zhao     std::optional<std::string> optInitials = "";
644828252d5SJiaqing Zhao     std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
645828252d5SJiaqing Zhao     std::optional<std::string> optKeyCurveId = "secp384r1";
646828252d5SJiaqing Zhao     std::optional<std::string> optKeyPairAlgorithm = "EC";
647828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optKeyUsage =
648828252d5SJiaqing Zhao         std::vector<std::string>();
649828252d5SJiaqing Zhao     std::optional<std::string> optSurname = "";
650828252d5SJiaqing Zhao     std::optional<std::string> optUnstructuredName = "";
651828252d5SJiaqing Zhao     if (!json_util::readJsonAction(
652828252d5SJiaqing Zhao             req, asyncResp->res, "City", city, "CommonName", commonName,
653828252d5SJiaqing Zhao             "ContactPerson", optContactPerson, "Country", country,
654828252d5SJiaqing Zhao             "Organization", organization, "OrganizationalUnit",
655828252d5SJiaqing Zhao             organizationalUnit, "State", state, "CertificateCollection",
656828252d5SJiaqing Zhao             certificateCollection, "AlternativeNames", optAlternativeNames,
657828252d5SJiaqing Zhao             "ChallengePassword", optChallengePassword, "Email", optEmail,
658828252d5SJiaqing Zhao             "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
659828252d5SJiaqing Zhao             optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
660828252d5SJiaqing Zhao             optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
661828252d5SJiaqing Zhao             "UnstructuredName", optUnstructuredName))
662828252d5SJiaqing Zhao     {
663828252d5SJiaqing Zhao         return;
6645968caeeSMarri Devender Rao     }
6655968caeeSMarri Devender Rao 
666828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
667828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
668828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
669828252d5SJiaqing Zhao     // value
670828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
6715968caeeSMarri Devender Rao     {
672828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
673828252d5SJiaqing Zhao                                               "ChallengePassword");
674828252d5SJiaqing Zhao         return;
675828252d5SJiaqing Zhao     }
676828252d5SJiaqing Zhao 
677828252d5SJiaqing Zhao     std::string certURI;
678828252d5SJiaqing Zhao     if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
679828252d5SJiaqing Zhao                                       "@odata.id", certURI))
680828252d5SJiaqing Zhao     {
681828252d5SJiaqing Zhao         return;
682828252d5SJiaqing Zhao     }
683828252d5SJiaqing Zhao 
684828252d5SJiaqing Zhao     std::string objectPath;
685828252d5SJiaqing Zhao     std::string service;
686828252d5SJiaqing Zhao     if (certURI.starts_with(
687828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
688828252d5SJiaqing Zhao     {
689828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
690828252d5SJiaqing Zhao         service = certs::httpsServiceName;
691828252d5SJiaqing Zhao     }
692828252d5SJiaqing Zhao     else if (certURI.starts_with(
693828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
694828252d5SJiaqing Zhao     {
695828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
696828252d5SJiaqing Zhao         service = certs::ldapServiceName;
697828252d5SJiaqing Zhao     }
698828252d5SJiaqing Zhao     else
699828252d5SJiaqing Zhao     {
700828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
701828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
702828252d5SJiaqing Zhao         return;
703828252d5SJiaqing Zhao     }
704828252d5SJiaqing Zhao 
705828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
706828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
707828252d5SJiaqing Zhao     {
708828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
709828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
710828252d5SJiaqing Zhao         return;
711828252d5SJiaqing Zhao     }
712828252d5SJiaqing Zhao 
713828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
714828252d5SJiaqing Zhao     // time consumed in generating private key
715828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
716828252d5SJiaqing Zhao     {
717828252d5SJiaqing Zhao         messages::propertyValueNotInList(
718828252d5SJiaqing Zhao             asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength");
719828252d5SJiaqing Zhao         return;
720828252d5SJiaqing Zhao     }
721828252d5SJiaqing Zhao 
722828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
723828252d5SJiaqing Zhao     if (certURI.starts_with(
724828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
725828252d5SJiaqing Zhao     {
726828252d5SJiaqing Zhao         if (optKeyUsage->empty())
727828252d5SJiaqing Zhao         {
728828252d5SJiaqing Zhao             optKeyUsage->push_back("ServerAuthentication");
729828252d5SJiaqing Zhao         }
730828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
731828252d5SJiaqing Zhao         {
732828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
733828252d5SJiaqing Zhao             {
734828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
735828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
736828252d5SJiaqing Zhao                 return;
737828252d5SJiaqing Zhao             }
738828252d5SJiaqing Zhao         }
739828252d5SJiaqing Zhao         else
740828252d5SJiaqing Zhao         {
741828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
742828252d5SJiaqing Zhao                                                   "GenerateCSR");
743828252d5SJiaqing Zhao             return;
744828252d5SJiaqing Zhao         }
745828252d5SJiaqing Zhao     }
746828252d5SJiaqing Zhao     else if (certURI.starts_with(
747828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
748828252d5SJiaqing Zhao     {
749828252d5SJiaqing Zhao         if (optKeyUsage->empty())
750828252d5SJiaqing Zhao         {
751828252d5SJiaqing Zhao             optKeyUsage->push_back("ClientAuthentication");
752828252d5SJiaqing Zhao         }
753828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
754828252d5SJiaqing Zhao         {
755828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
756828252d5SJiaqing Zhao             {
757828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
758828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
759828252d5SJiaqing Zhao                 return;
760828252d5SJiaqing Zhao             }
761828252d5SJiaqing Zhao         }
762828252d5SJiaqing Zhao         else
763828252d5SJiaqing Zhao         {
764828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
765828252d5SJiaqing Zhao                                                   "GenerateCSR");
766828252d5SJiaqing Zhao             return;
767828252d5SJiaqing Zhao         }
768828252d5SJiaqing Zhao     }
769828252d5SJiaqing Zhao 
770828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
771828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
772828252d5SJiaqing Zhao     static const int timeOut = 10;
773828252d5SJiaqing Zhao     if (csrMatcher)
774828252d5SJiaqing Zhao     {
775828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
776828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
777828252d5SJiaqing Zhao         return;
778828252d5SJiaqing Zhao     }
779828252d5SJiaqing Zhao 
780828252d5SJiaqing Zhao     // Make this static so it survives outside this method
781828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
782828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
783828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
784828252d5SJiaqing Zhao         csrMatcher = nullptr;
785828252d5SJiaqing Zhao         if (ec)
786828252d5SJiaqing Zhao         {
787828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
788828252d5SJiaqing Zhao             // before completion.
789828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
790828252d5SJiaqing Zhao             {
791828252d5SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
792828252d5SJiaqing Zhao             }
793828252d5SJiaqing Zhao             return;
794828252d5SJiaqing Zhao         }
795828252d5SJiaqing Zhao         BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
796828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
797828252d5SJiaqing Zhao     });
798828252d5SJiaqing Zhao 
799828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
800828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
801828252d5SJiaqing Zhao     std::string match("type='signal',"
802828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
803828252d5SJiaqing Zhao                       "path='" +
804828252d5SJiaqing Zhao                       objectPath +
805828252d5SJiaqing Zhao                       "',"
806828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
807828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
808828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
809828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
810828252d5SJiaqing Zhao         timeout.cancel();
811828252d5SJiaqing Zhao         if (m.is_method_error())
812828252d5SJiaqing Zhao         {
813828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "Dbus method error!!!";
814828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
815828252d5SJiaqing Zhao             return;
816828252d5SJiaqing Zhao         }
817828252d5SJiaqing Zhao 
818828252d5SJiaqing Zhao         dbus::utility::DBusInteracesMap interfacesProperties;
819828252d5SJiaqing Zhao 
820828252d5SJiaqing Zhao         sdbusplus::message::object_path csrObjectPath;
821828252d5SJiaqing Zhao         m.read(csrObjectPath, interfacesProperties);
822828252d5SJiaqing Zhao         BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
823828252d5SJiaqing Zhao         for (const auto& interface : interfacesProperties)
824828252d5SJiaqing Zhao         {
825828252d5SJiaqing Zhao             if (interface.first == "xyz.openbmc_project.Certs.CSR")
826828252d5SJiaqing Zhao             {
827828252d5SJiaqing Zhao                 getCSR(asyncResp, certURI, service, objectPath,
828828252d5SJiaqing Zhao                        csrObjectPath.str);
829828252d5SJiaqing Zhao                 break;
830828252d5SJiaqing Zhao             }
831828252d5SJiaqing Zhao         }
832828252d5SJiaqing Zhao         });
833828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
8345e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec, const std::string&) {
835828252d5SJiaqing Zhao         if (ec)
836828252d5SJiaqing Zhao         {
837828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
838828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
839828252d5SJiaqing Zhao             return;
840828252d5SJiaqing Zhao         }
841828252d5SJiaqing Zhao         },
842828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
843828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
844828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
845828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
846828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
847828252d5SJiaqing Zhao         *optUnstructuredName);
848828252d5SJiaqing Zhao }
849828252d5SJiaqing Zhao 
850828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
851828252d5SJiaqing Zhao {
852828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
853828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
854002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
855828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
856828252d5SJiaqing Zhao 
857828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
858828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
859828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
860828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
861828252d5SJiaqing Zhao 
862828252d5SJiaqing Zhao     BMCWEB_ROUTE(
863828252d5SJiaqing Zhao         app,
864828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
865828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
866828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
867828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
868828252d5SJiaqing Zhao 
869828252d5SJiaqing Zhao     BMCWEB_ROUTE(
870828252d5SJiaqing Zhao         app,
871828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
872828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
873828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
874828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
875828252d5SJiaqing Zhao } // requestRoutesCertificateService
876828252d5SJiaqing Zhao 
877828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
878828252d5SJiaqing Zhao     App& app, const crow::Request& req,
879828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
880828252d5SJiaqing Zhao {
8813ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
88245ca1b86SEd Tanous     {
88345ca1b86SEd Tanous         return;
88445ca1b86SEd Tanous     }
8851476687dSEd Tanous 
8861476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
8871476687dSEd Tanous         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
8881476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
8891476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
8901476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8911476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
8921476687dSEd Tanous         "A Collection of HTTPS certificate instances";
8938d1b46d7Szhanghch05 
894d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
895d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
896d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
897828252d5SJiaqing Zhao }
8985968caeeSMarri Devender Rao 
899828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
900828252d5SJiaqing Zhao     App& app, const crow::Request& req,
901828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
902828252d5SJiaqing Zhao {
9033ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
90445ca1b86SEd Tanous     {
90545ca1b86SEd Tanous         return;
90645ca1b86SEd Tanous     }
9075968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
9088d1b46d7Szhanghch05 
9091476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
9101476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
9115968caeeSMarri Devender Rao 
912002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
91358eb238fSKowalski, Kamil 
91458eb238fSKowalski, Kamil     if (certFileBody.empty())
91558eb238fSKowalski, Kamil     {
9160fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
917a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
91858eb238fSKowalski, Kamil         return;
91958eb238fSKowalski, Kamil     }
92058eb238fSKowalski, Kamil 
9215968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
92258eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
9235968caeeSMarri Devender Rao 
9245968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
9255e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
926656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9275968caeeSMarri Devender Rao         if (ec)
9285968caeeSMarri Devender Rao         {
9295968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9305968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
9315968caeeSMarri Devender Rao             return;
9325968caeeSMarri Devender Rao         }
933717b9802SJiaqing Zhao 
934717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
935717b9802SJiaqing Zhao         std::string certId = path.filename();
9361e312598SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
9371e312598SJiaqing Zhao             "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
9381e312598SJiaqing Zhao             "Certificates", certId);
939828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
940828252d5SJiaqing Zhao                                  certId, certURL, "HTTPS Certificate");
9415968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9425968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
9435968caeeSMarri Devender Rao         },
944828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
945828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
946828252d5SJiaqing Zhao }
9475968caeeSMarri Devender Rao 
948828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
949828252d5SJiaqing Zhao     App& app, const crow::Request& req,
950828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
9517e860f15SJohn Edward Broadbent {
9523ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
95345ca1b86SEd Tanous     {
95445ca1b86SEd Tanous         return;
95545ca1b86SEd Tanous     }
9567e860f15SJohn Edward Broadbent 
957828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id;
958828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
959828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
960828252d5SJiaqing Zhao         "Certificates", id);
961828252d5SJiaqing Zhao     std::string objPath =
962828252d5SJiaqing Zhao         sdbusplus::message::object_path(certs::httpsObjectPath) / id;
963828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
964828252d5SJiaqing Zhao                              certURL, "HTTPS Certificate");
9657e860f15SJohn Edward Broadbent }
96637cce918SMarri Devender Rao 
967828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
96837cce918SMarri Devender Rao {
969828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
970828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
971ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
972828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
973828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
974828252d5SJiaqing Zhao 
975828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
976828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
977828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
978828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
979828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
980828252d5SJiaqing Zhao 
981828252d5SJiaqing Zhao     BMCWEB_ROUTE(
982828252d5SJiaqing Zhao         app,
983828252d5SJiaqing Zhao         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
984828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
985002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
986828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
987828252d5SJiaqing Zhao }
988828252d5SJiaqing Zhao 
989828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
990828252d5SJiaqing Zhao     App& app, const crow::Request& req,
991828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
992828252d5SJiaqing Zhao {
9933ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
99445ca1b86SEd Tanous     {
99545ca1b86SEd Tanous         return;
99645ca1b86SEd Tanous     }
9971476687dSEd Tanous 
9981476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
9991476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
10001476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
10011476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
10021476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10031476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
10041476687dSEd Tanous         "A Collection of LDAP certificate instances";
10058d1b46d7Szhanghch05 
1006d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
1007d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1008d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1009828252d5SJiaqing Zhao }
101037cce918SMarri Devender Rao 
1011828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1012828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1013828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1014828252d5SJiaqing Zhao {
10153ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101645ca1b86SEd Tanous     {
101745ca1b86SEd Tanous         return;
101845ca1b86SEd Tanous     }
1019002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
102058eb238fSKowalski, Kamil 
102158eb238fSKowalski, Kamil     if (certFileBody.empty())
102258eb238fSKowalski, Kamil     {
1023002d39b4SEd Tanous         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1024a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
102558eb238fSKowalski, Kamil         return;
102658eb238fSKowalski, Kamil     }
102758eb238fSKowalski, Kamil 
102858eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
102958eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
103058eb238fSKowalski, Kamil 
103137cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
10325e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1033656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
103437cce918SMarri Devender Rao         if (ec)
103537cce918SMarri Devender Rao         {
103637cce918SMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
103737cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
103837cce918SMarri Devender Rao             return;
103937cce918SMarri Devender Rao         }
1040717b9802SJiaqing Zhao 
1041717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1042717b9802SJiaqing Zhao         std::string certId = path.filename();
1043828252d5SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
1044828252d5SJiaqing Zhao             "redfish", "v1", "AccountService", "LDAP", "Certificates", certId);
1045828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1046828252d5SJiaqing Zhao                                  certId, certURL, "LDAP Certificate");
104737cce918SMarri Devender Rao         BMCWEB_LOG_DEBUG << "LDAP certificate install file="
104837cce918SMarri Devender Rao                          << certFile->getCertFilePath();
104937cce918SMarri Devender Rao         },
1050828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1051828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1052828252d5SJiaqing Zhao }
105337cce918SMarri Devender Rao 
1054828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1055828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1056828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
105737cce918SMarri Devender Rao {
10583ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
105945ca1b86SEd Tanous     {
106045ca1b86SEd Tanous         return;
106145ca1b86SEd Tanous     }
1062717b9802SJiaqing Zhao 
1063717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id;
10641e312598SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
10651e312598SJiaqing Zhao         "redfish", "v1", "AccountService", "LDAP", "Certificates", id);
1066717b9802SJiaqing Zhao     std::string objPath =
1067717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1068717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1069717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1070828252d5SJiaqing Zhao }
1071828252d5SJiaqing Zhao 
107299612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
107399612247SJiaqing Zhao     App& app, const crow::Request& req,
107499612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
107599612247SJiaqing Zhao {
107699612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
107799612247SJiaqing Zhao     {
107899612247SJiaqing Zhao         return;
107999612247SJiaqing Zhao     }
108099612247SJiaqing Zhao 
108199612247SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Delete LDAP Certificate ID=" << id;
108299612247SJiaqing Zhao     std::string objPath =
108399612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
108499612247SJiaqing Zhao 
108599612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
108699612247SJiaqing Zhao }
108799612247SJiaqing Zhao 
1088828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1089cfcd5f6bSMarri Devender Rao {
1090828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1091828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1092828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1093828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1094828252d5SJiaqing Zhao 
1095828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1096828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1097828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1098828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1099828252d5SJiaqing Zhao 
1100828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1101ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1102002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1103828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
110499612247SJiaqing Zhao 
110599612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
110699612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
110799612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
110899612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1109828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1110828252d5SJiaqing Zhao 
1111828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1112828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1113828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1114828252d5SJiaqing Zhao {
11153ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111645ca1b86SEd Tanous     {
111745ca1b86SEd Tanous         return;
111845ca1b86SEd Tanous     }
11191476687dSEd Tanous 
11201476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
11211476687dSEd Tanous         "/redfish/v1/Managers/bmc/Truststore/Certificates/";
11221476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11231476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1124002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11251476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
11261476687dSEd Tanous         "A Collection of TrustStore certificate instances";
11278d1b46d7Szhanghch05 
1128d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1129d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1130d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1131828252d5SJiaqing Zhao }
1132cfcd5f6bSMarri Devender Rao 
1133828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1134828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1135828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1136828252d5SJiaqing Zhao {
11373ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
113845ca1b86SEd Tanous     {
113945ca1b86SEd Tanous         return;
114045ca1b86SEd Tanous     }
1141002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1142a08752f5SZbigniew Kurzynski 
1143a08752f5SZbigniew Kurzynski     if (certFileBody.empty())
1144a08752f5SZbigniew Kurzynski     {
11450fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1146a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1147a08752f5SZbigniew Kurzynski         return;
1148a08752f5SZbigniew Kurzynski     }
1149a08752f5SZbigniew Kurzynski 
1150a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1151a08752f5SZbigniew Kurzynski         std::make_shared<CertificateFile>(certFileBody);
1152cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
11535e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1154656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1155cfcd5f6bSMarri Devender Rao         if (ec)
1156cfcd5f6bSMarri Devender Rao         {
1157cfcd5f6bSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1158cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1159cfcd5f6bSMarri Devender Rao             return;
1160cfcd5f6bSMarri Devender Rao         }
1161656ec7e3SZbigniew Kurzynski 
1162717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1163717b9802SJiaqing Zhao         std::string certId = path.filename();
1164828252d5SJiaqing Zhao         const boost::urls::url certURL =
1165828252d5SJiaqing Zhao             crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1166828252d5SJiaqing Zhao                                          "Truststore", "Certificates", certId);
1167717b9802SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath,
1168828252d5SJiaqing Zhao                                  certs::authorityServiceName, certId, certURL,
1169828252d5SJiaqing Zhao                                  "TrustStore Certificate");
11700fda0f12SGeorge Liu         BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1171cfcd5f6bSMarri Devender Rao                          << certFile->getCertFilePath();
1172cfcd5f6bSMarri Devender Rao         },
1173cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
11740fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1175828252d5SJiaqing Zhao }
1176cfcd5f6bSMarri Devender Rao 
1177828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1178828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1179828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1180cfcd5f6bSMarri Devender Rao {
11813ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
118245ca1b86SEd Tanous     {
118345ca1b86SEd Tanous         return;
118445ca1b86SEd Tanous     }
1185717b9802SJiaqing Zhao 
1186717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id;
1187828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
1188828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id);
1189717b9802SJiaqing Zhao     std::string objPath =
1190717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1191828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1192828252d5SJiaqing Zhao                              id, certURL, "TrustStore Certificate");
1193828252d5SJiaqing Zhao }
119407a60299SZbigniew Kurzynski 
1195828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1196828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1197828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1198828252d5SJiaqing Zhao {
11993ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
120045ca1b86SEd Tanous     {
120145ca1b86SEd Tanous         return;
120245ca1b86SEd Tanous     }
120307a60299SZbigniew Kurzynski 
1204717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id;
1205717b9802SJiaqing Zhao     std::string objPath =
1206717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
120707a60299SZbigniew Kurzynski 
12087a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1209828252d5SJiaqing Zhao }
1210828252d5SJiaqing Zhao 
1211828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1212828252d5SJiaqing Zhao {
1213828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1214828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1215828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1216828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1217828252d5SJiaqing Zhao 
1218828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1219828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1220828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1221828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1222828252d5SJiaqing Zhao 
1223828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1224828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1225828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1226828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1227828252d5SJiaqing Zhao 
1228828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1229828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1230828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1231828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
12327e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
12335968caeeSMarri Devender Rao } // namespace redfish
1234