xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision cf9e417d3b88eb12f8c6a9d007d6a63c3eeb94f4)
15968caeeSMarri Devender Rao #pragma once
25968caeeSMarri Devender Rao 
37a1dbc48SGeorge Liu #include "dbus_utility.hpp"
49b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp"
59b12d1f9SKrzysztof Grobelny 
67e860f15SJohn Edward Broadbent #include <app.hpp>
7d9f6c621SEd Tanous #include <async_resp.hpp>
890d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp>
9d9f6c621SEd Tanous #include <http_response.hpp>
1045ca1b86SEd Tanous #include <query.hpp>
11ed398213SEd Tanous #include <registries/privilege_registry.hpp>
129b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
139b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
141214b7e7SGunnar Mills 
157a1dbc48SGeorge Liu #include <array>
167a1dbc48SGeorge Liu #include <string_view>
177a1dbc48SGeorge Liu 
185968caeeSMarri Devender Rao namespace redfish
195968caeeSMarri Devender Rao {
205968caeeSMarri Devender Rao namespace certs
215968caeeSMarri Devender Rao {
225968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
235968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
2407a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
255968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
265968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
275968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
2837cce918SMarri Devender Rao constexpr char const* httpsServiceName =
2937cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
3037cce918SMarri Devender Rao constexpr char const* ldapServiceName =
3137cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
32cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName =
33cfcd5f6bSMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
34c6a8dfb1SJiaqing Zhao constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
35c6a8dfb1SJiaqing Zhao constexpr char const* httpsObjectPath =
36c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
37c6a8dfb1SJiaqing Zhao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
38cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath =
39cfcd5f6bSMarri Devender Rao     "/xyz/openbmc_project/certs/authority/ldap";
405968caeeSMarri Devender Rao } // namespace certs
415968caeeSMarri Devender Rao 
425968caeeSMarri Devender Rao /**
435968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
445968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
455968caeeSMarri Devender Rao  * are installed.
465968caeeSMarri Devender Rao  */
477e860f15SJohn Edward Broadbent 
488d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
498d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5058eb238fSKowalski, Kamil     const crow::Request& req)
5158eb238fSKowalski, Kamil {
5258eb238fSKowalski, Kamil     nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
5358eb238fSKowalski, Kamil 
5458eb238fSKowalski, Kamil     if (reqJson.is_discarded())
5558eb238fSKowalski, Kamil     {
5658eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
5758eb238fSKowalski, Kamil         return req.body;
5858eb238fSKowalski, Kamil     }
5958eb238fSKowalski, Kamil 
6058eb238fSKowalski, Kamil     std::string certificate;
6158eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
6258eb238fSKowalski, Kamil 
6315ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
6415ed6780SWilly Tu                                   certificate, "CertificateType",
6515ed6780SWilly Tu                                   certificateType))
6658eb238fSKowalski, Kamil     {
6758eb238fSKowalski, Kamil         BMCWEB_LOG_ERROR << "Required parameters are missing";
6858eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
69abb93cddSEd Tanous         return {};
7058eb238fSKowalski, Kamil     }
7158eb238fSKowalski, Kamil 
7258eb238fSKowalski, Kamil     if (*certificateType != "PEM")
7358eb238fSKowalski, Kamil     {
7458eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
7558eb238fSKowalski, Kamil                                          "CertificateType");
76abb93cddSEd Tanous         return {};
7758eb238fSKowalski, Kamil     }
7858eb238fSKowalski, Kamil 
7958eb238fSKowalski, Kamil     return certificate;
8058eb238fSKowalski, Kamil }
8158eb238fSKowalski, Kamil 
825968caeeSMarri Devender Rao /**
835968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
845968caeeSMarri Devender Rao  */
855968caeeSMarri Devender Rao class CertificateFile
865968caeeSMarri Devender Rao {
875968caeeSMarri Devender Rao   public:
885968caeeSMarri Devender Rao     CertificateFile() = delete;
895968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
905968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
915968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
925968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
934e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
945968caeeSMarri Devender Rao     {
9572d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
965207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
975207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
985207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
99e662eae8SEd Tanous         if (tempDirectory != nullptr)
1005968caeeSMarri Devender Rao         {
1015968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1025968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
1035968caeeSMarri Devender Rao             std::ofstream out(certificateFile, std::ofstream::out |
1045968caeeSMarri Devender Rao                                                    std::ofstream::binary |
1055968caeeSMarri Devender Rao                                                    std::ofstream::trunc);
1065968caeeSMarri Devender Rao             out << certString;
1075968caeeSMarri Devender Rao             out.close();
1088cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Creating certificate file"
1098cc8edecSEd Tanous                              << certificateFile.string();
1105968caeeSMarri Devender Rao         }
1115968caeeSMarri Devender Rao     }
1125968caeeSMarri Devender Rao     ~CertificateFile()
1135968caeeSMarri Devender Rao     {
1145968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1155968caeeSMarri Devender Rao         {
1168cc8edecSEd Tanous             BMCWEB_LOG_DEBUG << "Removing certificate file"
1178cc8edecSEd Tanous                              << certificateFile.string();
11823a21a1cSEd Tanous             std::error_code ec;
11923a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
12023a21a1cSEd Tanous             if (ec)
1215968caeeSMarri Devender Rao             {
1225968caeeSMarri Devender Rao                 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
1238cc8edecSEd Tanous                                  << certDirectory.string();
1245968caeeSMarri Devender Rao             }
1255968caeeSMarri Devender Rao         }
1265968caeeSMarri Devender Rao     }
1275968caeeSMarri Devender Rao     std::string getCertFilePath()
1285968caeeSMarri Devender Rao     {
1295968caeeSMarri Devender Rao         return certificateFile;
1305968caeeSMarri Devender Rao     }
1315968caeeSMarri Devender Rao 
1325968caeeSMarri Devender Rao   private:
1335968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1345968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1355968caeeSMarri Devender Rao };
1365968caeeSMarri Devender Rao 
1375968caeeSMarri Devender Rao /**
1384e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1395968caeeSMarri Devender Rao  *
1405968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1415968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1425968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1435968caeeSMarri Devender Rao  * @return None
1445968caeeSMarri Devender Rao  */
1455968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
1465968caeeSMarri Devender Rao                                       const std::string_view value)
1475968caeeSMarri Devender Rao {
1485968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1495968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1505968caeeSMarri Devender Rao     while (i != value.end())
1515968caeeSMarri Devender Rao     {
1525968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1535968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1545968caeeSMarri Devender Rao         {
15517a897dfSManojkiran Eda             ++i;
1565968caeeSMarri Devender Rao         }
1575968caeeSMarri Devender Rao         if (i == value.end())
1585968caeeSMarri Devender Rao         {
1595968caeeSMarri Devender Rao             break;
1605968caeeSMarri Devender Rao         }
161271584abSEd Tanous         const std::string_view key(tokenBegin,
162271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
16317a897dfSManojkiran Eda         ++i;
1645968caeeSMarri Devender Rao         tokenBegin = i;
1655968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
1665968caeeSMarri Devender Rao         {
16717a897dfSManojkiran Eda             ++i;
1685968caeeSMarri Devender Rao         }
169271584abSEd Tanous         const std::string_view val(tokenBegin,
170271584abSEd Tanous                                    static_cast<size_t>(i - tokenBegin));
1715968caeeSMarri Devender Rao         if (key == "L")
1725968caeeSMarri Devender Rao         {
1735968caeeSMarri Devender Rao             out["City"] = val;
1745968caeeSMarri Devender Rao         }
1755968caeeSMarri Devender Rao         else if (key == "CN")
1765968caeeSMarri Devender Rao         {
1775968caeeSMarri Devender Rao             out["CommonName"] = val;
1785968caeeSMarri Devender Rao         }
1795968caeeSMarri Devender Rao         else if (key == "C")
1805968caeeSMarri Devender Rao         {
1815968caeeSMarri Devender Rao             out["Country"] = val;
1825968caeeSMarri Devender Rao         }
1835968caeeSMarri Devender Rao         else if (key == "O")
1845968caeeSMarri Devender Rao         {
1855968caeeSMarri Devender Rao             out["Organization"] = val;
1865968caeeSMarri Devender Rao         }
1875968caeeSMarri Devender Rao         else if (key == "OU")
1885968caeeSMarri Devender Rao         {
1895968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
1905968caeeSMarri Devender Rao         }
1915968caeeSMarri Devender Rao         else if (key == "ST")
1925968caeeSMarri Devender Rao         {
1935968caeeSMarri Devender Rao             out["State"] = val;
1945968caeeSMarri Devender Rao         }
1955968caeeSMarri Devender Rao         // skip comma character
1965968caeeSMarri Devender Rao         if (i != value.end())
1975968caeeSMarri Devender Rao         {
19817a897dfSManojkiran Eda             ++i;
1995968caeeSMarri Devender Rao         }
2005968caeeSMarri Devender Rao     }
2015968caeeSMarri Devender Rao }
2025968caeeSMarri Devender Rao 
2035968caeeSMarri Devender Rao /**
204d3f92ce7SJiaqing Zhao  * @brief Retrieve the installed certificate list
205d3f92ce7SJiaqing Zhao  *
206d3f92ce7SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
207d3f92ce7SJiaqing Zhao  * @param[in] basePath DBus object path to search
208d3f92ce7SJiaqing Zhao  * @param[in] listPtr Json pointer to the list in asyncResp
209d3f92ce7SJiaqing Zhao  * @param[in] countPtr Json pointer to the count in asyncResp
210d3f92ce7SJiaqing Zhao  * @return None
211d3f92ce7SJiaqing Zhao  */
212d3f92ce7SJiaqing Zhao static void
213d3f92ce7SJiaqing Zhao     getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
214d3f92ce7SJiaqing Zhao                        const std::string& basePath,
215d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& listPtr,
216d3f92ce7SJiaqing Zhao                        const nlohmann::json::json_pointer& countPtr)
217d3f92ce7SJiaqing Zhao {
2187a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
2197a1dbc48SGeorge Liu         certs::certPropIntf};
2207a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
2217a1dbc48SGeorge Liu         basePath, 0, interfaces,
222d3f92ce7SJiaqing Zhao         [asyncResp, listPtr, countPtr](
2237a1dbc48SGeorge Liu             const boost::system::error_code& ec,
224d3f92ce7SJiaqing Zhao             const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
225d3f92ce7SJiaqing Zhao         if (ec)
226d3f92ce7SJiaqing Zhao         {
227d3f92ce7SJiaqing Zhao             BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
228d3f92ce7SJiaqing Zhao             messages::internalError(asyncResp->res);
229d3f92ce7SJiaqing Zhao             return;
230d3f92ce7SJiaqing Zhao         }
231d3f92ce7SJiaqing Zhao 
232d3f92ce7SJiaqing Zhao         nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
233d3f92ce7SJiaqing Zhao         links = nlohmann::json::array();
234d3f92ce7SJiaqing Zhao         for (const auto& certPath : certPaths)
235d3f92ce7SJiaqing Zhao         {
236d3f92ce7SJiaqing Zhao             sdbusplus::message::object_path objPath(certPath);
237d3f92ce7SJiaqing Zhao             std::string certId = objPath.filename();
238d3f92ce7SJiaqing Zhao             if (certId.empty())
239d3f92ce7SJiaqing Zhao             {
240d3f92ce7SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
241d3f92ce7SJiaqing Zhao                 continue;
242d3f92ce7SJiaqing Zhao             }
243d3f92ce7SJiaqing Zhao 
244d3f92ce7SJiaqing Zhao             boost::urls::url certURL;
245d3f92ce7SJiaqing Zhao             if (objPath.parent_path() == certs::httpsObjectPath)
246d3f92ce7SJiaqing Zhao             {
247d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
248d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
249d3f92ce7SJiaqing Zhao                     "HTTPS", "Certificates", certId);
250d3f92ce7SJiaqing Zhao             }
251d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::ldapObjectPath)
252d3f92ce7SJiaqing Zhao             {
253d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces("redfish", "v1",
254d3f92ce7SJiaqing Zhao                                                        "AccountService", "LDAP",
255d3f92ce7SJiaqing Zhao                                                        "Certificates", certId);
256d3f92ce7SJiaqing Zhao             }
257d3f92ce7SJiaqing Zhao             else if (objPath.parent_path() == certs::authorityObjectPath)
258d3f92ce7SJiaqing Zhao             {
259d3f92ce7SJiaqing Zhao                 certURL = crow::utility::urlFromPieces(
260d3f92ce7SJiaqing Zhao                     "redfish", "v1", "Managers", "bmc", "Truststore",
261d3f92ce7SJiaqing Zhao                     "Certificates", certId);
262d3f92ce7SJiaqing Zhao             }
263d3f92ce7SJiaqing Zhao             else
264d3f92ce7SJiaqing Zhao             {
265d3f92ce7SJiaqing Zhao                 continue;
266d3f92ce7SJiaqing Zhao             }
267d3f92ce7SJiaqing Zhao 
268d3f92ce7SJiaqing Zhao             nlohmann::json::object_t link;
269d3f92ce7SJiaqing Zhao             link["@odata.id"] = certURL;
270d3f92ce7SJiaqing Zhao             links.emplace_back(std::move(link));
271d3f92ce7SJiaqing Zhao         }
272d3f92ce7SJiaqing Zhao 
273d3f92ce7SJiaqing Zhao         asyncResp->res.jsonValue[countPtr] = links.size();
2747a1dbc48SGeorge Liu         });
275d3f92ce7SJiaqing Zhao }
276d3f92ce7SJiaqing Zhao 
277d3f92ce7SJiaqing Zhao /**
2785968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
2795968caeeSMarri Devender Rao  * message
2805968caeeSMarri Devender Rao  *
2815968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
2825968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
2835968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
2845968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
2855968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
2865968caeeSMarri Devender Rao  * @return None
2875968caeeSMarri Devender Rao  */
2885968caeeSMarri Devender Rao static void getCertificateProperties(
2898d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
290e19e97e2SJiaqing Zhao     const std::string& objectPath, const std::string& service,
2911e312598SJiaqing Zhao     const std::string& certId, const boost::urls::url& certURL,
292e19e97e2SJiaqing Zhao     const std::string& name)
2935968caeeSMarri Devender Rao {
2945968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
2955968caeeSMarri Devender Rao                      << " certId=" << certId << " certURl=" << certURL;
2969b12d1f9SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
2979b12d1f9SKrzysztof Grobelny         *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
298b9d36b47SEd Tanous         [asyncResp, certURL, certId,
299b9d36b47SEd Tanous          name](const boost::system::error_code ec,
300b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
3015968caeeSMarri Devender Rao         if (ec)
3025968caeeSMarri Devender Rao         {
3035968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
304d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", certId);
3055968caeeSMarri Devender Rao             return;
3065968caeeSMarri Devender Rao         }
3079b12d1f9SKrzysztof Grobelny 
3089b12d1f9SKrzysztof Grobelny         const std::string* certificateString = nullptr;
3099b12d1f9SKrzysztof Grobelny         const std::vector<std::string>* keyUsage = nullptr;
3109b12d1f9SKrzysztof Grobelny         const std::string* issuer = nullptr;
3119b12d1f9SKrzysztof Grobelny         const std::string* subject = nullptr;
3129b12d1f9SKrzysztof Grobelny         const uint64_t* validNotAfter = nullptr;
3139b12d1f9SKrzysztof Grobelny         const uint64_t* validNotBefore = nullptr;
3149b12d1f9SKrzysztof Grobelny 
3159b12d1f9SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
3169b12d1f9SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "CertificateString",
3179b12d1f9SKrzysztof Grobelny             certificateString, "KeyUsage", keyUsage, "Issuer", issuer,
3189b12d1f9SKrzysztof Grobelny             "Subject", subject, "ValidNotAfter", validNotAfter,
3199b12d1f9SKrzysztof Grobelny             "ValidNotBefore", validNotBefore);
3209b12d1f9SKrzysztof Grobelny 
3219b12d1f9SKrzysztof Grobelny         if (!success)
3229b12d1f9SKrzysztof Grobelny         {
3239b12d1f9SKrzysztof Grobelny             messages::internalError(asyncResp->res);
3249b12d1f9SKrzysztof Grobelny             return;
3259b12d1f9SKrzysztof Grobelny         }
3269b12d1f9SKrzysztof Grobelny 
3271476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = certURL;
3281476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
3291476687dSEd Tanous             "#Certificate.v1_0_0.Certificate";
330e19e97e2SJiaqing Zhao         asyncResp->res.jsonValue["Id"] = certId;
3311476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = name;
3321476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = name;
3335968caeeSMarri Devender Rao         asyncResp->res.jsonValue["CertificateString"] = "";
3349b12d1f9SKrzysztof Grobelny         asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
3359b12d1f9SKrzysztof Grobelny 
3369b12d1f9SKrzysztof Grobelny         if (certificateString != nullptr)
3375968caeeSMarri Devender Rao         {
3389b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["CertificateString"] = *certificateString;
3395968caeeSMarri Devender Rao         }
3409b12d1f9SKrzysztof Grobelny 
3419b12d1f9SKrzysztof Grobelny         if (keyUsage != nullptr)
3425968caeeSMarri Devender Rao         {
3439b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
3445968caeeSMarri Devender Rao         }
3459b12d1f9SKrzysztof Grobelny 
3469b12d1f9SKrzysztof Grobelny         if (issuer != nullptr)
3475968caeeSMarri Devender Rao         {
3489b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
3499b12d1f9SKrzysztof Grobelny                                       *issuer);
3505968caeeSMarri Devender Rao         }
3519b12d1f9SKrzysztof Grobelny 
3529b12d1f9SKrzysztof Grobelny         if (subject != nullptr)
3535968caeeSMarri Devender Rao         {
3549b12d1f9SKrzysztof Grobelny             updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
3559b12d1f9SKrzysztof Grobelny                                       *subject);
3565968caeeSMarri Devender Rao         }
3579b12d1f9SKrzysztof Grobelny 
3589b12d1f9SKrzysztof Grobelny         if (validNotAfter != nullptr)
3595968caeeSMarri Devender Rao         {
3605968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotAfter"] =
3619b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotAfter);
3625968caeeSMarri Devender Rao         }
3639b12d1f9SKrzysztof Grobelny 
3649b12d1f9SKrzysztof Grobelny         if (validNotBefore != nullptr)
3655968caeeSMarri Devender Rao         {
3665968caeeSMarri Devender Rao             asyncResp->res.jsonValue["ValidNotBefore"] =
3679b12d1f9SKrzysztof Grobelny                 redfish::time_utils::getDateTimeUint(*validNotBefore);
3685968caeeSMarri Devender Rao         }
3699b12d1f9SKrzysztof Grobelny 
3701e312598SJiaqing Zhao         asyncResp->res.addHeader(
371d9f6c621SEd Tanous             boost::beast::http::field::location,
372d9f6c621SEd Tanous             std::string_view(certURL.data(), certURL.size()));
3739b12d1f9SKrzysztof Grobelny         });
3745968caeeSMarri Devender Rao }
3755968caeeSMarri Devender Rao 
3767a3a8f7aSJiaqing Zhao static void
3777a3a8f7aSJiaqing Zhao     deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3787a3a8f7aSJiaqing Zhao                       const std::string& service,
3797a3a8f7aSJiaqing Zhao                       const sdbusplus::message::object_path& objectPath)
3807a3a8f7aSJiaqing Zhao {
3817a3a8f7aSJiaqing Zhao     crow::connections::systemBus->async_method_call(
3827a3a8f7aSJiaqing Zhao         [asyncResp,
3837a3a8f7aSJiaqing Zhao          id{objectPath.filename()}](const boost::system::error_code ec) {
3847a3a8f7aSJiaqing Zhao         if (ec)
3857a3a8f7aSJiaqing Zhao         {
3867a3a8f7aSJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Certificate", id);
3877a3a8f7aSJiaqing Zhao             return;
3887a3a8f7aSJiaqing Zhao         }
3897a3a8f7aSJiaqing Zhao         BMCWEB_LOG_INFO << "Certificate deleted";
3907a3a8f7aSJiaqing Zhao         asyncResp->res.result(boost::beast::http::status::no_content);
3917a3a8f7aSJiaqing Zhao         },
3927a3a8f7aSJiaqing Zhao         service, objectPath, certs::objDeleteIntf, "Delete");
3937a3a8f7aSJiaqing Zhao }
3947a3a8f7aSJiaqing Zhao 
395828252d5SJiaqing Zhao inline void handleCertificateServiceGet(
396828252d5SJiaqing Zhao     App& app, const crow::Request& req,
397828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3985968caeeSMarri Devender Rao {
399828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
400828252d5SJiaqing Zhao     {
401828252d5SJiaqing Zhao         return;
402828252d5SJiaqing Zhao     }
403828252d5SJiaqing Zhao 
404828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
405828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
406828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
407828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
408828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
409828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
410828252d5SJiaqing Zhao         "Actions available to manage certificates";
411828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
412828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
413828252d5SJiaqing Zhao     // has permissions ConfigureManager
414828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
415828252d5SJiaqing Zhao         redfish::getUserPrivileges(req.userRole);
416828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
417828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
418828252d5SJiaqing Zhao     {
419828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
420828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
421828252d5SJiaqing Zhao     }
422828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
423828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
424828252d5SJiaqing Zhao     replace["target"] =
425828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
426828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
427828252d5SJiaqing Zhao     allowed.push_back("PEM");
428828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
429828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
430828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
431828252d5SJiaqing Zhao }
432828252d5SJiaqing Zhao 
433828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
434828252d5SJiaqing Zhao     App& app, const crow::Request& req,
435828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
436828252d5SJiaqing Zhao {
437828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
438828252d5SJiaqing Zhao     {
439828252d5SJiaqing Zhao         return;
440828252d5SJiaqing Zhao     }
441828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
442828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
443828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
444828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
445828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
446828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
447828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
448828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
449828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
450828252d5SJiaqing Zhao 
451828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
452828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
453828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
454828252d5SJiaqing Zhao }
455828252d5SJiaqing Zhao 
456828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
457828252d5SJiaqing Zhao     App& app, const crow::Request& req,
458828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
459828252d5SJiaqing Zhao {
4603ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
46145ca1b86SEd Tanous     {
46245ca1b86SEd Tanous         return;
46345ca1b86SEd Tanous     }
4645968caeeSMarri Devender Rao     std::string certificate;
4655968caeeSMarri Devender Rao     nlohmann::json certificateUri;
4665968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
4678d1b46d7Szhanghch05 
468002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
469002d39b4SEd Tanous                                    certificate, "CertificateUri",
470002d39b4SEd Tanous                                    certificateUri, "CertificateType",
471002d39b4SEd Tanous                                    certificateType))
4725968caeeSMarri Devender Rao     {
4735968caeeSMarri Devender Rao         BMCWEB_LOG_ERROR << "Required parameters are missing";
4745968caeeSMarri Devender Rao         messages::internalError(asyncResp->res);
4755968caeeSMarri Devender Rao         return;
4765968caeeSMarri Devender Rao     }
4775968caeeSMarri Devender Rao 
4785968caeeSMarri Devender Rao     if (!certificateType)
4795968caeeSMarri Devender Rao     {
4805968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
4815968caeeSMarri Devender Rao         return;
4825968caeeSMarri Devender Rao     }
4835968caeeSMarri Devender Rao     if (certificateType != "PEM")
4845968caeeSMarri Devender Rao     {
485828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
486828252d5SJiaqing Zhao                                               "ReplaceCertificate");
4875968caeeSMarri Devender Rao         return;
4885968caeeSMarri Devender Rao     }
4895968caeeSMarri Devender Rao 
4905968caeeSMarri Devender Rao     std::string certURI;
4915968caeeSMarri Devender Rao     if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
4925968caeeSMarri Devender Rao                                       "@odata.id", certURI))
4935968caeeSMarri Devender Rao     {
494828252d5SJiaqing Zhao         messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
495828252d5SJiaqing Zhao                                          "CertificateUri");
4965968caeeSMarri Devender Rao         return;
4975968caeeSMarri Devender Rao     }
49875b63a2cSJiaqing Zhao     BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI;
4995968caeeSMarri Devender Rao 
50075b63a2cSJiaqing Zhao     boost::urls::result<boost::urls::url_view> parsedUrl =
50175b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
50275b63a2cSJiaqing Zhao     if (!parsedUrl)
5035968caeeSMarri Devender Rao     {
504828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
505828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
5065968caeeSMarri Devender Rao         return;
5075968caeeSMarri Devender Rao     }
50875b63a2cSJiaqing Zhao 
50975b63a2cSJiaqing Zhao     std::string id;
51075b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
5115968caeeSMarri Devender Rao     std::string name;
51237cce918SMarri Devender Rao     std::string service;
513828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
514828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
515828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5165968caeeSMarri Devender Rao     {
517002d39b4SEd Tanous         objectPath =
51875b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::httpsObjectPath) / id;
5195968caeeSMarri Devender Rao         name = "HTTPS certificate";
52037cce918SMarri Devender Rao         service = certs::httpsServiceName;
52137cce918SMarri Devender Rao     }
52275b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
52375b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
52475b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
52537cce918SMarri Devender Rao     {
526002d39b4SEd Tanous         objectPath =
52775b63a2cSJiaqing Zhao             sdbusplus::message::object_path(certs::ldapObjectPath) / id;
52837cce918SMarri Devender Rao         name = "LDAP certificate";
52937cce918SMarri Devender Rao         service = certs::ldapServiceName;
5305968caeeSMarri Devender Rao     }
53175b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
53275b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
53375b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
534cfcd5f6bSMarri Devender Rao     {
53575b63a2cSJiaqing Zhao         objectPath =
536828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
537cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
538cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
539cfcd5f6bSMarri Devender Rao     }
5405968caeeSMarri Devender Rao     else
5415968caeeSMarri Devender Rao     {
542828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
543828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5445968caeeSMarri Devender Rao         return;
5455968caeeSMarri Devender Rao     }
5465968caeeSMarri Devender Rao 
5475968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
5485968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
5495968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
5501e312598SJiaqing Zhao         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
5515968caeeSMarri Devender Rao          name](const boost::system::error_code ec) {
5525968caeeSMarri Devender Rao         if (ec)
5535968caeeSMarri Devender Rao         {
5545968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
55590d2d1e8SJiaqing Zhao             if (ec.value() ==
55690d2d1e8SJiaqing Zhao                 boost::system::linux_error::bad_request_descriptor)
55790d2d1e8SJiaqing Zhao             {
558828252d5SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
5595968caeeSMarri Devender Rao                 return;
5605968caeeSMarri Devender Rao             }
56190d2d1e8SJiaqing Zhao             messages::internalError(asyncResp->res);
56290d2d1e8SJiaqing Zhao             return;
56390d2d1e8SJiaqing Zhao         }
564828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, service, id, url, name);
5655968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
5665968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
5675968caeeSMarri Devender Rao         },
5685968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
5695968caeeSMarri Devender Rao         certFile->getCertFilePath());
570828252d5SJiaqing Zhao }
5715968caeeSMarri Devender Rao 
572*cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
573828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
5745968caeeSMarri Devender Rao /**
575828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
576828252d5SJiaqing Zhao  *
577828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
578828252d5SJiaqing Zhao  * @param[in] certURI Link to certifiate collection URI
579828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
580828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
581828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
582828252d5SJiaqing Zhao  * @return None
5835968caeeSMarri Devender Rao  */
584828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
585828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
586828252d5SJiaqing Zhao                    const std::string& certObjPath,
587828252d5SJiaqing Zhao                    const std::string& csrObjPath)
5885968caeeSMarri Devender Rao {
589828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
590828252d5SJiaqing Zhao                      << " CSRObjectPath=" << csrObjPath
591828252d5SJiaqing Zhao                      << " service=" << service;
592828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
593828252d5SJiaqing Zhao         [asyncResp, certURI](const boost::system::error_code ec,
594828252d5SJiaqing Zhao                              const std::string& csr) {
595828252d5SJiaqing Zhao         if (ec)
596828252d5SJiaqing Zhao         {
597828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
598828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
599828252d5SJiaqing Zhao             return;
600828252d5SJiaqing Zhao         }
601828252d5SJiaqing Zhao         if (csr.empty())
602828252d5SJiaqing Zhao         {
603828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "CSR read is empty";
604828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
605828252d5SJiaqing Zhao             return;
606828252d5SJiaqing Zhao         }
607828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CSRString"] = csr;
608828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
609828252d5SJiaqing Zhao             certURI;
610828252d5SJiaqing Zhao         },
611828252d5SJiaqing Zhao         service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
612828252d5SJiaqing Zhao }
613828252d5SJiaqing Zhao 
614828252d5SJiaqing Zhao inline void
615828252d5SJiaqing Zhao     handleGenerateCSRAction(App& app, const crow::Request& req,
616828252d5SJiaqing Zhao                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
617828252d5SJiaqing Zhao {
6183ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
61945ca1b86SEd Tanous     {
62045ca1b86SEd Tanous         return;
62145ca1b86SEd Tanous     }
622828252d5SJiaqing Zhao     static const int rsaKeyBitLength = 2048;
6235968caeeSMarri Devender Rao 
624828252d5SJiaqing Zhao     // Required parameters
625828252d5SJiaqing Zhao     std::string city;
626828252d5SJiaqing Zhao     std::string commonName;
627828252d5SJiaqing Zhao     std::string country;
628828252d5SJiaqing Zhao     std::string organization;
629828252d5SJiaqing Zhao     std::string organizationalUnit;
630828252d5SJiaqing Zhao     std::string state;
631828252d5SJiaqing Zhao     nlohmann::json certificateCollection;
632828252d5SJiaqing Zhao 
633828252d5SJiaqing Zhao     // Optional parameters
634828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optAlternativeNames =
635828252d5SJiaqing Zhao         std::vector<std::string>();
636828252d5SJiaqing Zhao     std::optional<std::string> optContactPerson = "";
637828252d5SJiaqing Zhao     std::optional<std::string> optChallengePassword = "";
638828252d5SJiaqing Zhao     std::optional<std::string> optEmail = "";
639828252d5SJiaqing Zhao     std::optional<std::string> optGivenName = "";
640828252d5SJiaqing Zhao     std::optional<std::string> optInitials = "";
641828252d5SJiaqing Zhao     std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
642828252d5SJiaqing Zhao     std::optional<std::string> optKeyCurveId = "secp384r1";
643828252d5SJiaqing Zhao     std::optional<std::string> optKeyPairAlgorithm = "EC";
644828252d5SJiaqing Zhao     std::optional<std::vector<std::string>> optKeyUsage =
645828252d5SJiaqing Zhao         std::vector<std::string>();
646828252d5SJiaqing Zhao     std::optional<std::string> optSurname = "";
647828252d5SJiaqing Zhao     std::optional<std::string> optUnstructuredName = "";
648828252d5SJiaqing Zhao     if (!json_util::readJsonAction(
649828252d5SJiaqing Zhao             req, asyncResp->res, "City", city, "CommonName", commonName,
650828252d5SJiaqing Zhao             "ContactPerson", optContactPerson, "Country", country,
651828252d5SJiaqing Zhao             "Organization", organization, "OrganizationalUnit",
652828252d5SJiaqing Zhao             organizationalUnit, "State", state, "CertificateCollection",
653828252d5SJiaqing Zhao             certificateCollection, "AlternativeNames", optAlternativeNames,
654828252d5SJiaqing Zhao             "ChallengePassword", optChallengePassword, "Email", optEmail,
655828252d5SJiaqing Zhao             "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
656828252d5SJiaqing Zhao             optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
657828252d5SJiaqing Zhao             optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
658828252d5SJiaqing Zhao             "UnstructuredName", optUnstructuredName))
659828252d5SJiaqing Zhao     {
660828252d5SJiaqing Zhao         return;
6615968caeeSMarri Devender Rao     }
6625968caeeSMarri Devender Rao 
663828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
664828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
665828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
666828252d5SJiaqing Zhao     // value
667828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
6685968caeeSMarri Devender Rao     {
669828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
670828252d5SJiaqing Zhao                                               "ChallengePassword");
671828252d5SJiaqing Zhao         return;
672828252d5SJiaqing Zhao     }
673828252d5SJiaqing Zhao 
674828252d5SJiaqing Zhao     std::string certURI;
675828252d5SJiaqing Zhao     if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
676828252d5SJiaqing Zhao                                       "@odata.id", certURI))
677828252d5SJiaqing Zhao     {
678828252d5SJiaqing Zhao         return;
679828252d5SJiaqing Zhao     }
680828252d5SJiaqing Zhao 
681828252d5SJiaqing Zhao     std::string objectPath;
682828252d5SJiaqing Zhao     std::string service;
683828252d5SJiaqing Zhao     if (certURI.starts_with(
684828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
685828252d5SJiaqing Zhao     {
686828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
687828252d5SJiaqing Zhao         service = certs::httpsServiceName;
688828252d5SJiaqing Zhao     }
689828252d5SJiaqing Zhao     else if (certURI.starts_with(
690828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
691828252d5SJiaqing Zhao     {
692828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
693828252d5SJiaqing Zhao         service = certs::ldapServiceName;
694828252d5SJiaqing Zhao     }
695828252d5SJiaqing Zhao     else
696828252d5SJiaqing Zhao     {
697828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
698828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
699828252d5SJiaqing Zhao         return;
700828252d5SJiaqing Zhao     }
701828252d5SJiaqing Zhao 
702828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
703828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
704828252d5SJiaqing Zhao     {
705828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
706828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
707828252d5SJiaqing Zhao         return;
708828252d5SJiaqing Zhao     }
709828252d5SJiaqing Zhao 
710828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
711828252d5SJiaqing Zhao     // time consumed in generating private key
712828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
713828252d5SJiaqing Zhao     {
714828252d5SJiaqing Zhao         messages::propertyValueNotInList(
715828252d5SJiaqing Zhao             asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength");
716828252d5SJiaqing Zhao         return;
717828252d5SJiaqing Zhao     }
718828252d5SJiaqing Zhao 
719828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
720828252d5SJiaqing Zhao     if (certURI.starts_with(
721828252d5SJiaqing Zhao             "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
722828252d5SJiaqing Zhao     {
723828252d5SJiaqing Zhao         if (optKeyUsage->empty())
724828252d5SJiaqing Zhao         {
725828252d5SJiaqing Zhao             optKeyUsage->push_back("ServerAuthentication");
726828252d5SJiaqing Zhao         }
727828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
728828252d5SJiaqing Zhao         {
729828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
730828252d5SJiaqing Zhao             {
731828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
732828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
733828252d5SJiaqing Zhao                 return;
734828252d5SJiaqing Zhao             }
735828252d5SJiaqing Zhao         }
736828252d5SJiaqing Zhao         else
737828252d5SJiaqing Zhao         {
738828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
739828252d5SJiaqing Zhao                                                   "GenerateCSR");
740828252d5SJiaqing Zhao             return;
741828252d5SJiaqing Zhao         }
742828252d5SJiaqing Zhao     }
743828252d5SJiaqing Zhao     else if (certURI.starts_with(
744828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
745828252d5SJiaqing Zhao     {
746828252d5SJiaqing Zhao         if (optKeyUsage->empty())
747828252d5SJiaqing Zhao         {
748828252d5SJiaqing Zhao             optKeyUsage->push_back("ClientAuthentication");
749828252d5SJiaqing Zhao         }
750828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
751828252d5SJiaqing Zhao         {
752828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
753828252d5SJiaqing Zhao             {
754828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
755828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
756828252d5SJiaqing Zhao                 return;
757828252d5SJiaqing Zhao             }
758828252d5SJiaqing Zhao         }
759828252d5SJiaqing Zhao         else
760828252d5SJiaqing Zhao         {
761828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
762828252d5SJiaqing Zhao                                                   "GenerateCSR");
763828252d5SJiaqing Zhao             return;
764828252d5SJiaqing Zhao         }
765828252d5SJiaqing Zhao     }
766828252d5SJiaqing Zhao 
767828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
768828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
769828252d5SJiaqing Zhao     static const int timeOut = 10;
770828252d5SJiaqing Zhao     if (csrMatcher)
771828252d5SJiaqing Zhao     {
772828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
773828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
774828252d5SJiaqing Zhao         return;
775828252d5SJiaqing Zhao     }
776828252d5SJiaqing Zhao 
777828252d5SJiaqing Zhao     // Make this static so it survives outside this method
778828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
779828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
780828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
781828252d5SJiaqing Zhao         csrMatcher = nullptr;
782828252d5SJiaqing Zhao         if (ec)
783828252d5SJiaqing Zhao         {
784828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
785828252d5SJiaqing Zhao             // before completion.
786828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
787828252d5SJiaqing Zhao             {
788828252d5SJiaqing Zhao                 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
789828252d5SJiaqing Zhao             }
790828252d5SJiaqing Zhao             return;
791828252d5SJiaqing Zhao         }
792828252d5SJiaqing Zhao         BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
793828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
794828252d5SJiaqing Zhao     });
795828252d5SJiaqing Zhao 
796828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
797828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
798828252d5SJiaqing Zhao     std::string match("type='signal',"
799828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
800828252d5SJiaqing Zhao                       "path='" +
801828252d5SJiaqing Zhao                       objectPath +
802828252d5SJiaqing Zhao                       "',"
803828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
804828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
805828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
806828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
807828252d5SJiaqing Zhao         timeout.cancel();
808828252d5SJiaqing Zhao         if (m.is_method_error())
809828252d5SJiaqing Zhao         {
810828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "Dbus method error!!!";
811828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
812828252d5SJiaqing Zhao             return;
813828252d5SJiaqing Zhao         }
814828252d5SJiaqing Zhao 
815828252d5SJiaqing Zhao         dbus::utility::DBusInteracesMap interfacesProperties;
816828252d5SJiaqing Zhao 
817828252d5SJiaqing Zhao         sdbusplus::message::object_path csrObjectPath;
818828252d5SJiaqing Zhao         m.read(csrObjectPath, interfacesProperties);
819828252d5SJiaqing Zhao         BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
820828252d5SJiaqing Zhao         for (const auto& interface : interfacesProperties)
821828252d5SJiaqing Zhao         {
822828252d5SJiaqing Zhao             if (interface.first == "xyz.openbmc_project.Certs.CSR")
823828252d5SJiaqing Zhao             {
824828252d5SJiaqing Zhao                 getCSR(asyncResp, certURI, service, objectPath,
825828252d5SJiaqing Zhao                        csrObjectPath.str);
826828252d5SJiaqing Zhao                 break;
827828252d5SJiaqing Zhao             }
828828252d5SJiaqing Zhao         }
829828252d5SJiaqing Zhao         });
830828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
831828252d5SJiaqing Zhao         [asyncResp](const boost::system::error_code ec, const std::string&) {
832828252d5SJiaqing Zhao         if (ec)
833828252d5SJiaqing Zhao         {
834828252d5SJiaqing Zhao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
835828252d5SJiaqing Zhao             messages::internalError(asyncResp->res);
836828252d5SJiaqing Zhao             return;
837828252d5SJiaqing Zhao         }
838828252d5SJiaqing Zhao         },
839828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
840828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
841828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
842828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
843828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
844828252d5SJiaqing Zhao         *optUnstructuredName);
845828252d5SJiaqing Zhao }
846828252d5SJiaqing Zhao 
847828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
848828252d5SJiaqing Zhao {
849828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
850828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
851002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
852828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
853828252d5SJiaqing Zhao 
854828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
855828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
856828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
857828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
858828252d5SJiaqing Zhao 
859828252d5SJiaqing Zhao     BMCWEB_ROUTE(
860828252d5SJiaqing Zhao         app,
861828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
862828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
863828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
864828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
865828252d5SJiaqing Zhao 
866828252d5SJiaqing Zhao     BMCWEB_ROUTE(
867828252d5SJiaqing Zhao         app,
868828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
869828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
870828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
871828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
872828252d5SJiaqing Zhao } // requestRoutesCertificateService
873828252d5SJiaqing Zhao 
874828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
875828252d5SJiaqing Zhao     App& app, const crow::Request& req,
876828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
877828252d5SJiaqing Zhao {
8783ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
87945ca1b86SEd Tanous     {
88045ca1b86SEd Tanous         return;
88145ca1b86SEd Tanous     }
8821476687dSEd Tanous 
8831476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
8841476687dSEd Tanous         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
8851476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
8861476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
8871476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
8881476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
8891476687dSEd Tanous         "A Collection of HTTPS certificate instances";
8908d1b46d7Szhanghch05 
891d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
892d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
893d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
894828252d5SJiaqing Zhao }
8955968caeeSMarri Devender Rao 
896828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
897828252d5SJiaqing Zhao     App& app, const crow::Request& req,
898828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
899828252d5SJiaqing Zhao {
9003ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
90145ca1b86SEd Tanous     {
90245ca1b86SEd Tanous         return;
90345ca1b86SEd Tanous     }
9045968caeeSMarri Devender Rao     BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
9058d1b46d7Szhanghch05 
9061476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
9071476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
9085968caeeSMarri Devender Rao 
909002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
91058eb238fSKowalski, Kamil 
91158eb238fSKowalski, Kamil     if (certFileBody.empty())
91258eb238fSKowalski, Kamil     {
9130fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
914a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
91558eb238fSKowalski, Kamil         return;
91658eb238fSKowalski, Kamil     }
91758eb238fSKowalski, Kamil 
9185968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
91958eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
9205968caeeSMarri Devender Rao 
9215968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
922656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
923656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9245968caeeSMarri Devender Rao         if (ec)
9255968caeeSMarri Devender Rao         {
9265968caeeSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
9275968caeeSMarri Devender Rao             messages::internalError(asyncResp->res);
9285968caeeSMarri Devender Rao             return;
9295968caeeSMarri Devender Rao         }
930717b9802SJiaqing Zhao 
931717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
932717b9802SJiaqing Zhao         std::string certId = path.filename();
9331e312598SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
9341e312598SJiaqing Zhao             "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
9351e312598SJiaqing Zhao             "Certificates", certId);
936828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
937828252d5SJiaqing Zhao                                  certId, certURL, "HTTPS Certificate");
9385968caeeSMarri Devender Rao         BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
9395968caeeSMarri Devender Rao                          << certFile->getCertFilePath();
9405968caeeSMarri Devender Rao         },
941828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
942828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
943828252d5SJiaqing Zhao }
9445968caeeSMarri Devender Rao 
945828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
946828252d5SJiaqing Zhao     App& app, const crow::Request& req,
947828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
9487e860f15SJohn Edward Broadbent {
9493ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
95045ca1b86SEd Tanous     {
95145ca1b86SEd Tanous         return;
95245ca1b86SEd Tanous     }
9537e860f15SJohn Edward Broadbent 
954828252d5SJiaqing Zhao     BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id;
955828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
956828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
957828252d5SJiaqing Zhao         "Certificates", id);
958828252d5SJiaqing Zhao     std::string objPath =
959828252d5SJiaqing Zhao         sdbusplus::message::object_path(certs::httpsObjectPath) / id;
960828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
961828252d5SJiaqing Zhao                              certURL, "HTTPS Certificate");
9627e860f15SJohn Edward Broadbent }
96337cce918SMarri Devender Rao 
964828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
96537cce918SMarri Devender Rao {
966828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
967828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
968ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
969828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
970828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
971828252d5SJiaqing Zhao 
972828252d5SJiaqing Zhao     BMCWEB_ROUTE(app,
973828252d5SJiaqing Zhao                  "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
974828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
975828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
976828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
977828252d5SJiaqing Zhao 
978828252d5SJiaqing Zhao     BMCWEB_ROUTE(
979828252d5SJiaqing Zhao         app,
980828252d5SJiaqing Zhao         "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
981828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
982002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
983828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
984828252d5SJiaqing Zhao }
985828252d5SJiaqing Zhao 
986828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
987828252d5SJiaqing Zhao     App& app, const crow::Request& req,
988828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
989828252d5SJiaqing Zhao {
9903ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
99145ca1b86SEd Tanous     {
99245ca1b86SEd Tanous         return;
99345ca1b86SEd Tanous     }
9941476687dSEd Tanous 
9951476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
9961476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
9971476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
9981476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
9991476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10001476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
10011476687dSEd Tanous         "A Collection of LDAP certificate instances";
10028d1b46d7Szhanghch05 
1003d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
1004d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1005d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1006828252d5SJiaqing Zhao }
100737cce918SMarri Devender Rao 
1008828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1009828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1010828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1011828252d5SJiaqing Zhao {
10123ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101345ca1b86SEd Tanous     {
101445ca1b86SEd Tanous         return;
101545ca1b86SEd Tanous     }
1016002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
101758eb238fSKowalski, Kamil 
101858eb238fSKowalski, Kamil     if (certFileBody.empty())
101958eb238fSKowalski, Kamil     {
1020002d39b4SEd Tanous         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1021a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
102258eb238fSKowalski, Kamil         return;
102358eb238fSKowalski, Kamil     }
102458eb238fSKowalski, Kamil 
102558eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
102658eb238fSKowalski, Kamil         std::make_shared<CertificateFile>(certFileBody);
102758eb238fSKowalski, Kamil 
102837cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
1029656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
1030656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
103137cce918SMarri Devender Rao         if (ec)
103237cce918SMarri Devender Rao         {
103337cce918SMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
103437cce918SMarri Devender Rao             messages::internalError(asyncResp->res);
103537cce918SMarri Devender Rao             return;
103637cce918SMarri Devender Rao         }
1037717b9802SJiaqing Zhao 
1038717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1039717b9802SJiaqing Zhao         std::string certId = path.filename();
1040828252d5SJiaqing Zhao         const boost::urls::url certURL = crow::utility::urlFromPieces(
1041828252d5SJiaqing Zhao             "redfish", "v1", "AccountService", "LDAP", "Certificates", certId);
1042828252d5SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1043828252d5SJiaqing Zhao                                  certId, certURL, "LDAP Certificate");
104437cce918SMarri Devender Rao         BMCWEB_LOG_DEBUG << "LDAP certificate install file="
104537cce918SMarri Devender Rao                          << certFile->getCertFilePath();
104637cce918SMarri Devender Rao         },
1047828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1048828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1049828252d5SJiaqing Zhao }
105037cce918SMarri Devender Rao 
1051828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1052828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1053828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
105437cce918SMarri Devender Rao {
10553ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
105645ca1b86SEd Tanous     {
105745ca1b86SEd Tanous         return;
105845ca1b86SEd Tanous     }
1059717b9802SJiaqing Zhao 
1060717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id;
10611e312598SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
10621e312598SJiaqing Zhao         "redfish", "v1", "AccountService", "LDAP", "Certificates", id);
1063717b9802SJiaqing Zhao     std::string objPath =
1064717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1065717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1066717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1067828252d5SJiaqing Zhao }
1068828252d5SJiaqing Zhao 
106999612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
107099612247SJiaqing Zhao     App& app, const crow::Request& req,
107199612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
107299612247SJiaqing Zhao {
107399612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
107499612247SJiaqing Zhao     {
107599612247SJiaqing Zhao         return;
107699612247SJiaqing Zhao     }
107799612247SJiaqing Zhao 
107899612247SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Delete LDAP Certificate ID=" << id;
107999612247SJiaqing Zhao     std::string objPath =
108099612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
108199612247SJiaqing Zhao 
108299612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
108399612247SJiaqing Zhao }
108499612247SJiaqing Zhao 
1085828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1086cfcd5f6bSMarri Devender Rao {
1087828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1088828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1089828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1090828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1091828252d5SJiaqing Zhao 
1092828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1093828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1094828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1095828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1096828252d5SJiaqing Zhao 
1097828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1098ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1099002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1100828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
110199612247SJiaqing Zhao 
110299612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
110399612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
110499612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
110599612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1106828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1107828252d5SJiaqing Zhao 
1108828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1109828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1110828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1111828252d5SJiaqing Zhao {
11123ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
111345ca1b86SEd Tanous     {
111445ca1b86SEd Tanous         return;
111545ca1b86SEd Tanous     }
11161476687dSEd Tanous 
11171476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
11181476687dSEd Tanous         "/redfish/v1/Managers/bmc/Truststore/Certificates/";
11191476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11201476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1121002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11221476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
11231476687dSEd Tanous         "A Collection of TrustStore certificate instances";
11248d1b46d7Szhanghch05 
1125d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1126d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1127d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1128828252d5SJiaqing Zhao }
1129cfcd5f6bSMarri Devender Rao 
1130828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1131828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1132828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1133828252d5SJiaqing Zhao {
11343ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
113545ca1b86SEd Tanous     {
113645ca1b86SEd Tanous         return;
113745ca1b86SEd Tanous     }
1138002d39b4SEd Tanous     std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1139a08752f5SZbigniew Kurzynski 
1140a08752f5SZbigniew Kurzynski     if (certFileBody.empty())
1141a08752f5SZbigniew Kurzynski     {
11420fda0f12SGeorge Liu         BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1143a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1144a08752f5SZbigniew Kurzynski         return;
1145a08752f5SZbigniew Kurzynski     }
1146a08752f5SZbigniew Kurzynski 
1147a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1148a08752f5SZbigniew Kurzynski         std::make_shared<CertificateFile>(certFileBody);
1149cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
1150656ec7e3SZbigniew Kurzynski         [asyncResp, certFile](const boost::system::error_code ec,
1151656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1152cfcd5f6bSMarri Devender Rao         if (ec)
1153cfcd5f6bSMarri Devender Rao         {
1154cfcd5f6bSMarri Devender Rao             BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1155cfcd5f6bSMarri Devender Rao             messages::internalError(asyncResp->res);
1156cfcd5f6bSMarri Devender Rao             return;
1157cfcd5f6bSMarri Devender Rao         }
1158656ec7e3SZbigniew Kurzynski 
1159717b9802SJiaqing Zhao         sdbusplus::message::object_path path(objectPath);
1160717b9802SJiaqing Zhao         std::string certId = path.filename();
1161828252d5SJiaqing Zhao         const boost::urls::url certURL =
1162828252d5SJiaqing Zhao             crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1163828252d5SJiaqing Zhao                                          "Truststore", "Certificates", certId);
1164717b9802SJiaqing Zhao         getCertificateProperties(asyncResp, objectPath,
1165828252d5SJiaqing Zhao                                  certs::authorityServiceName, certId, certURL,
1166828252d5SJiaqing Zhao                                  "TrustStore Certificate");
11670fda0f12SGeorge Liu         BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1168cfcd5f6bSMarri Devender Rao                          << certFile->getCertFilePath();
1169cfcd5f6bSMarri Devender Rao         },
1170cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
11710fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1172828252d5SJiaqing Zhao }
1173cfcd5f6bSMarri Devender Rao 
1174828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1175828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1176828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1177cfcd5f6bSMarri Devender Rao {
11783ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
117945ca1b86SEd Tanous     {
118045ca1b86SEd Tanous         return;
118145ca1b86SEd Tanous     }
1182717b9802SJiaqing Zhao 
1183717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id;
1184828252d5SJiaqing Zhao     const boost::urls::url certURL = crow::utility::urlFromPieces(
1185828252d5SJiaqing Zhao         "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id);
1186717b9802SJiaqing Zhao     std::string objPath =
1187717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1188828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1189828252d5SJiaqing Zhao                              id, certURL, "TrustStore Certificate");
1190828252d5SJiaqing Zhao }
119107a60299SZbigniew Kurzynski 
1192828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1193828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1194828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1195828252d5SJiaqing Zhao {
11963ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
119745ca1b86SEd Tanous     {
119845ca1b86SEd Tanous         return;
119945ca1b86SEd Tanous     }
120007a60299SZbigniew Kurzynski 
1201717b9802SJiaqing Zhao     BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id;
1202717b9802SJiaqing Zhao     std::string objPath =
1203717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
120407a60299SZbigniew Kurzynski 
12057a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1206828252d5SJiaqing Zhao }
1207828252d5SJiaqing Zhao 
1208828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1209828252d5SJiaqing Zhao {
1210828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1211828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1212828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1213828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1214828252d5SJiaqing Zhao 
1215828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
1216828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1217828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1218828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1219828252d5SJiaqing Zhao 
1220828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1221828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1222828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1223828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1224828252d5SJiaqing Zhao 
1225828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
1226828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1227828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1228828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
12297e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
12305968caeeSMarri Devender Rao } // namespace redfish
1231