xref: /openbmc/bmcweb/features/redfish/lib/certificate_service.hpp (revision bd79bce8c3f1deb1fb2773868b9ece25233cf27b)
15968caeeSMarri Devender Rao #pragma once
25968caeeSMarri Devender Rao 
33ccb3adbSEd Tanous #include "app.hpp"
43ccb3adbSEd Tanous #include "async_resp.hpp"
57a1dbc48SGeorge Liu #include "dbus_utility.hpp"
61aa0c2b8SEd Tanous #include "http/parsing.hpp"
73ccb3adbSEd Tanous #include "http_response.hpp"
83ccb3adbSEd Tanous #include "query.hpp"
93ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
109b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp"
113ccb3adbSEd Tanous #include "utils/json_utils.hpp"
123ccb3adbSEd Tanous #include "utils/time_utils.hpp"
139b12d1f9SKrzysztof Grobelny 
1490d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp>
15ef4c65b7SEd Tanous #include <boost/url/format.hpp>
169b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
173ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
189b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
191214b7e7SGunnar Mills 
207a1dbc48SGeorge Liu #include <array>
213ccb3adbSEd Tanous #include <memory>
227a1dbc48SGeorge Liu #include <string_view>
237a1dbc48SGeorge Liu 
245968caeeSMarri Devender Rao namespace redfish
255968caeeSMarri Devender Rao {
265968caeeSMarri Devender Rao namespace certs
275968caeeSMarri Devender Rao {
2889492a15SPatrick Williams constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install";
2989492a15SPatrick Williams constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
3089492a15SPatrick Williams constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
3189492a15SPatrick Williams constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
3289492a15SPatrick Williams constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties";
3389492a15SPatrick Williams constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
3489492a15SPatrick Williams constexpr const char* httpsServiceName =
3537cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Server.Https";
3689492a15SPatrick Williams constexpr const char* ldapServiceName =
3737cce918SMarri Devender Rao     "xyz.openbmc_project.Certs.Manager.Client.Ldap";
3889492a15SPatrick Williams constexpr const char* authorityServiceName =
39b2254ccdSMichal Orzel     "xyz.openbmc_project.Certs.Manager.Authority.Truststore";
4089492a15SPatrick Williams constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs";
4189492a15SPatrick Williams constexpr const char* httpsObjectPath =
42c6a8dfb1SJiaqing Zhao     "/xyz/openbmc_project/certs/server/https";
4389492a15SPatrick Williams constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
4489492a15SPatrick Williams constexpr const char* authorityObjectPath =
45b2254ccdSMichal Orzel     "/xyz/openbmc_project/certs/authority/truststore";
465968caeeSMarri Devender Rao } // namespace certs
475968caeeSMarri Devender Rao 
485968caeeSMarri Devender Rao /**
495968caeeSMarri Devender Rao  * The Certificate schema defines a Certificate Service which represents the
505968caeeSMarri Devender Rao  * actions available to manage certificates and links to where certificates
515968caeeSMarri Devender Rao  * are installed.
525968caeeSMarri Devender Rao  */
537e860f15SJohn Edward Broadbent 
548d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody(
558d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5658eb238fSKowalski, Kamil     const crow::Request& req)
5758eb238fSKowalski, Kamil {
581aa0c2b8SEd Tanous     nlohmann::json reqJson;
591aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, reqJson);
601aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
6158eb238fSKowalski, Kamil     {
6258eb238fSKowalski, Kamil         // We did not receive JSON request, proceed as it is RAW data
6333c6b580SEd Tanous         return req.body();
6458eb238fSKowalski, Kamil     }
6558eb238fSKowalski, Kamil 
6658eb238fSKowalski, Kamil     std::string certificate;
6758eb238fSKowalski, Kamil     std::optional<std::string> certificateType = "PEM";
6858eb238fSKowalski, Kamil 
6915ed6780SWilly Tu     if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
7015ed6780SWilly Tu                                   certificate, "CertificateType",
7115ed6780SWilly Tu                                   certificateType))
7258eb238fSKowalski, Kamil     {
7362598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
7458eb238fSKowalski, Kamil         messages::internalError(asyncResp->res);
75abb93cddSEd Tanous         return {};
7658eb238fSKowalski, Kamil     }
7758eb238fSKowalski, Kamil 
7858eb238fSKowalski, Kamil     if (*certificateType != "PEM")
7958eb238fSKowalski, Kamil     {
8058eb238fSKowalski, Kamil         messages::propertyValueNotInList(asyncResp->res, *certificateType,
8158eb238fSKowalski, Kamil                                          "CertificateType");
82abb93cddSEd Tanous         return {};
8358eb238fSKowalski, Kamil     }
8458eb238fSKowalski, Kamil 
8558eb238fSKowalski, Kamil     return certificate;
8658eb238fSKowalski, Kamil }
8758eb238fSKowalski, Kamil 
885968caeeSMarri Devender Rao /**
895968caeeSMarri Devender Rao  * Class to create a temporary certificate file for uploading to system
905968caeeSMarri Devender Rao  */
915968caeeSMarri Devender Rao class CertificateFile
925968caeeSMarri Devender Rao {
935968caeeSMarri Devender Rao   public:
945968caeeSMarri Devender Rao     CertificateFile() = delete;
955968caeeSMarri Devender Rao     CertificateFile(const CertificateFile&) = delete;
965968caeeSMarri Devender Rao     CertificateFile& operator=(const CertificateFile&) = delete;
975968caeeSMarri Devender Rao     CertificateFile(CertificateFile&&) = delete;
985968caeeSMarri Devender Rao     CertificateFile& operator=(CertificateFile&&) = delete;
994e23a444SEd Tanous     explicit CertificateFile(const std::string& certString)
1005968caeeSMarri Devender Rao     {
10172d52d25SEd Tanous         std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
1025207438cSEd Tanous                                             'e', 'r', 't', 's', '.', 'X',
1035207438cSEd Tanous                                             'X', 'X', 'X', 'X', 'X', '\0'};
1045207438cSEd Tanous         char* tempDirectory = mkdtemp(dirTemplate.data());
105e662eae8SEd Tanous         if (tempDirectory != nullptr)
1065968caeeSMarri Devender Rao         {
1075968caeeSMarri Devender Rao             certDirectory = tempDirectory;
1085968caeeSMarri Devender Rao             certificateFile = certDirectory / "cert.pem";
109*bd79bce8SPatrick Williams             std::ofstream out(certificateFile,
110*bd79bce8SPatrick Williams                               std::ofstream::out | std::ofstream::binary |
1115968caeeSMarri Devender Rao                                   std::ofstream::trunc);
1125968caeeSMarri Devender Rao             out << certString;
1135968caeeSMarri Devender Rao             out.close();
11462598e31SEd Tanous             BMCWEB_LOG_DEBUG("Creating certificate file{}",
11562598e31SEd Tanous                              certificateFile.string());
1165968caeeSMarri Devender Rao         }
1175968caeeSMarri Devender Rao     }
1185968caeeSMarri Devender Rao     ~CertificateFile()
1195968caeeSMarri Devender Rao     {
1205968caeeSMarri Devender Rao         if (std::filesystem::exists(certDirectory))
1215968caeeSMarri Devender Rao         {
12262598e31SEd Tanous             BMCWEB_LOG_DEBUG("Removing certificate file{}",
12362598e31SEd Tanous                              certificateFile.string());
12423a21a1cSEd Tanous             std::error_code ec;
12523a21a1cSEd Tanous             std::filesystem::remove_all(certDirectory, ec);
12623a21a1cSEd Tanous             if (ec)
1275968caeeSMarri Devender Rao             {
12862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Failed to remove temp directory{}",
12962598e31SEd Tanous                                  certDirectory.string());
1305968caeeSMarri Devender Rao             }
1315968caeeSMarri Devender Rao         }
1325968caeeSMarri Devender Rao     }
1335968caeeSMarri Devender Rao     std::string getCertFilePath()
1345968caeeSMarri Devender Rao     {
1355968caeeSMarri Devender Rao         return certificateFile;
1365968caeeSMarri Devender Rao     }
1375968caeeSMarri Devender Rao 
1385968caeeSMarri Devender Rao   private:
1395968caeeSMarri Devender Rao     std::filesystem::path certificateFile;
1405968caeeSMarri Devender Rao     std::filesystem::path certDirectory;
1415968caeeSMarri Devender Rao };
1425968caeeSMarri Devender Rao 
1435968caeeSMarri Devender Rao /**
1444e0453b1SGunnar Mills  * @brief Parse and update Certificate Issue/Subject property
1455968caeeSMarri Devender Rao  *
1465968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
1475968caeeSMarri Devender Rao  * @param[in] str  Issuer/Subject value in key=value pairs
1485968caeeSMarri Devender Rao  * @param[in] type Issuer/Subject
1495968caeeSMarri Devender Rao  * @return None
1505968caeeSMarri Devender Rao  */
1515968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out,
15226ccae32SEd Tanous                                       std::string_view value)
1535968caeeSMarri Devender Rao {
1545968caeeSMarri Devender Rao     // example: O=openbmc-project.xyz,CN=localhost
1555968caeeSMarri Devender Rao     std::string_view::iterator i = value.begin();
1565968caeeSMarri Devender Rao     while (i != value.end())
1575968caeeSMarri Devender Rao     {
1585968caeeSMarri Devender Rao         std::string_view::iterator tokenBegin = i;
1595968caeeSMarri Devender Rao         while (i != value.end() && *i != '=')
1605968caeeSMarri Devender Rao         {
1616da47babSPatrick Williams             std::advance(i, 1);
1625968caeeSMarri Devender Rao         }
1635968caeeSMarri Devender Rao         if (i == value.end())
1645968caeeSMarri Devender Rao         {
1655968caeeSMarri Devender Rao             break;
1665968caeeSMarri Devender Rao         }
16726ccae32SEd Tanous         std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin));
1686da47babSPatrick Williams         std::advance(i, 1);
1695968caeeSMarri Devender Rao         tokenBegin = i;
1705968caeeSMarri Devender Rao         while (i != value.end() && *i != ',')
1715968caeeSMarri Devender Rao         {
1726da47babSPatrick Williams             std::advance(i, 1);
1735968caeeSMarri Devender Rao         }
17426ccae32SEd Tanous         std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin));
1755968caeeSMarri Devender Rao         if (key == "L")
1765968caeeSMarri Devender Rao         {
1775968caeeSMarri Devender Rao             out["City"] = val;
1785968caeeSMarri Devender Rao         }
1795968caeeSMarri Devender Rao         else if (key == "CN")
1805968caeeSMarri Devender Rao         {
1815968caeeSMarri Devender Rao             out["CommonName"] = val;
1825968caeeSMarri Devender Rao         }
1835968caeeSMarri Devender Rao         else if (key == "C")
1845968caeeSMarri Devender Rao         {
1855968caeeSMarri Devender Rao             out["Country"] = val;
1865968caeeSMarri Devender Rao         }
1875968caeeSMarri Devender Rao         else if (key == "O")
1885968caeeSMarri Devender Rao         {
1895968caeeSMarri Devender Rao             out["Organization"] = val;
1905968caeeSMarri Devender Rao         }
1915968caeeSMarri Devender Rao         else if (key == "OU")
1925968caeeSMarri Devender Rao         {
1935968caeeSMarri Devender Rao             out["OrganizationalUnit"] = val;
1945968caeeSMarri Devender Rao         }
1955968caeeSMarri Devender Rao         else if (key == "ST")
1965968caeeSMarri Devender Rao         {
1975968caeeSMarri Devender Rao             out["State"] = val;
1985968caeeSMarri Devender Rao         }
1995968caeeSMarri Devender Rao         // skip comma character
2005968caeeSMarri Devender Rao         if (i != value.end())
2015968caeeSMarri Devender Rao         {
2026da47babSPatrick Williams             std::advance(i, 1);
2035968caeeSMarri Devender Rao         }
2045968caeeSMarri Devender Rao     }
2055968caeeSMarri Devender Rao }
2065968caeeSMarri Devender Rao 
2075968caeeSMarri Devender Rao /**
208d3f92ce7SJiaqing Zhao  * @brief Retrieve the installed certificate list
209d3f92ce7SJiaqing Zhao  *
210d3f92ce7SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
211d3f92ce7SJiaqing Zhao  * @param[in] basePath DBus object path to search
212d3f92ce7SJiaqing Zhao  * @param[in] listPtr Json pointer to the list in asyncResp
213d3f92ce7SJiaqing Zhao  * @param[in] countPtr Json pointer to the count in asyncResp
214d3f92ce7SJiaqing Zhao  * @return None
215d3f92ce7SJiaqing Zhao  */
216*bd79bce8SPatrick Williams static void getCertificateList(
217*bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218*bd79bce8SPatrick Williams     const std::string& basePath, 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             {
23062598e31SEd Tanous                 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                 {
243*bd79bce8SPatrick Williams                     BMCWEB_LOG_ERROR("Invalid certificate objPath {}",
244*bd79bce8SPatrick Williams                                      certPath);
245d3f92ce7SJiaqing Zhao                     continue;
246d3f92ce7SJiaqing Zhao                 }
247d3f92ce7SJiaqing Zhao 
248d3f92ce7SJiaqing Zhao                 boost::urls::url certURL;
249d3f92ce7SJiaqing Zhao                 if (objPath.parent_path() == certs::httpsObjectPath)
250d3f92ce7SJiaqing Zhao                 {
251ef4c65b7SEd Tanous                     certURL = boost::urls::format(
252253f11b8SEd Tanous                         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
253253f11b8SEd Tanous                         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
254d3f92ce7SJiaqing Zhao                 }
255d3f92ce7SJiaqing Zhao                 else if (objPath.parent_path() == certs::ldapObjectPath)
256d3f92ce7SJiaqing Zhao                 {
257ef4c65b7SEd Tanous                     certURL = boost::urls::format(
258*bd79bce8SPatrick Williams                         "/redfish/v1/AccountService/LDAP/Certificates/{}",
259*bd79bce8SPatrick Williams                         certId);
260d3f92ce7SJiaqing Zhao                 }
261d3f92ce7SJiaqing Zhao                 else if (objPath.parent_path() == certs::authorityObjectPath)
262d3f92ce7SJiaqing Zhao                 {
263ef4c65b7SEd Tanous                     certURL = boost::urls::format(
264253f11b8SEd Tanous                         "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
265253f11b8SEd Tanous                         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
266d3f92ce7SJiaqing Zhao                 }
267d3f92ce7SJiaqing Zhao                 else
268d3f92ce7SJiaqing Zhao                 {
269d3f92ce7SJiaqing Zhao                     continue;
270d3f92ce7SJiaqing Zhao                 }
271d3f92ce7SJiaqing Zhao 
272d3f92ce7SJiaqing Zhao                 nlohmann::json::object_t link;
273d3f92ce7SJiaqing Zhao                 link["@odata.id"] = certURL;
274d3f92ce7SJiaqing Zhao                 links.emplace_back(std::move(link));
275d3f92ce7SJiaqing Zhao             }
276d3f92ce7SJiaqing Zhao 
277d3f92ce7SJiaqing Zhao             asyncResp->res.jsonValue[countPtr] = links.size();
2787a1dbc48SGeorge Liu         });
279d3f92ce7SJiaqing Zhao }
280d3f92ce7SJiaqing Zhao 
281d3f92ce7SJiaqing Zhao /**
2825968caeeSMarri Devender Rao  * @brief Retrieve the certificates properties and append to the response
2835968caeeSMarri Devender Rao  * message
2845968caeeSMarri Devender Rao  *
2855968caeeSMarri Devender Rao  * @param[in] asyncResp Shared pointer to the response message
2865968caeeSMarri Devender Rao  * @param[in] objectPath  Path of the D-Bus service object
2875968caeeSMarri Devender Rao  * @param[in] certId  Id of the certificate
2885968caeeSMarri Devender Rao  * @param[in] certURL  URL of the certificate object
2895968caeeSMarri Devender Rao  * @param[in] name  name of the certificate
2905968caeeSMarri Devender Rao  * @return None
2915968caeeSMarri Devender Rao  */
2925968caeeSMarri Devender Rao static void getCertificateProperties(
2938d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
294e19e97e2SJiaqing Zhao     const std::string& objectPath, const std::string& service,
2951e312598SJiaqing Zhao     const std::string& certId, const boost::urls::url& certURL,
296e19e97e2SJiaqing Zhao     const std::string& name)
2975968caeeSMarri Devender Rao {
29862598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}",
29962598e31SEd Tanous                      objectPath, certId, certURL);
3009b12d1f9SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
3019b12d1f9SKrzysztof Grobelny         *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
302b9d36b47SEd Tanous         [asyncResp, certURL, certId,
3035e7e2dc5SEd Tanous          name](const boost::system::error_code& ec,
304b9d36b47SEd Tanous                const dbus::utility::DBusPropertiesMap& properties) {
3055968caeeSMarri Devender Rao             if (ec)
3065968caeeSMarri Devender Rao             {
30762598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
308*bd79bce8SPatrick Williams                 messages::resourceNotFound(asyncResp->res, "Certificate",
309*bd79bce8SPatrick Williams                                            certId);
3105968caeeSMarri Devender Rao                 return;
3115968caeeSMarri Devender Rao             }
3129b12d1f9SKrzysztof Grobelny 
3139b12d1f9SKrzysztof Grobelny             const std::string* certificateString = nullptr;
3149b12d1f9SKrzysztof Grobelny             const std::vector<std::string>* keyUsage = nullptr;
3159b12d1f9SKrzysztof Grobelny             const std::string* issuer = nullptr;
3169b12d1f9SKrzysztof Grobelny             const std::string* subject = nullptr;
3179b12d1f9SKrzysztof Grobelny             const uint64_t* validNotAfter = nullptr;
3189b12d1f9SKrzysztof Grobelny             const uint64_t* validNotBefore = nullptr;
3199b12d1f9SKrzysztof Grobelny 
3209b12d1f9SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
321*bd79bce8SPatrick Williams                 dbus_utils::UnpackErrorPrinter(), properties,
322*bd79bce8SPatrick Williams                 "CertificateString", certificateString, "KeyUsage", keyUsage,
323*bd79bce8SPatrick Williams                 "Issuer", issuer, "Subject", subject, "ValidNotAfter",
324*bd79bce8SPatrick Williams                 validNotAfter, "ValidNotBefore", validNotBefore);
3259b12d1f9SKrzysztof Grobelny 
3269b12d1f9SKrzysztof Grobelny             if (!success)
3279b12d1f9SKrzysztof Grobelny             {
3289b12d1f9SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
3299b12d1f9SKrzysztof Grobelny                 return;
3309b12d1f9SKrzysztof Grobelny             }
3319b12d1f9SKrzysztof Grobelny 
3321476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = certURL;
3331476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
3341476687dSEd Tanous                 "#Certificate.v1_0_0.Certificate";
335e19e97e2SJiaqing Zhao             asyncResp->res.jsonValue["Id"] = certId;
3361476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = name;
3371476687dSEd Tanous             asyncResp->res.jsonValue["Description"] = name;
3385968caeeSMarri Devender Rao             asyncResp->res.jsonValue["CertificateString"] = "";
3399b12d1f9SKrzysztof Grobelny             asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
3409b12d1f9SKrzysztof Grobelny 
3419b12d1f9SKrzysztof Grobelny             if (certificateString != nullptr)
3425968caeeSMarri Devender Rao             {
343*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["CertificateString"] =
344*bd79bce8SPatrick Williams                     *certificateString;
3455968caeeSMarri Devender Rao             }
3469b12d1f9SKrzysztof Grobelny 
3479b12d1f9SKrzysztof Grobelny             if (keyUsage != nullptr)
3485968caeeSMarri Devender Rao             {
3499b12d1f9SKrzysztof Grobelny                 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
3505968caeeSMarri Devender Rao             }
3519b12d1f9SKrzysztof Grobelny 
3529b12d1f9SKrzysztof Grobelny             if (issuer != nullptr)
3535968caeeSMarri Devender Rao             {
3549b12d1f9SKrzysztof Grobelny                 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
3559b12d1f9SKrzysztof Grobelny                                           *issuer);
3565968caeeSMarri Devender Rao             }
3579b12d1f9SKrzysztof Grobelny 
3589b12d1f9SKrzysztof Grobelny             if (subject != nullptr)
3595968caeeSMarri Devender Rao             {
3609b12d1f9SKrzysztof Grobelny                 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
3619b12d1f9SKrzysztof Grobelny                                           *subject);
3625968caeeSMarri Devender Rao             }
3639b12d1f9SKrzysztof Grobelny 
3649b12d1f9SKrzysztof Grobelny             if (validNotAfter != nullptr)
3655968caeeSMarri Devender Rao             {
3665968caeeSMarri Devender Rao                 asyncResp->res.jsonValue["ValidNotAfter"] =
3679b12d1f9SKrzysztof Grobelny                     redfish::time_utils::getDateTimeUint(*validNotAfter);
3685968caeeSMarri Devender Rao             }
3699b12d1f9SKrzysztof Grobelny 
3709b12d1f9SKrzysztof Grobelny             if (validNotBefore != nullptr)
3715968caeeSMarri Devender Rao             {
3725968caeeSMarri Devender Rao                 asyncResp->res.jsonValue["ValidNotBefore"] =
3739b12d1f9SKrzysztof Grobelny                     redfish::time_utils::getDateTimeUint(*validNotBefore);
3745968caeeSMarri Devender Rao             }
3759b12d1f9SKrzysztof Grobelny 
3761e312598SJiaqing Zhao             asyncResp->res.addHeader(
377d9f6c621SEd Tanous                 boost::beast::http::field::location,
378d9f6c621SEd Tanous                 std::string_view(certURL.data(), certURL.size()));
3799b12d1f9SKrzysztof Grobelny         });
3805968caeeSMarri Devender Rao }
3815968caeeSMarri Devender Rao 
3827a3a8f7aSJiaqing Zhao static void
3837a3a8f7aSJiaqing Zhao     deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3847a3a8f7aSJiaqing Zhao                       const std::string& service,
3857a3a8f7aSJiaqing Zhao                       const sdbusplus::message::object_path& objectPath)
3867a3a8f7aSJiaqing Zhao {
3877a3a8f7aSJiaqing Zhao     crow::connections::systemBus->async_method_call(
3887a3a8f7aSJiaqing Zhao         [asyncResp,
3895e7e2dc5SEd Tanous          id{objectPath.filename()}](const boost::system::error_code& ec) {
3907a3a8f7aSJiaqing Zhao             if (ec)
3917a3a8f7aSJiaqing Zhao             {
3927a3a8f7aSJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "Certificate", id);
3937a3a8f7aSJiaqing Zhao                 return;
3947a3a8f7aSJiaqing Zhao             }
39562598e31SEd Tanous             BMCWEB_LOG_INFO("Certificate deleted");
3967a3a8f7aSJiaqing Zhao             asyncResp->res.result(boost::beast::http::status::no_content);
3977a3a8f7aSJiaqing Zhao         },
3987a3a8f7aSJiaqing Zhao         service, objectPath, certs::objDeleteIntf, "Delete");
3997a3a8f7aSJiaqing Zhao }
4007a3a8f7aSJiaqing Zhao 
401828252d5SJiaqing Zhao inline void handleCertificateServiceGet(
402828252d5SJiaqing Zhao     App& app, const crow::Request& req,
403828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4045968caeeSMarri Devender Rao {
405828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
406828252d5SJiaqing Zhao     {
407828252d5SJiaqing Zhao         return;
408828252d5SJiaqing Zhao     }
409828252d5SJiaqing Zhao 
4103e72c202SNinad Palsule     if (req.session == nullptr)
4113e72c202SNinad Palsule     {
4123e72c202SNinad Palsule         messages::internalError(asyncResp->res);
4133e72c202SNinad Palsule         return;
4143e72c202SNinad Palsule     }
4153e72c202SNinad Palsule 
416828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
417828252d5SJiaqing Zhao         "#CertificateService.v1_0_0.CertificateService";
418828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
419828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateService";
420828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Service";
421828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
422828252d5SJiaqing Zhao         "Actions available to manage certificates";
423828252d5SJiaqing Zhao     // /redfish/v1/CertificateService/CertificateLocations is something
424828252d5SJiaqing Zhao     // only ConfigureManager can access then only display when the user
425828252d5SJiaqing Zhao     // has permissions ConfigureManager
426828252d5SJiaqing Zhao     Privileges effectiveUserPrivileges =
4273e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
428828252d5SJiaqing Zhao     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
429828252d5SJiaqing Zhao                                          effectiveUserPrivileges))
430828252d5SJiaqing Zhao     {
431828252d5SJiaqing Zhao         asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
432828252d5SJiaqing Zhao             "/redfish/v1/CertificateService/CertificateLocations";
433828252d5SJiaqing Zhao     }
434828252d5SJiaqing Zhao     nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
435828252d5SJiaqing Zhao     nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
436828252d5SJiaqing Zhao     replace["target"] =
437828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
438828252d5SJiaqing Zhao     nlohmann::json::array_t allowed;
439ad539545SPatrick Williams     allowed.emplace_back("PEM");
440828252d5SJiaqing Zhao     replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
441828252d5SJiaqing Zhao     actions["#CertificateService.GenerateCSR"]["target"] =
442828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
443828252d5SJiaqing Zhao }
444828252d5SJiaqing Zhao 
445828252d5SJiaqing Zhao inline void handleCertificateLocationsGet(
446828252d5SJiaqing Zhao     App& app, const crow::Request& req,
447828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
448828252d5SJiaqing Zhao {
449828252d5SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
450828252d5SJiaqing Zhao     {
451828252d5SJiaqing Zhao         return;
452828252d5SJiaqing Zhao     }
453828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.id"] =
454828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/CertificateLocations";
455828252d5SJiaqing Zhao     asyncResp->res.jsonValue["@odata.type"] =
456828252d5SJiaqing Zhao         "#CertificateLocations.v1_0_0.CertificateLocations";
457828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Name"] = "Certificate Locations";
458828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Id"] = "CertificateLocations";
459828252d5SJiaqing Zhao     asyncResp->res.jsonValue["Description"] =
460828252d5SJiaqing Zhao         "Defines a resource that an administrator can use in order to "
461828252d5SJiaqing Zhao         "locate all certificates installed on a given service";
462828252d5SJiaqing Zhao 
463828252d5SJiaqing Zhao     getCertificateList(asyncResp, certs::baseObjectPath,
464828252d5SJiaqing Zhao                        "/Links/Certificates"_json_pointer,
465828252d5SJiaqing Zhao                        "/Links/Certificates@odata.count"_json_pointer);
466828252d5SJiaqing Zhao }
467828252d5SJiaqing Zhao 
468828252d5SJiaqing Zhao inline void handleReplaceCertificateAction(
469828252d5SJiaqing Zhao     App& app, const crow::Request& req,
470828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
471828252d5SJiaqing Zhao {
4723ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
47345ca1b86SEd Tanous     {
47445ca1b86SEd Tanous         return;
47545ca1b86SEd Tanous     }
4765968caeeSMarri Devender Rao     std::string certificate;
4777a31e336SEd Tanous     std::string certURI;
4785968caeeSMarri Devender Rao     std::optional<std::string> certificateType = "PEM";
4798d1b46d7Szhanghch05 
480002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
4817a31e336SEd Tanous                                    certificate, "CertificateUri/@odata.id",
4827a31e336SEd Tanous                                    certURI, "CertificateType", certificateType))
4835968caeeSMarri Devender Rao     {
48462598e31SEd Tanous         BMCWEB_LOG_ERROR("Required parameters are missing");
4855968caeeSMarri Devender Rao         return;
4865968caeeSMarri Devender Rao     }
4875968caeeSMarri Devender Rao 
4885968caeeSMarri Devender Rao     if (!certificateType)
4895968caeeSMarri Devender Rao     {
4905968caeeSMarri Devender Rao         // should never happen, but it never hurts to be paranoid.
4915968caeeSMarri Devender Rao         return;
4925968caeeSMarri Devender Rao     }
4935968caeeSMarri Devender Rao     if (certificateType != "PEM")
4945968caeeSMarri Devender Rao     {
495828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
496828252d5SJiaqing Zhao                                               "ReplaceCertificate");
4975968caeeSMarri Devender Rao         return;
4985968caeeSMarri Devender Rao     }
4995968caeeSMarri Devender Rao 
50062598e31SEd Tanous     BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI);
5015968caeeSMarri Devender Rao 
5026fd29553SEd Tanous     boost::system::result<boost::urls::url> parsedUrl =
50375b63a2cSJiaqing Zhao         boost::urls::parse_relative_ref(certURI);
50475b63a2cSJiaqing Zhao     if (!parsedUrl)
5055968caeeSMarri Devender Rao     {
506828252d5SJiaqing Zhao         messages::actionParameterValueFormatError(
507828252d5SJiaqing Zhao             asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
5085968caeeSMarri Devender Rao         return;
5095968caeeSMarri Devender Rao     }
51075b63a2cSJiaqing Zhao 
51175b63a2cSJiaqing Zhao     std::string id;
51275b63a2cSJiaqing Zhao     sdbusplus::message::object_path objectPath;
5135968caeeSMarri Devender Rao     std::string name;
51437cce918SMarri Devender Rao     std::string service;
515828252d5SJiaqing Zhao     if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
516828252d5SJiaqing Zhao                                        "bmc", "NetworkProtocol", "HTTPS",
517828252d5SJiaqing Zhao                                        "Certificates", std::ref(id)))
5185968caeeSMarri Devender Rao     {
51989492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) /
52089492a15SPatrick Williams                      id;
5215968caeeSMarri Devender Rao         name = "HTTPS certificate";
52237cce918SMarri Devender Rao         service = certs::httpsServiceName;
52337cce918SMarri Devender Rao     }
52475b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
52575b63a2cSJiaqing Zhao                                             "AccountService", "LDAP",
52675b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
52737cce918SMarri Devender Rao     {
52889492a15SPatrick Williams         objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) /
52989492a15SPatrick Williams                      id;
53037cce918SMarri Devender Rao         name = "LDAP certificate";
53137cce918SMarri Devender Rao         service = certs::ldapServiceName;
5325968caeeSMarri Devender Rao     }
53375b63a2cSJiaqing Zhao     else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
53475b63a2cSJiaqing Zhao                                             "Managers", "bmc", "Truststore",
53575b63a2cSJiaqing Zhao                                             "Certificates", std::ref(id)))
536cfcd5f6bSMarri Devender Rao     {
53775b63a2cSJiaqing Zhao         objectPath =
538828252d5SJiaqing Zhao             sdbusplus::message::object_path(certs::authorityObjectPath) / id;
539cfcd5f6bSMarri Devender Rao         name = "TrustStore certificate";
540cfcd5f6bSMarri Devender Rao         service = certs::authorityServiceName;
541cfcd5f6bSMarri Devender Rao     }
5425968caeeSMarri Devender Rao     else
5435968caeeSMarri Devender Rao     {
544828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
545828252d5SJiaqing Zhao                                               "ReplaceCertificate");
5465968caeeSMarri Devender Rao         return;
5475968caeeSMarri Devender Rao     }
5485968caeeSMarri Devender Rao 
5495968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
5505968caeeSMarri Devender Rao         std::make_shared<CertificateFile>(certificate);
5515968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
5521e312598SJiaqing Zhao         [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
5535e7e2dc5SEd Tanous          name](const boost::system::error_code& ec) {
5545968caeeSMarri Devender Rao             if (ec)
5555968caeeSMarri Devender Rao             {
55662598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
55790d2d1e8SJiaqing Zhao                 if (ec.value() ==
55890d2d1e8SJiaqing Zhao                     boost::system::linux_error::bad_request_descriptor)
55990d2d1e8SJiaqing Zhao                 {
560*bd79bce8SPatrick Williams                     messages::resourceNotFound(asyncResp->res, "Certificate",
561*bd79bce8SPatrick Williams                                                id);
5625968caeeSMarri Devender Rao                     return;
5635968caeeSMarri Devender Rao                 }
56490d2d1e8SJiaqing Zhao                 messages::internalError(asyncResp->res);
56590d2d1e8SJiaqing Zhao                 return;
56690d2d1e8SJiaqing Zhao             }
567*bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath, service, id, url,
568*bd79bce8SPatrick Williams                                      name);
56962598e31SEd Tanous             BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
57062598e31SEd Tanous                              certFile->getCertFilePath());
5715968caeeSMarri Devender Rao         },
5725968caeeSMarri Devender Rao         service, objectPath, certs::certReplaceIntf, "Replace",
5735968caeeSMarri Devender Rao         certFile->getCertFilePath());
574828252d5SJiaqing Zhao }
5755968caeeSMarri Devender Rao 
576cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
577828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
5785968caeeSMarri Devender Rao /**
579828252d5SJiaqing Zhao  * @brief Read data from CSR D-bus object and set to response
580828252d5SJiaqing Zhao  *
581828252d5SJiaqing Zhao  * @param[in] asyncResp Shared pointer to the response message
5828ece0e45SEd Tanous  * @param[in] certURI Link to certificate collection URI
583828252d5SJiaqing Zhao  * @param[in] service D-Bus service name
584828252d5SJiaqing Zhao  * @param[in] certObjPath certificate D-Bus object path
585828252d5SJiaqing Zhao  * @param[in] csrObjPath CSR D-Bus object path
586828252d5SJiaqing Zhao  * @return None
5875968caeeSMarri Devender Rao  */
588828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
589828252d5SJiaqing Zhao                    const std::string& certURI, const std::string& service,
590828252d5SJiaqing Zhao                    const std::string& certObjPath,
591828252d5SJiaqing Zhao                    const std::string& csrObjPath)
5925968caeeSMarri Devender Rao {
59362598e31SEd Tanous     BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}",
59462598e31SEd Tanous                      certObjPath, csrObjPath, service);
595828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
596*bd79bce8SPatrick Williams         [asyncResp,
597*bd79bce8SPatrick Williams          certURI](const boost::system::error_code& ec, const std::string& csr) {
598828252d5SJiaqing Zhao             if (ec)
599828252d5SJiaqing Zhao             {
60062598e31SEd Tanous                 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             {
60662598e31SEd Tanous                 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;
6347a31e336SEd Tanous     std::string certURI;
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",
6557a31e336SEd Tanous             organizationalUnit, "State", state,
6567a31e336SEd Tanous             "CertificateCollection/@odata.id", certURI, "AlternativeNames",
6577a31e336SEd Tanous             optAlternativeNames, "ChallengePassword", optChallengePassword,
6587a31e336SEd Tanous             "Email", optEmail, "GivenName", optGivenName, "Initials",
6597a31e336SEd Tanous             optInitials, "KeyBitLength", optKeyBitLength, "KeyCurveId",
6607a31e336SEd Tanous             optKeyCurveId, "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
6617a31e336SEd Tanous             optKeyUsage, "Surname", optSurname, "UnstructuredName",
6627a31e336SEd Tanous             optUnstructuredName))
663828252d5SJiaqing Zhao     {
664828252d5SJiaqing Zhao         return;
6655968caeeSMarri Devender Rao     }
6665968caeeSMarri Devender Rao 
667828252d5SJiaqing Zhao     // bmcweb has no way to store or decode a private key challenge
668828252d5SJiaqing Zhao     // password, which will likely cause bmcweb to crash on startup
669828252d5SJiaqing Zhao     // if this is not set on a post so not allowing the user to set
670828252d5SJiaqing Zhao     // value
671828252d5SJiaqing Zhao     if (!optChallengePassword->empty())
6725968caeeSMarri Devender Rao     {
673828252d5SJiaqing Zhao         messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
674828252d5SJiaqing Zhao                                               "ChallengePassword");
675828252d5SJiaqing Zhao         return;
676828252d5SJiaqing Zhao     }
677828252d5SJiaqing Zhao 
678828252d5SJiaqing Zhao     std::string objectPath;
679828252d5SJiaqing Zhao     std::string service;
680253f11b8SEd Tanous     if (certURI.starts_with(std::format(
681253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
682253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
683828252d5SJiaqing Zhao     {
684828252d5SJiaqing Zhao         objectPath = certs::httpsObjectPath;
685828252d5SJiaqing Zhao         service = certs::httpsServiceName;
686828252d5SJiaqing Zhao     }
687828252d5SJiaqing Zhao     else if (certURI.starts_with(
688828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
689828252d5SJiaqing Zhao     {
690828252d5SJiaqing Zhao         objectPath = certs::ldapObjectPath;
691828252d5SJiaqing Zhao         service = certs::ldapServiceName;
692828252d5SJiaqing Zhao     }
693828252d5SJiaqing Zhao     else
694828252d5SJiaqing Zhao     {
695828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
696828252d5SJiaqing Zhao             asyncResp->res, "CertificateCollection", "GenerateCSR");
697828252d5SJiaqing Zhao         return;
698828252d5SJiaqing Zhao     }
699828252d5SJiaqing Zhao 
700828252d5SJiaqing Zhao     // supporting only EC and RSA algorithm
701828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
702828252d5SJiaqing Zhao     {
703828252d5SJiaqing Zhao         messages::actionParameterNotSupported(
704828252d5SJiaqing Zhao             asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
705828252d5SJiaqing Zhao         return;
706828252d5SJiaqing Zhao     }
707828252d5SJiaqing Zhao 
708828252d5SJiaqing Zhao     // supporting only 2048 key bit length for RSA algorithm due to
709828252d5SJiaqing Zhao     // time consumed in generating private key
710828252d5SJiaqing Zhao     if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
711828252d5SJiaqing Zhao     {
712e2616cc5SEd Tanous         messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
713e2616cc5SEd Tanous                                          "KeyBitLength");
714828252d5SJiaqing Zhao         return;
715828252d5SJiaqing Zhao     }
716828252d5SJiaqing Zhao 
717828252d5SJiaqing Zhao     // validate KeyUsage supporting only 1 type based on URL
718253f11b8SEd Tanous     if (certURI.starts_with(std::format(
719253f11b8SEd Tanous             "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
720253f11b8SEd Tanous             BMCWEB_REDFISH_MANAGER_URI_NAME)))
721828252d5SJiaqing Zhao     {
722828252d5SJiaqing Zhao         if (optKeyUsage->empty())
723828252d5SJiaqing Zhao         {
724b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ServerAuthentication");
725828252d5SJiaqing Zhao         }
726828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
727828252d5SJiaqing Zhao         {
728828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ServerAuthentication")
729828252d5SJiaqing Zhao             {
730828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
731828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
732828252d5SJiaqing Zhao                 return;
733828252d5SJiaqing Zhao             }
734828252d5SJiaqing Zhao         }
735828252d5SJiaqing Zhao         else
736828252d5SJiaqing Zhao         {
737828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
738828252d5SJiaqing Zhao                                                   "GenerateCSR");
739828252d5SJiaqing Zhao             return;
740828252d5SJiaqing Zhao         }
741828252d5SJiaqing Zhao     }
742828252d5SJiaqing Zhao     else if (certURI.starts_with(
743828252d5SJiaqing Zhao                  "/redfish/v1/AccountService/LDAP/Certificates"))
744828252d5SJiaqing Zhao     {
745828252d5SJiaqing Zhao         if (optKeyUsage->empty())
746828252d5SJiaqing Zhao         {
747b2ba3072SPatrick Williams             optKeyUsage->emplace_back("ClientAuthentication");
748828252d5SJiaqing Zhao         }
749828252d5SJiaqing Zhao         else if (optKeyUsage->size() == 1)
750828252d5SJiaqing Zhao         {
751828252d5SJiaqing Zhao             if ((*optKeyUsage)[0] != "ClientAuthentication")
752828252d5SJiaqing Zhao             {
753828252d5SJiaqing Zhao                 messages::propertyValueNotInList(asyncResp->res,
754828252d5SJiaqing Zhao                                                  (*optKeyUsage)[0], "KeyUsage");
755828252d5SJiaqing Zhao                 return;
756828252d5SJiaqing Zhao             }
757828252d5SJiaqing Zhao         }
758828252d5SJiaqing Zhao         else
759828252d5SJiaqing Zhao         {
760828252d5SJiaqing Zhao             messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
761828252d5SJiaqing Zhao                                                   "GenerateCSR");
762828252d5SJiaqing Zhao             return;
763828252d5SJiaqing Zhao         }
764828252d5SJiaqing Zhao     }
765828252d5SJiaqing Zhao 
766828252d5SJiaqing Zhao     // Only allow one CSR matcher at a time so setting retry
767828252d5SJiaqing Zhao     // time-out and timer expiry to 10 seconds for now.
768828252d5SJiaqing Zhao     static const int timeOut = 10;
769828252d5SJiaqing Zhao     if (csrMatcher)
770828252d5SJiaqing Zhao     {
771828252d5SJiaqing Zhao         messages::serviceTemporarilyUnavailable(asyncResp->res,
772828252d5SJiaqing Zhao                                                 std::to_string(timeOut));
773828252d5SJiaqing Zhao         return;
774828252d5SJiaqing Zhao     }
775828252d5SJiaqing Zhao 
7768e8245dbSEd Tanous     if (req.ioService == nullptr)
7778e8245dbSEd Tanous     {
7788e8245dbSEd Tanous         messages::internalError(asyncResp->res);
7798e8245dbSEd Tanous         return;
7808e8245dbSEd Tanous     }
7818e8245dbSEd Tanous 
782828252d5SJiaqing Zhao     // Make this static so it survives outside this method
783828252d5SJiaqing Zhao     static boost::asio::steady_timer timeout(*req.ioService);
784828252d5SJiaqing Zhao     timeout.expires_after(std::chrono::seconds(timeOut));
785828252d5SJiaqing Zhao     timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
786828252d5SJiaqing Zhao         csrMatcher = nullptr;
787828252d5SJiaqing Zhao         if (ec)
788828252d5SJiaqing Zhao         {
789828252d5SJiaqing Zhao             // operation_aborted is expected if timer is canceled
790828252d5SJiaqing Zhao             // before completion.
791828252d5SJiaqing Zhao             if (ec != boost::asio::error::operation_aborted)
792828252d5SJiaqing Zhao             {
79362598e31SEd Tanous                 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
794828252d5SJiaqing Zhao             }
795828252d5SJiaqing Zhao             return;
796828252d5SJiaqing Zhao         }
79762598e31SEd Tanous         BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
798828252d5SJiaqing Zhao         messages::internalError(asyncResp->res);
799828252d5SJiaqing Zhao     });
800828252d5SJiaqing Zhao 
801828252d5SJiaqing Zhao     // create a matcher to wait on CSR object
80262598e31SEd Tanous     BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
803828252d5SJiaqing Zhao     std::string match("type='signal',"
804828252d5SJiaqing Zhao                       "interface='org.freedesktop.DBus.ObjectManager',"
805828252d5SJiaqing Zhao                       "path='" +
806828252d5SJiaqing Zhao                       objectPath +
807828252d5SJiaqing Zhao                       "',"
808828252d5SJiaqing Zhao                       "member='InterfacesAdded'");
809828252d5SJiaqing Zhao     csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
810828252d5SJiaqing Zhao         *crow::connections::systemBus, match,
811828252d5SJiaqing Zhao         [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
812828252d5SJiaqing Zhao             timeout.cancel();
813828252d5SJiaqing Zhao             if (m.is_method_error())
814828252d5SJiaqing Zhao             {
81562598e31SEd Tanous                 BMCWEB_LOG_ERROR("Dbus method error!!!");
816828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
817828252d5SJiaqing Zhao                 return;
818828252d5SJiaqing Zhao             }
819828252d5SJiaqing Zhao 
82080f79a40SMichael Shen             dbus::utility::DBusInterfacesMap interfacesProperties;
821828252d5SJiaqing Zhao 
822828252d5SJiaqing Zhao             sdbusplus::message::object_path csrObjectPath;
823828252d5SJiaqing Zhao             m.read(csrObjectPath, interfacesProperties);
82462598e31SEd Tanous             BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
825828252d5SJiaqing Zhao             for (const auto& interface : interfacesProperties)
826828252d5SJiaqing Zhao             {
827828252d5SJiaqing Zhao                 if (interface.first == "xyz.openbmc_project.Certs.CSR")
828828252d5SJiaqing Zhao                 {
829828252d5SJiaqing Zhao                     getCSR(asyncResp, certURI, service, objectPath,
830828252d5SJiaqing Zhao                            csrObjectPath.str);
831828252d5SJiaqing Zhao                     break;
832828252d5SJiaqing Zhao                 }
833828252d5SJiaqing Zhao             }
834828252d5SJiaqing Zhao         });
835828252d5SJiaqing Zhao     crow::connections::systemBus->async_method_call(
8365e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec, const std::string&) {
837828252d5SJiaqing Zhao             if (ec)
838828252d5SJiaqing Zhao             {
83962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
840828252d5SJiaqing Zhao                 messages::internalError(asyncResp->res);
841828252d5SJiaqing Zhao                 return;
842828252d5SJiaqing Zhao             }
843828252d5SJiaqing Zhao         },
844828252d5SJiaqing Zhao         service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
845828252d5SJiaqing Zhao         "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
846828252d5SJiaqing Zhao         commonName, *optContactPerson, country, *optEmail, *optGivenName,
847828252d5SJiaqing Zhao         *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
848828252d5SJiaqing Zhao         *optKeyUsage, organization, organizationalUnit, state, *optSurname,
849828252d5SJiaqing Zhao         *optUnstructuredName);
850828252d5SJiaqing Zhao }
851828252d5SJiaqing Zhao 
852828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app)
853828252d5SJiaqing Zhao {
854828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
855828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateService)
856002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
857828252d5SJiaqing Zhao             std::bind_front(handleCertificateServiceGet, std::ref(app)));
858828252d5SJiaqing Zhao 
859828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
860828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateLocations)
861828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
862828252d5SJiaqing Zhao             std::bind_front(handleCertificateLocationsGet, std::ref(app)));
863828252d5SJiaqing Zhao 
864828252d5SJiaqing Zhao     BMCWEB_ROUTE(
865828252d5SJiaqing Zhao         app,
866828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
867828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
868828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
869828252d5SJiaqing Zhao             std::bind_front(handleReplaceCertificateAction, std::ref(app)));
870828252d5SJiaqing Zhao 
871828252d5SJiaqing Zhao     BMCWEB_ROUTE(
872828252d5SJiaqing Zhao         app,
873828252d5SJiaqing Zhao         "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
874828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateService)
875828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(
876828252d5SJiaqing Zhao             std::bind_front(handleGenerateCSRAction, std::ref(app)));
877828252d5SJiaqing Zhao } // requestRoutesCertificateService
878828252d5SJiaqing Zhao 
879828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet(
880828252d5SJiaqing Zhao     App& app, const crow::Request& req,
881253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
882253f11b8SEd Tanous     const std::string& managerId)
883828252d5SJiaqing Zhao {
8843ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
88545ca1b86SEd Tanous     {
88645ca1b86SEd Tanous         return;
88745ca1b86SEd Tanous     }
8881476687dSEd Tanous 
889253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
890253f11b8SEd Tanous     {
891253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
892253f11b8SEd Tanous         return;
893253f11b8SEd Tanous     }
894253f11b8SEd Tanous 
895253f11b8SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
896253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
897253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME);
8981476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
8991476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
9001476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
9011476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
9021476687dSEd Tanous         "A Collection of HTTPS certificate instances";
9038d1b46d7Szhanghch05 
904d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::httpsObjectPath,
905d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
906d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
907828252d5SJiaqing Zhao }
9085968caeeSMarri Devender Rao 
909828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost(
910828252d5SJiaqing Zhao     App& app, const crow::Request& req,
911253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
912253f11b8SEd Tanous     const std::string& managerId)
913828252d5SJiaqing Zhao {
9143ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
91545ca1b86SEd Tanous     {
91645ca1b86SEd Tanous         return;
91745ca1b86SEd Tanous     }
918253f11b8SEd Tanous 
919253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
920253f11b8SEd Tanous     {
921253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
922253f11b8SEd Tanous         return;
923253f11b8SEd Tanous     }
924253f11b8SEd Tanous 
92562598e31SEd Tanous     BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
9268d1b46d7Szhanghch05 
9271476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
9281476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
9295968caeeSMarri Devender Rao 
930b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
93158eb238fSKowalski, Kamil 
932b2896149SEd Tanous     if (certHttpBody.empty())
93358eb238fSKowalski, Kamil     {
93462598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
935a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
93658eb238fSKowalski, Kamil         return;
93758eb238fSKowalski, Kamil     }
93858eb238fSKowalski, Kamil 
9395968caeeSMarri Devender Rao     std::shared_ptr<CertificateFile> certFile =
940b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
9415968caeeSMarri Devender Rao 
9425968caeeSMarri Devender Rao     crow::connections::systemBus->async_method_call(
9435e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
944656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
9455968caeeSMarri Devender Rao             if (ec)
9465968caeeSMarri Devender Rao             {
94762598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
9485968caeeSMarri Devender Rao                 messages::internalError(asyncResp->res);
9495968caeeSMarri Devender Rao                 return;
9505968caeeSMarri Devender Rao             }
951717b9802SJiaqing Zhao 
952717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
953717b9802SJiaqing Zhao             std::string certId = path.filename();
954ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
955253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
956253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
957*bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath,
958*bd79bce8SPatrick Williams                                      certs::httpsServiceName, certId, certURL,
959*bd79bce8SPatrick Williams                                      "HTTPS Certificate");
96062598e31SEd Tanous             BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
96162598e31SEd Tanous                              certFile->getCertFilePath());
9625968caeeSMarri Devender Rao         },
963828252d5SJiaqing Zhao         certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
964828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
965828252d5SJiaqing Zhao }
9665968caeeSMarri Devender Rao 
967828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet(
968828252d5SJiaqing Zhao     App& app, const crow::Request& req,
969253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
970253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
9717e860f15SJohn Edward Broadbent {
9723ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
97345ca1b86SEd Tanous     {
97445ca1b86SEd Tanous         return;
97545ca1b86SEd Tanous     }
9767e860f15SJohn Edward Broadbent 
977253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
978253f11b8SEd Tanous     {
979253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
980253f11b8SEd Tanous         return;
981253f11b8SEd Tanous     }
982253f11b8SEd Tanous 
983253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId);
984ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
985253f11b8SEd Tanous         "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
986253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
987828252d5SJiaqing Zhao     std::string objPath =
988253f11b8SEd Tanous         sdbusplus::message::object_path(certs::httpsObjectPath) / certId;
989253f11b8SEd Tanous     getCertificateProperties(asyncResp, objPath, certs::httpsServiceName,
990253f11b8SEd Tanous                              certId, certURL, "HTTPS Certificate");
9917e860f15SJohn Edward Broadbent }
99237cce918SMarri Devender Rao 
993828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app)
99437cce918SMarri Devender Rao {
995253f11b8SEd Tanous     BMCWEB_ROUTE(
996253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
997ed398213SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
998828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
999828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionGet, std::ref(app)));
1000828252d5SJiaqing Zhao 
1001253f11b8SEd Tanous     BMCWEB_ROUTE(
1002253f11b8SEd Tanous         app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
1003828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1004828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1005828252d5SJiaqing Zhao             handleHTTPSCertificateCollectionPost, std::ref(app)));
1006828252d5SJiaqing Zhao 
1007828252d5SJiaqing Zhao     BMCWEB_ROUTE(
1008828252d5SJiaqing Zhao         app,
1009253f11b8SEd Tanous         "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/")
1010828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1011002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1012828252d5SJiaqing Zhao             std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
1013828252d5SJiaqing Zhao }
1014828252d5SJiaqing Zhao 
1015828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet(
1016828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1017828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1018828252d5SJiaqing Zhao {
10193ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
102045ca1b86SEd Tanous     {
102145ca1b86SEd Tanous         return;
102245ca1b86SEd Tanous     }
10231476687dSEd Tanous 
10241476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
10251476687dSEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates";
10261476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
10271476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
10281476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
10291476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
10301476687dSEd Tanous         "A Collection of LDAP certificate instances";
10318d1b46d7Szhanghch05 
1032d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::ldapObjectPath,
1033d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1034d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1035828252d5SJiaqing Zhao }
103637cce918SMarri Devender Rao 
1037828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost(
1038828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1039828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1040828252d5SJiaqing Zhao {
10413ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
104245ca1b86SEd Tanous     {
104345ca1b86SEd Tanous         return;
104445ca1b86SEd Tanous     }
1045b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
104658eb238fSKowalski, Kamil 
1047b2896149SEd Tanous     if (certHttpBody.empty())
104858eb238fSKowalski, Kamil     {
104962598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1050a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
105158eb238fSKowalski, Kamil         return;
105258eb238fSKowalski, Kamil     }
105358eb238fSKowalski, Kamil 
105458eb238fSKowalski, Kamil     std::shared_ptr<CertificateFile> certFile =
1055b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
105658eb238fSKowalski, Kamil 
105737cce918SMarri Devender Rao     crow::connections::systemBus->async_method_call(
10585e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1059656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
106037cce918SMarri Devender Rao             if (ec)
106137cce918SMarri Devender Rao             {
106262598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
106337cce918SMarri Devender Rao                 messages::internalError(asyncResp->res);
106437cce918SMarri Devender Rao                 return;
106537cce918SMarri Devender Rao             }
1066717b9802SJiaqing Zhao 
1067717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
1068717b9802SJiaqing Zhao             std::string certId = path.filename();
1069ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
1070ef4c65b7SEd Tanous                 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
1071*bd79bce8SPatrick Williams             getCertificateProperties(asyncResp, objectPath,
1072*bd79bce8SPatrick Williams                                      certs::ldapServiceName, certId, certURL,
1073*bd79bce8SPatrick Williams                                      "LDAP Certificate");
107462598e31SEd Tanous             BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
107562598e31SEd Tanous                              certFile->getCertFilePath());
107637cce918SMarri Devender Rao         },
1077828252d5SJiaqing Zhao         certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1078828252d5SJiaqing Zhao         "Install", certFile->getCertFilePath());
1079828252d5SJiaqing Zhao }
108037cce918SMarri Devender Rao 
1081828252d5SJiaqing Zhao inline void handleLDAPCertificateGet(
1082828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1083828252d5SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
108437cce918SMarri Devender Rao {
10853ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
108645ca1b86SEd Tanous     {
108745ca1b86SEd Tanous         return;
108845ca1b86SEd Tanous     }
1089717b9802SJiaqing Zhao 
109062598e31SEd Tanous     BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
1091ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1092ef4c65b7SEd Tanous         "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
1093717b9802SJiaqing Zhao     std::string objPath =
1094717b9802SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1095717b9802SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1096717b9802SJiaqing Zhao                              certURL, "LDAP Certificate");
1097828252d5SJiaqing Zhao }
1098828252d5SJiaqing Zhao 
109999612247SJiaqing Zhao inline void handleLDAPCertificateDelete(
110099612247SJiaqing Zhao     App& app, const crow::Request& req,
110199612247SJiaqing Zhao     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
110299612247SJiaqing Zhao {
110399612247SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
110499612247SJiaqing Zhao     {
110599612247SJiaqing Zhao         return;
110699612247SJiaqing Zhao     }
110799612247SJiaqing Zhao 
110862598e31SEd Tanous     BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
110999612247SJiaqing Zhao     std::string objPath =
111099612247SJiaqing Zhao         sdbusplus::message::object_path(certs::ldapObjectPath) / id;
111199612247SJiaqing Zhao 
111299612247SJiaqing Zhao     deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
111399612247SJiaqing Zhao }
111499612247SJiaqing Zhao 
1115828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app)
1116cfcd5f6bSMarri Devender Rao {
1117828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1118828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificateCollection)
1119828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1120828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1121828252d5SJiaqing Zhao 
1122828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1123828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1124828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1125828252d5SJiaqing Zhao             handleLDAPCertificateCollectionPost, std::ref(app)));
1126828252d5SJiaqing Zhao 
1127828252d5SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1128ed398213SEd Tanous         .privileges(redfish::privileges::getCertificate)
1129002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1130828252d5SJiaqing Zhao             std::bind_front(handleLDAPCertificateGet, std::ref(app)));
113199612247SJiaqing Zhao 
113299612247SJiaqing Zhao     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
113399612247SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
113499612247SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
113599612247SJiaqing Zhao             std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
1136828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate
1137828252d5SJiaqing Zhao 
1138828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet(
1139828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1140253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1141253f11b8SEd Tanous     const std::string& managerId)
1142828252d5SJiaqing Zhao {
11433ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
114445ca1b86SEd Tanous     {
114545ca1b86SEd Tanous         return;
114645ca1b86SEd Tanous     }
11471476687dSEd Tanous 
1148253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1149253f11b8SEd Tanous     {
1150253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1151253f11b8SEd Tanous         return;
1152253f11b8SEd Tanous     }
1153253f11b8SEd Tanous 
11541476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
1155253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/",
1156253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
11571476687dSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
11581476687dSEd Tanous         "#CertificateCollection.CertificateCollection";
1159002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
11601476687dSEd Tanous     asyncResp->res.jsonValue["Description"] =
11611476687dSEd Tanous         "A Collection of TrustStore certificate instances";
11628d1b46d7Szhanghch05 
1163d3f92ce7SJiaqing Zhao     getCertificateList(asyncResp, certs::authorityObjectPath,
1164d3f92ce7SJiaqing Zhao                        "/Members"_json_pointer,
1165d3f92ce7SJiaqing Zhao                        "/Members@odata.count"_json_pointer);
1166828252d5SJiaqing Zhao }
1167cfcd5f6bSMarri Devender Rao 
1168828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost(
1169828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1170253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1171253f11b8SEd Tanous     const std::string& managerId)
1172828252d5SJiaqing Zhao {
11733ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
117445ca1b86SEd Tanous     {
117545ca1b86SEd Tanous         return;
117645ca1b86SEd Tanous     }
1177253f11b8SEd Tanous 
1178253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1179253f11b8SEd Tanous     {
1180253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1181253f11b8SEd Tanous         return;
1182253f11b8SEd Tanous     }
1183253f11b8SEd Tanous 
1184b2896149SEd Tanous     std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
1185a08752f5SZbigniew Kurzynski 
1186b2896149SEd Tanous     if (certHttpBody.empty())
1187a08752f5SZbigniew Kurzynski     {
118862598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
1189a08752f5SZbigniew Kurzynski         messages::unrecognizedRequestBody(asyncResp->res);
1190a08752f5SZbigniew Kurzynski         return;
1191a08752f5SZbigniew Kurzynski     }
1192a08752f5SZbigniew Kurzynski 
1193a08752f5SZbigniew Kurzynski     std::shared_ptr<CertificateFile> certFile =
1194b2896149SEd Tanous         std::make_shared<CertificateFile>(certHttpBody);
1195cfcd5f6bSMarri Devender Rao     crow::connections::systemBus->async_method_call(
11965e7e2dc5SEd Tanous         [asyncResp, certFile](const boost::system::error_code& ec,
1197656ec7e3SZbigniew Kurzynski                               const std::string& objectPath) {
1198cfcd5f6bSMarri Devender Rao             if (ec)
1199cfcd5f6bSMarri Devender Rao             {
120062598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
1201cfcd5f6bSMarri Devender Rao                 messages::internalError(asyncResp->res);
1202cfcd5f6bSMarri Devender Rao                 return;
1203cfcd5f6bSMarri Devender Rao             }
1204656ec7e3SZbigniew Kurzynski 
1205717b9802SJiaqing Zhao             sdbusplus::message::object_path path(objectPath);
1206717b9802SJiaqing Zhao             std::string certId = path.filename();
1207ef4c65b7SEd Tanous             const boost::urls::url certURL = boost::urls::format(
1208253f11b8SEd Tanous                 "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1209253f11b8SEd Tanous                 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1210717b9802SJiaqing Zhao             getCertificateProperties(asyncResp, objectPath,
1211*bd79bce8SPatrick Williams                                      certs::authorityServiceName, certId,
1212*bd79bce8SPatrick Williams                                      certURL, "TrustStore Certificate");
121362598e31SEd Tanous             BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
121462598e31SEd Tanous                              certFile->getCertFilePath());
1215cfcd5f6bSMarri Devender Rao         },
1216cfcd5f6bSMarri Devender Rao         certs::authorityServiceName, certs::authorityObjectPath,
12170fda0f12SGeorge Liu         certs::certInstallIntf, "Install", certFile->getCertFilePath());
1218828252d5SJiaqing Zhao }
1219cfcd5f6bSMarri Devender Rao 
1220828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet(
1221828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1222253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1223253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1224cfcd5f6bSMarri Devender Rao {
12253ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
122645ca1b86SEd Tanous     {
122745ca1b86SEd Tanous         return;
122845ca1b86SEd Tanous     }
1229717b9802SJiaqing Zhao 
1230253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1231253f11b8SEd Tanous     {
1232253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1233253f11b8SEd Tanous         return;
1234253f11b8SEd Tanous     }
1235253f11b8SEd Tanous 
1236253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId);
1237ef4c65b7SEd Tanous     const boost::urls::url certURL = boost::urls::format(
1238253f11b8SEd Tanous         "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1239253f11b8SEd Tanous         BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1240717b9802SJiaqing Zhao     std::string objPath =
1241253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
1242828252d5SJiaqing Zhao     getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1243253f11b8SEd Tanous                              certId, certURL, "TrustStore Certificate");
1244828252d5SJiaqing Zhao }
124507a60299SZbigniew Kurzynski 
1246828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete(
1247828252d5SJiaqing Zhao     App& app, const crow::Request& req,
1248253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1249253f11b8SEd Tanous     const std::string& managerId, const std::string& certId)
1250828252d5SJiaqing Zhao {
12513ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
125245ca1b86SEd Tanous     {
125345ca1b86SEd Tanous         return;
125445ca1b86SEd Tanous     }
125507a60299SZbigniew Kurzynski 
1256253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1257253f11b8SEd Tanous     {
1258253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1259253f11b8SEd Tanous         return;
1260253f11b8SEd Tanous     }
1261253f11b8SEd Tanous 
1262253f11b8SEd Tanous     BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId);
1263717b9802SJiaqing Zhao     std::string objPath =
1264253f11b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
126507a60299SZbigniew Kurzynski 
12667a3a8f7aSJiaqing Zhao     deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
1267828252d5SJiaqing Zhao }
1268828252d5SJiaqing Zhao 
1269828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app)
1270828252d5SJiaqing Zhao {
1271253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1272828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1273828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(std::bind_front(
1274828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionGet, std::ref(app)));
1275828252d5SJiaqing Zhao 
1276253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
1277828252d5SJiaqing Zhao         .privileges(redfish::privileges::postCertificateCollection)
1278828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::post)(std::bind_front(
1279828252d5SJiaqing Zhao             handleTrustStoreCertificateCollectionPost, std::ref(app)));
1280828252d5SJiaqing Zhao 
1281253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1282253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1283828252d5SJiaqing Zhao         .privileges(redfish::privileges::getCertificate)
1284828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::get)(
1285828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
1286828252d5SJiaqing Zhao 
1287253f11b8SEd Tanous     BMCWEB_ROUTE(app,
1288253f11b8SEd Tanous                  "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
1289828252d5SJiaqing Zhao         .privileges(redfish::privileges::deleteCertificate)
1290828252d5SJiaqing Zhao         .methods(boost::beast::http::verb::delete_)(
1291828252d5SJiaqing Zhao             std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
12927e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate
12935968caeeSMarri Devender Rao } // namespace redfish
1294