blob: e90f7494762e4feaffde3429540a6da674aca793 [file] [log] [blame]
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001#pragma once
2
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08003#include "app.hpp"
4#include "async_resp.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +08005#include "dbus_utility.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01006#include "http/parsing.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08007#include "http_response.hpp"
8#include "query.hpp"
9#include "registries/privilege_registry.hpp"
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020010#include "utils/dbus_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011#include "utils/json_utils.hpp"
12#include "utils/time_utils.hpp"
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020013
Jiaqing Zhao90d2d1e2022-04-13 17:01:57 +080014#include <boost/system/linux_error.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070015#include <boost/url/format.hpp>
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020016#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080017#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020018#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050019
George Liu7a1dbc42022-12-07 16:03:22 +080020#include <array>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include <memory>
George Liu7a1dbc42022-12-07 16:03:22 +080022#include <string_view>
23
Marri Devender Rao5968cae2019-01-21 10:27:12 -060024namespace redfish
25{
26namespace certs
27{
Patrick Williams89492a12023-05-10 07:51:34 -050028constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install";
29constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
30constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
31constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
32constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties";
33constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
34constexpr const char* httpsServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060035 "xyz.openbmc_project.Certs.Manager.Server.Https";
Patrick Williams89492a12023-05-10 07:51:34 -050036constexpr const char* ldapServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060037 "xyz.openbmc_project.Certs.Manager.Client.Ldap";
Patrick Williams89492a12023-05-10 07:51:34 -050038constexpr const char* authorityServiceName =
Michal Orzelb2254cc2023-07-27 14:08:32 +020039 "xyz.openbmc_project.Certs.Manager.Authority.Truststore";
Patrick Williams89492a12023-05-10 07:51:34 -050040constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs";
41constexpr const char* httpsObjectPath =
Jiaqing Zhaoc6a8dfb2022-06-03 10:44:23 +080042 "/xyz/openbmc_project/certs/server/https";
Patrick Williams89492a12023-05-10 07:51:34 -050043constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
44constexpr const char* authorityObjectPath =
Michal Orzelb2254cc2023-07-27 14:08:32 +020045 "/xyz/openbmc_project/certs/authority/truststore";
Marri Devender Rao5968cae2019-01-21 10:27:12 -060046} // namespace certs
47
48/**
49 * The Certificate schema defines a Certificate Service which represents the
50 * actions available to manage certificates and links to where certificates
51 * are installed.
52 */
Marri Devender Rao5968cae2019-01-21 10:27:12 -060053
zhanghch058d1b46d2021-04-01 11:18:24 +080054inline std::string getCertificateFromReqBody(
55 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
56 const crow::Request& req)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020057{
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010058 nlohmann::json reqJson;
59 JsonParseResult ret = parseRequestAsJson(req, reqJson);
60 if (ret != JsonParseResult::Success)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020061 {
62 // We did not receive JSON request, proceed as it is RAW data
Ed Tanous33c6b582023-02-14 15:05:48 -080063 return req.body();
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020064 }
65
66 std::string certificate;
67 std::optional<std::string> certificateType = "PEM";
68
Willy Tu15ed6782021-12-14 11:03:16 -080069 if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
70 certificate, "CertificateType",
71 certificateType))
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020072 {
Ed Tanous62598e32023-07-17 17:06:25 -070073 BMCWEB_LOG_ERROR("Required parameters are missing");
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020074 messages::internalError(asyncResp->res);
Ed Tanousabb93cd2021-09-02 14:34:57 -070075 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020076 }
77
78 if (*certificateType != "PEM")
79 {
80 messages::propertyValueNotInList(asyncResp->res, *certificateType,
81 "CertificateType");
Ed Tanousabb93cd2021-09-02 14:34:57 -070082 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020083 }
84
85 return certificate;
86}
87
Marri Devender Rao5968cae2019-01-21 10:27:12 -060088/**
89 * Class to create a temporary certificate file for uploading to system
90 */
91class CertificateFile
92{
93 public:
94 CertificateFile() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050095 CertificateFile(const CertificateFile&) = delete;
96 CertificateFile& operator=(const CertificateFile&) = delete;
97 CertificateFile(CertificateFile&&) = delete;
98 CertificateFile& operator=(CertificateFile&&) = delete;
Ed Tanous4e23a442022-06-06 09:57:26 -070099 explicit CertificateFile(const std::string& certString)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600100 {
Ed Tanous72d52d22020-10-12 07:46:27 -0700101 std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
Ed Tanous52074382020-09-28 19:16:18 -0700102 'e', 'r', 't', 's', '.', 'X',
103 'X', 'X', 'X', 'X', 'X', '\0'};
104 char* tempDirectory = mkdtemp(dirTemplate.data());
Ed Tanouse662eae2022-01-25 10:39:19 -0800105 if (tempDirectory != nullptr)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600106 {
107 certDirectory = tempDirectory;
108 certificateFile = certDirectory / "cert.pem";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400109 std::ofstream out(certificateFile,
110 std::ofstream::out | std::ofstream::binary |
111 std::ofstream::trunc);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600112 out << certString;
113 out.close();
Ed Tanous62598e32023-07-17 17:06:25 -0700114 BMCWEB_LOG_DEBUG("Creating certificate file{}",
115 certificateFile.string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600116 }
117 }
118 ~CertificateFile()
119 {
120 if (std::filesystem::exists(certDirectory))
121 {
Ed Tanous62598e32023-07-17 17:06:25 -0700122 BMCWEB_LOG_DEBUG("Removing certificate file{}",
123 certificateFile.string());
Ed Tanous23a21a12020-07-25 04:45:05 +0000124 std::error_code ec;
125 std::filesystem::remove_all(certDirectory, ec);
126 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600127 {
Ed Tanous62598e32023-07-17 17:06:25 -0700128 BMCWEB_LOG_ERROR("Failed to remove temp directory{}",
129 certDirectory.string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600130 }
131 }
132 }
133 std::string getCertFilePath()
134 {
135 return certificateFile;
136 }
137
138 private:
139 std::filesystem::path certificateFile;
140 std::filesystem::path certDirectory;
141};
142
143/**
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500144 * @brief Parse and update Certificate Issue/Subject property
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600145 *
146 * @param[in] asyncResp Shared pointer to the response message
147 * @param[in] str Issuer/Subject value in key=value pairs
148 * @param[in] type Issuer/Subject
149 * @return None
150 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500151static void updateCertIssuerOrSubject(nlohmann::json& out,
Ed Tanous26ccae32023-02-16 10:28:44 -0800152 std::string_view value)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600153{
154 // example: O=openbmc-project.xyz,CN=localhost
155 std::string_view::iterator i = value.begin();
156 while (i != value.end())
157 {
158 std::string_view::iterator tokenBegin = i;
159 while (i != value.end() && *i != '=')
160 {
Patrick Williams6da47ba2023-05-11 11:53:56 -0500161 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600162 }
163 if (i == value.end())
164 {
165 break;
166 }
Ed Tanous26ccae32023-02-16 10:28:44 -0800167 std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin));
Patrick Williams6da47ba2023-05-11 11:53:56 -0500168 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600169 tokenBegin = i;
170 while (i != value.end() && *i != ',')
171 {
Patrick Williams6da47ba2023-05-11 11:53:56 -0500172 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600173 }
Ed Tanous26ccae32023-02-16 10:28:44 -0800174 std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600175 if (key == "L")
176 {
177 out["City"] = val;
178 }
179 else if (key == "CN")
180 {
181 out["CommonName"] = val;
182 }
183 else if (key == "C")
184 {
185 out["Country"] = val;
186 }
187 else if (key == "O")
188 {
189 out["Organization"] = val;
190 }
191 else if (key == "OU")
192 {
193 out["OrganizationalUnit"] = val;
194 }
195 else if (key == "ST")
196 {
197 out["State"] = val;
198 }
199 // skip comma character
200 if (i != value.end())
201 {
Patrick Williams6da47ba2023-05-11 11:53:56 -0500202 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600203 }
204 }
205}
206
207/**
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800208 * @brief Retrieve the installed certificate list
209 *
210 * @param[in] asyncResp Shared pointer to the response message
211 * @param[in] basePath DBus object path to search
212 * @param[in] listPtr Json pointer to the list in asyncResp
213 * @param[in] countPtr Json pointer to the count in asyncResp
214 * @return None
215 */
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400216static void getCertificateList(
217 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218 const std::string& basePath, const nlohmann::json::json_pointer& listPtr,
219 const nlohmann::json::json_pointer& countPtr)
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800220{
George Liu7a1dbc42022-12-07 16:03:22 +0800221 constexpr std::array<std::string_view, 1> interfaces = {
222 certs::certPropIntf};
223 dbus::utility::getSubTreePaths(
224 basePath, 0, interfaces,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800225 [asyncResp, listPtr, countPtr](
George Liu7a1dbc42022-12-07 16:03:22 +0800226 const boost::system::error_code& ec,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800227 const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400228 if (ec)
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800229 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400230 BMCWEB_LOG_ERROR("Certificate collection query failed: {}", ec);
231 messages::internalError(asyncResp->res);
232 return;
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800233 }
234
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400235 nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
236 links = nlohmann::json::array();
237 for (const auto& certPath : certPaths)
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800238 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400239 sdbusplus::message::object_path objPath(certPath);
240 std::string certId = objPath.filename();
241 if (certId.empty())
242 {
243 BMCWEB_LOG_ERROR("Invalid certificate objPath {}",
244 certPath);
245 continue;
246 }
247
248 boost::urls::url certURL;
249 if (objPath.parent_path() == certs::httpsObjectPath)
250 {
251 certURL = boost::urls::format(
252 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
253 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
254 }
255 else if (objPath.parent_path() == certs::ldapObjectPath)
256 {
257 certURL = boost::urls::format(
258 "/redfish/v1/AccountService/LDAP/Certificates/{}",
259 certId);
260 }
261 else if (objPath.parent_path() == certs::authorityObjectPath)
262 {
263 certURL = boost::urls::format(
264 "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
265 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
266 }
267 else
268 {
269 continue;
270 }
271
272 nlohmann::json::object_t link;
273 link["@odata.id"] = certURL;
274 links.emplace_back(std::move(link));
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800275 }
276
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400277 asyncResp->res.jsonValue[countPtr] = links.size();
278 });
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800279}
280
281/**
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600282 * @brief Retrieve the certificates properties and append to the response
283 * message
284 *
285 * @param[in] asyncResp Shared pointer to the response message
286 * @param[in] objectPath Path of the D-Bus service object
287 * @param[in] certId Id of the certificate
288 * @param[in] certURL URL of the certificate object
289 * @param[in] name name of the certificate
290 * @return None
291 */
292static void getCertificateProperties(
zhanghch058d1b46d2021-04-01 11:18:24 +0800293 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800294 const std::string& objectPath, const std::string& service,
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800295 const std::string& certId, const boost::urls::url& certURL,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800296 const std::string& name)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600297{
Ed Tanous62598e32023-07-17 17:06:25 -0700298 BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}",
299 objectPath, certId, certURL);
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200300 sdbusplus::asio::getAllProperties(
301 *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800302 [asyncResp, certURL, certId,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800303 name](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800304 const dbus::utility::DBusPropertiesMap& properties) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400305 if (ec)
306 {
307 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
308 messages::resourceNotFound(asyncResp->res, "Certificate",
309 certId);
310 return;
311 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200312
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400313 const std::string* certificateString = nullptr;
314 const std::vector<std::string>* keyUsage = nullptr;
315 const std::string* issuer = nullptr;
316 const std::string* subject = nullptr;
317 const uint64_t* validNotAfter = nullptr;
318 const uint64_t* validNotBefore = nullptr;
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200319
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400320 const bool success = sdbusplus::unpackPropertiesNoThrow(
321 dbus_utils::UnpackErrorPrinter(), properties,
322 "CertificateString", certificateString, "KeyUsage", keyUsage,
323 "Issuer", issuer, "Subject", subject, "ValidNotAfter",
324 validNotAfter, "ValidNotBefore", validNotBefore);
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200325
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400326 if (!success)
327 {
328 messages::internalError(asyncResp->res);
329 return;
330 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200331
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400332 asyncResp->res.jsonValue["@odata.id"] = certURL;
333 asyncResp->res.jsonValue["@odata.type"] =
334 "#Certificate.v1_0_0.Certificate";
335 asyncResp->res.jsonValue["Id"] = certId;
336 asyncResp->res.jsonValue["Name"] = name;
337 asyncResp->res.jsonValue["Description"] = name;
338 asyncResp->res.jsonValue["CertificateString"] = "";
339 asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200340
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400341 if (certificateString != nullptr)
342 {
343 asyncResp->res.jsonValue["CertificateString"] =
344 *certificateString;
345 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200346
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400347 if (keyUsage != nullptr)
348 {
349 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
350 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200351
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400352 if (issuer != nullptr)
353 {
354 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
355 *issuer);
356 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200357
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400358 if (subject != nullptr)
359 {
360 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
361 *subject);
362 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200363
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400364 if (validNotAfter != nullptr)
365 {
366 asyncResp->res.jsonValue["ValidNotAfter"] =
367 redfish::time_utils::getDateTimeUint(*validNotAfter);
368 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200369
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400370 if (validNotBefore != nullptr)
371 {
372 asyncResp->res.jsonValue["ValidNotBefore"] =
373 redfish::time_utils::getDateTimeUint(*validNotBefore);
374 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200375
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400376 asyncResp->res.addHeader(
377 boost::beast::http::field::location,
378 std::string_view(certURL.data(), certURL.size()));
379 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600380}
381
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800382static void
383 deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
384 const std::string& service,
385 const sdbusplus::message::object_path& objectPath)
386{
387 crow::connections::systemBus->async_method_call(
388 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800389 id{objectPath.filename()}](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400390 if (ec)
391 {
392 messages::resourceNotFound(asyncResp->res, "Certificate", id);
393 return;
394 }
395 BMCWEB_LOG_INFO("Certificate deleted");
396 asyncResp->res.result(boost::beast::http::status::no_content);
397 },
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800398 service, objectPath, certs::objDeleteIntf, "Delete");
399}
400
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800401inline void handleCertificateServiceGet(
402 App& app, const crow::Request& req,
403 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600404{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800405 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
406 {
407 return;
408 }
409
Ninad Palsule3e72c202023-03-27 17:19:55 -0500410 if (req.session == nullptr)
411 {
412 messages::internalError(asyncResp->res);
413 return;
414 }
415
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800416 asyncResp->res.jsonValue["@odata.type"] =
417 "#CertificateService.v1_0_0.CertificateService";
418 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
419 asyncResp->res.jsonValue["Id"] = "CertificateService";
420 asyncResp->res.jsonValue["Name"] = "Certificate Service";
421 asyncResp->res.jsonValue["Description"] =
422 "Actions available to manage certificates";
423 // /redfish/v1/CertificateService/CertificateLocations is something
424 // only ConfigureManager can access then only display when the user
425 // has permissions ConfigureManager
426 Privileges effectiveUserPrivileges =
Ninad Palsule3e72c202023-03-27 17:19:55 -0500427 redfish::getUserPrivileges(*req.session);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800428 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
429 effectiveUserPrivileges))
430 {
431 asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
432 "/redfish/v1/CertificateService/CertificateLocations";
433 }
434 nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
435 nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
436 replace["target"] =
437 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
438 nlohmann::json::array_t allowed;
Patrick Williamsad539542023-05-12 10:10:08 -0500439 allowed.emplace_back("PEM");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800440 replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
441 actions["#CertificateService.GenerateCSR"]["target"] =
442 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
443}
444
445inline void handleCertificateLocationsGet(
446 App& app, const crow::Request& req,
447 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
448{
449 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
450 {
451 return;
452 }
453 asyncResp->res.jsonValue["@odata.id"] =
454 "/redfish/v1/CertificateService/CertificateLocations";
455 asyncResp->res.jsonValue["@odata.type"] =
456 "#CertificateLocations.v1_0_0.CertificateLocations";
457 asyncResp->res.jsonValue["Name"] = "Certificate Locations";
458 asyncResp->res.jsonValue["Id"] = "CertificateLocations";
459 asyncResp->res.jsonValue["Description"] =
460 "Defines a resource that an administrator can use in order to "
461 "locate all certificates installed on a given service";
462
463 getCertificateList(asyncResp, certs::baseObjectPath,
464 "/Links/Certificates"_json_pointer,
465 "/Links/Certificates@odata.count"_json_pointer);
466}
467
468inline void handleReplaceCertificateAction(
469 App& app, const crow::Request& req,
470 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
471{
472 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
473 {
474 return;
475 }
476 std::string certificate;
Ed Tanous7a31e332024-03-06 12:17:43 -0800477 std::string certURI;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800478 std::optional<std::string> certificateType = "PEM";
479
480 if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
Ed Tanous7a31e332024-03-06 12:17:43 -0800481 certificate, "CertificateUri/@odata.id",
482 certURI, "CertificateType", certificateType))
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800483 {
Ed Tanous62598e32023-07-17 17:06:25 -0700484 BMCWEB_LOG_ERROR("Required parameters are missing");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800485 return;
486 }
487
488 if (!certificateType)
489 {
490 // should never happen, but it never hurts to be paranoid.
491 return;
492 }
493 if (certificateType != "PEM")
494 {
495 messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
496 "ReplaceCertificate");
497 return;
498 }
499
Ed Tanous62598e32023-07-17 17:06:25 -0700500 BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800501
Ed Tanous6fd29552023-10-04 09:40:14 -0700502 boost::system::result<boost::urls::url> parsedUrl =
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800503 boost::urls::parse_relative_ref(certURI);
504 if (!parsedUrl)
505 {
506 messages::actionParameterValueFormatError(
507 asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
508 return;
509 }
510
511 std::string id;
512 sdbusplus::message::object_path objectPath;
513 std::string name;
514 std::string service;
515 if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
516 "bmc", "NetworkProtocol", "HTTPS",
517 "Certificates", std::ref(id)))
518 {
Patrick Williams89492a12023-05-10 07:51:34 -0500519 objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) /
520 id;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800521 name = "HTTPS certificate";
522 service = certs::httpsServiceName;
523 }
524 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
525 "AccountService", "LDAP",
526 "Certificates", std::ref(id)))
527 {
Patrick Williams89492a12023-05-10 07:51:34 -0500528 objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) /
529 id;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800530 name = "LDAP certificate";
531 service = certs::ldapServiceName;
532 }
533 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
534 "Managers", "bmc", "Truststore",
535 "Certificates", std::ref(id)))
536 {
537 objectPath =
538 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
539 name = "TrustStore certificate";
540 service = certs::authorityServiceName;
541 }
542 else
543 {
544 messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
545 "ReplaceCertificate");
546 return;
547 }
548
549 std::shared_ptr<CertificateFile> certFile =
550 std::make_shared<CertificateFile>(certificate);
551 crow::connections::systemBus->async_method_call(
552 [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800553 name](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400554 if (ec)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800555 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400556 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
557 if (ec.value() ==
558 boost::system::linux_error::bad_request_descriptor)
559 {
560 messages::resourceNotFound(asyncResp->res, "Certificate",
561 id);
562 return;
563 }
564 messages::internalError(asyncResp->res);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800565 return;
566 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400567 getCertificateProperties(asyncResp, objectPath, service, id, url,
568 name);
569 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
570 certFile->getCertFilePath());
571 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800572 service, objectPath, certs::certReplaceIntf, "Replace",
573 certFile->getCertFilePath());
574}
575
Ed Tanouscf9e4172022-12-21 09:30:16 -0800576// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800577static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
578/**
579 * @brief Read data from CSR D-bus object and set to response
580 *
581 * @param[in] asyncResp Shared pointer to the response message
Ed Tanous8ece0e42024-01-02 13:16:50 -0800582 * @param[in] certURI Link to certificate collection URI
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800583 * @param[in] service D-Bus service name
584 * @param[in] certObjPath certificate D-Bus object path
585 * @param[in] csrObjPath CSR D-Bus object path
586 * @return None
587 */
588static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
589 const std::string& certURI, const std::string& service,
590 const std::string& certObjPath,
591 const std::string& csrObjPath)
592{
Ed Tanous62598e32023-07-17 17:06:25 -0700593 BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}",
594 certObjPath, csrObjPath, service);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800595 crow::connections::systemBus->async_method_call(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400596 [asyncResp,
597 certURI](const boost::system::error_code& ec, const std::string& csr) {
598 if (ec)
599 {
600 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
601 messages::internalError(asyncResp->res);
602 return;
603 }
604 if (csr.empty())
605 {
606 BMCWEB_LOG_ERROR("CSR read is empty");
607 messages::internalError(asyncResp->res);
608 return;
609 }
610 asyncResp->res.jsonValue["CSRString"] = csr;
611 asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
612 certURI;
613 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800614 service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
615}
616
617inline void
618 handleGenerateCSRAction(App& app, const crow::Request& req,
619 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
620{
621 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
622 {
623 return;
624 }
625 static const int rsaKeyBitLength = 2048;
626
627 // Required parameters
628 std::string city;
629 std::string commonName;
630 std::string country;
631 std::string organization;
632 std::string organizationalUnit;
633 std::string state;
Ed Tanous7a31e332024-03-06 12:17:43 -0800634 std::string certURI;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800635
636 // Optional parameters
637 std::optional<std::vector<std::string>> optAlternativeNames =
638 std::vector<std::string>();
639 std::optional<std::string> optContactPerson = "";
640 std::optional<std::string> optChallengePassword = "";
641 std::optional<std::string> optEmail = "";
642 std::optional<std::string> optGivenName = "";
643 std::optional<std::string> optInitials = "";
644 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
645 std::optional<std::string> optKeyCurveId = "secp384r1";
646 std::optional<std::string> optKeyPairAlgorithm = "EC";
647 std::optional<std::vector<std::string>> optKeyUsage =
648 std::vector<std::string>();
649 std::optional<std::string> optSurname = "";
650 std::optional<std::string> optUnstructuredName = "";
651 if (!json_util::readJsonAction(
652 req, asyncResp->res, "City", city, "CommonName", commonName,
653 "ContactPerson", optContactPerson, "Country", country,
654 "Organization", organization, "OrganizationalUnit",
Ed Tanous7a31e332024-03-06 12:17:43 -0800655 organizationalUnit, "State", state,
656 "CertificateCollection/@odata.id", certURI, "AlternativeNames",
657 optAlternativeNames, "ChallengePassword", optChallengePassword,
658 "Email", optEmail, "GivenName", optGivenName, "Initials",
659 optInitials, "KeyBitLength", optKeyBitLength, "KeyCurveId",
660 optKeyCurveId, "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
661 optKeyUsage, "Surname", optSurname, "UnstructuredName",
662 optUnstructuredName))
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800663 {
664 return;
665 }
666
667 // bmcweb has no way to store or decode a private key challenge
668 // password, which will likely cause bmcweb to crash on startup
669 // if this is not set on a post so not allowing the user to set
670 // value
671 if (!optChallengePassword->empty())
672 {
673 messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
674 "ChallengePassword");
675 return;
676 }
677
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800678 std::string objectPath;
679 std::string service;
Ed Tanous253f11b2024-05-16 09:38:31 -0700680 if (certURI.starts_with(std::format(
681 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
682 BMCWEB_REDFISH_MANAGER_URI_NAME)))
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800683 {
684 objectPath = certs::httpsObjectPath;
685 service = certs::httpsServiceName;
686 }
687 else if (certURI.starts_with(
688 "/redfish/v1/AccountService/LDAP/Certificates"))
689 {
690 objectPath = certs::ldapObjectPath;
691 service = certs::ldapServiceName;
692 }
693 else
694 {
695 messages::actionParameterNotSupported(
696 asyncResp->res, "CertificateCollection", "GenerateCSR");
697 return;
698 }
699
700 // supporting only EC and RSA algorithm
701 if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
702 {
703 messages::actionParameterNotSupported(
704 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
705 return;
706 }
707
708 // supporting only 2048 key bit length for RSA algorithm due to
709 // time consumed in generating private key
710 if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
711 {
Ed Tanouse2616cc2022-06-27 12:45:55 -0700712 messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
713 "KeyBitLength");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800714 return;
715 }
716
717 // validate KeyUsage supporting only 1 type based on URL
Ed Tanous253f11b2024-05-16 09:38:31 -0700718 if (certURI.starts_with(std::format(
719 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
720 BMCWEB_REDFISH_MANAGER_URI_NAME)))
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800721 {
722 if (optKeyUsage->empty())
723 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500724 optKeyUsage->emplace_back("ServerAuthentication");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800725 }
726 else if (optKeyUsage->size() == 1)
727 {
728 if ((*optKeyUsage)[0] != "ServerAuthentication")
729 {
730 messages::propertyValueNotInList(asyncResp->res,
731 (*optKeyUsage)[0], "KeyUsage");
732 return;
733 }
734 }
735 else
736 {
737 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
738 "GenerateCSR");
739 return;
740 }
741 }
742 else if (certURI.starts_with(
743 "/redfish/v1/AccountService/LDAP/Certificates"))
744 {
745 if (optKeyUsage->empty())
746 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500747 optKeyUsage->emplace_back("ClientAuthentication");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800748 }
749 else if (optKeyUsage->size() == 1)
750 {
751 if ((*optKeyUsage)[0] != "ClientAuthentication")
752 {
753 messages::propertyValueNotInList(asyncResp->res,
754 (*optKeyUsage)[0], "KeyUsage");
755 return;
756 }
757 }
758 else
759 {
760 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
761 "GenerateCSR");
762 return;
763 }
764 }
765
766 // Only allow one CSR matcher at a time so setting retry
767 // time-out and timer expiry to 10 seconds for now.
768 static const int timeOut = 10;
769 if (csrMatcher)
770 {
771 messages::serviceTemporarilyUnavailable(asyncResp->res,
772 std::to_string(timeOut));
773 return;
774 }
775
Ed Tanous8e8245d2024-04-11 22:21:38 -0700776 if (req.ioService == nullptr)
777 {
778 messages::internalError(asyncResp->res);
779 return;
780 }
781
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800782 // Make this static so it survives outside this method
783 static boost::asio::steady_timer timeout(*req.ioService);
784 timeout.expires_after(std::chrono::seconds(timeOut));
785 timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
786 csrMatcher = nullptr;
787 if (ec)
788 {
789 // operation_aborted is expected if timer is canceled
790 // before completion.
791 if (ec != boost::asio::error::operation_aborted)
792 {
Ed Tanous62598e32023-07-17 17:06:25 -0700793 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800794 }
795 return;
796 }
Ed Tanous62598e32023-07-17 17:06:25 -0700797 BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800798 messages::internalError(asyncResp->res);
799 });
800
801 // create a matcher to wait on CSR object
Ed Tanous62598e32023-07-17 17:06:25 -0700802 BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800803 std::string match("type='signal',"
804 "interface='org.freedesktop.DBus.ObjectManager',"
805 "path='" +
806 objectPath +
807 "',"
808 "member='InterfacesAdded'");
809 csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
810 *crow::connections::systemBus, match,
811 [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400812 timeout.cancel();
813 if (m.is_method_error())
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800814 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400815 BMCWEB_LOG_ERROR("Dbus method error!!!");
816 messages::internalError(asyncResp->res);
817 return;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800818 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400819
820 dbus::utility::DBusInterfacesMap interfacesProperties;
821
822 sdbusplus::message::object_path csrObjectPath;
823 m.read(csrObjectPath, interfacesProperties);
824 BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
825 for (const auto& interface : interfacesProperties)
826 {
827 if (interface.first == "xyz.openbmc_project.Certs.CSR")
828 {
829 getCSR(asyncResp, certURI, service, objectPath,
830 csrObjectPath.str);
831 break;
832 }
833 }
834 });
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800835 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800836 [asyncResp](const boost::system::error_code& ec, const std::string&) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400837 if (ec)
838 {
839 BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
840 messages::internalError(asyncResp->res);
841 return;
842 }
843 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800844 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
845 "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
846 commonName, *optContactPerson, country, *optEmail, *optGivenName,
847 *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
848 *optKeyUsage, organization, organizationalUnit, state, *optSurname,
849 *optUnstructuredName);
850}
851
852inline void requestRoutesCertificateService(App& app)
853{
854 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
855 .privileges(redfish::privileges::getCertificateService)
856 .methods(boost::beast::http::verb::get)(
857 std::bind_front(handleCertificateServiceGet, std::ref(app)));
858
859 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
860 .privileges(redfish::privileges::getCertificateLocations)
861 .methods(boost::beast::http::verb::get)(
862 std::bind_front(handleCertificateLocationsGet, std::ref(app)));
863
George Liu0fda0f12021-11-16 10:06:17 +0800864 BMCWEB_ROUTE(
865 app,
866 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
Ed Tanoused398212021-06-09 17:05:54 -0700867 .privileges(redfish::privileges::postCertificateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700868 .methods(boost::beast::http::verb::post)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800869 std::bind_front(handleReplaceCertificateAction, std::ref(app)));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600870
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800871 BMCWEB_ROUTE(
872 app,
873 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
874 .privileges(redfish::privileges::postCertificateService)
875 .methods(boost::beast::http::verb::post)(
876 std::bind_front(handleGenerateCSRAction, std::ref(app)));
877} // requestRoutesCertificateService
878
879inline void handleHTTPSCertificateCollectionGet(
880 App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700881 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
882 const std::string& managerId)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800883{
884 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
885 {
886 return;
887 }
888
Ed Tanous253f11b2024-05-16 09:38:31 -0700889 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
890 {
891 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
892 return;
893 }
894
895 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
896 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates",
897 BMCWEB_REDFISH_MANAGER_URI_NAME);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800898 asyncResp->res.jsonValue["@odata.type"] =
899 "#CertificateCollection.CertificateCollection";
900 asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
901 asyncResp->res.jsonValue["Description"] =
902 "A Collection of HTTPS certificate instances";
903
904 getCertificateList(asyncResp, certs::httpsObjectPath,
905 "/Members"_json_pointer,
906 "/Members@odata.count"_json_pointer);
907}
908
909inline void handleHTTPSCertificateCollectionPost(
910 App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700911 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
912 const std::string& managerId)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800913{
914 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
915 {
916 return;
917 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700918
919 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
920 {
921 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
922 return;
923 }
924
Ed Tanous62598e32023-07-17 17:06:25 -0700925 BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800926
927 asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
928 asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
929
Ed Tanousb2896142024-01-31 15:25:47 -0800930 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800931
Ed Tanousb2896142024-01-31 15:25:47 -0800932 if (certHttpBody.empty())
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800933 {
Ed Tanous62598e32023-07-17 17:06:25 -0700934 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800935 messages::unrecognizedRequestBody(asyncResp->res);
936 return;
937 }
938
939 std::shared_ptr<CertificateFile> certFile =
Ed Tanousb2896142024-01-31 15:25:47 -0800940 std::make_shared<CertificateFile>(certHttpBody);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800941
942 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800943 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800944 const std::string& objectPath) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400945 if (ec)
946 {
947 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
948 messages::internalError(asyncResp->res);
949 return;
950 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700951
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400952 sdbusplus::message::object_path path(objectPath);
953 std::string certId = path.filename();
954 const boost::urls::url certURL = boost::urls::format(
955 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
956 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
957 getCertificateProperties(asyncResp, objectPath,
958 certs::httpsServiceName, certId, certURL,
959 "HTTPS Certificate");
960 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
961 certFile->getCertFilePath());
962 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800963 certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
964 "Install", certFile->getCertFilePath());
965}
Ed Tanous002d39b2022-05-31 08:59:27 -0700966
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800967inline void handleHTTPSCertificateGet(
968 App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -0700969 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
970 const std::string& managerId, const std::string& certId)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800971{
972 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
973 {
974 return;
975 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700976
Ed Tanous253f11b2024-05-16 09:38:31 -0700977 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
978 {
979 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
980 return;
981 }
982
983 BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId);
Ed Tanousef4c65b2023-04-24 15:28:50 -0700984 const boost::urls::url certURL = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -0700985 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}",
986 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800987 std::string objPath =
Ed Tanous253f11b2024-05-16 09:38:31 -0700988 sdbusplus::message::object_path(certs::httpsObjectPath) / certId;
989 getCertificateProperties(asyncResp, objPath, certs::httpsServiceName,
990 certId, certURL, "HTTPS Certificate");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800991}
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700992
993inline void requestRoutesHTTPSCertificate(App& app)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600994{
Ed Tanous253f11b2024-05-16 09:38:31 -0700995 BMCWEB_ROUTE(
996 app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800997 .privileges(redfish::privileges::getCertificateCollection)
998 .methods(boost::beast::http::verb::get)(std::bind_front(
999 handleHTTPSCertificateCollectionGet, std::ref(app)));
1000
Ed Tanous253f11b2024-05-16 09:38:31 -07001001 BMCWEB_ROUTE(
1002 app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/")
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001003 .privileges(redfish::privileges::postCertificateCollection)
1004 .methods(boost::beast::http::verb::post)(std::bind_front(
1005 handleHTTPSCertificateCollectionPost, std::ref(app)));
1006
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001007 BMCWEB_ROUTE(
1008 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07001009 "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001010 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao1e312592022-06-14 12:58:09 +08001011 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001012 std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001013}
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001014
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001015inline void handleLDAPCertificateCollectionGet(
1016 App& app, const crow::Request& req,
1017 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001018{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001019 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1020 {
1021 return;
1022 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001023
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001024 asyncResp->res.jsonValue["@odata.id"] =
1025 "/redfish/v1/AccountService/LDAP/Certificates";
1026 asyncResp->res.jsonValue["@odata.type"] =
1027 "#CertificateCollection.CertificateCollection";
1028 asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
1029 asyncResp->res.jsonValue["Description"] =
1030 "A Collection of LDAP certificate instances";
Ed Tanous002d39b2022-05-31 08:59:27 -07001031
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001032 getCertificateList(asyncResp, certs::ldapObjectPath,
1033 "/Members"_json_pointer,
1034 "/Members@odata.count"_json_pointer);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001035}
Marri Devender Rao37cce912019-02-20 01:05:22 -06001036
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001037inline void handleLDAPCertificateCollectionPost(
1038 App& app, const crow::Request& req,
1039 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001040{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001041 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1042 {
1043 return;
1044 }
Ed Tanousb2896142024-01-31 15:25:47 -08001045 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001046
Ed Tanousb2896142024-01-31 15:25:47 -08001047 if (certHttpBody.empty())
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001048 {
Ed Tanous62598e32023-07-17 17:06:25 -07001049 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001050 messages::unrecognizedRequestBody(asyncResp->res);
1051 return;
1052 }
1053
1054 std::shared_ptr<CertificateFile> certFile =
Ed Tanousb2896142024-01-31 15:25:47 -08001055 std::make_shared<CertificateFile>(certHttpBody);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001056
1057 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001058 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001059 const std::string& objectPath) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001060 if (ec)
1061 {
1062 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
1063 messages::internalError(asyncResp->res);
1064 return;
1065 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001066
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001067 sdbusplus::message::object_path path(objectPath);
1068 std::string certId = path.filename();
1069 const boost::urls::url certURL = boost::urls::format(
1070 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
1071 getCertificateProperties(asyncResp, objectPath,
1072 certs::ldapServiceName, certId, certURL,
1073 "LDAP Certificate");
1074 BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
1075 certFile->getCertFilePath());
1076 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001077 certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1078 "Install", certFile->getCertFilePath());
1079}
Ed Tanous002d39b2022-05-31 08:59:27 -07001080
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001081inline void handleLDAPCertificateGet(
1082 App& app, const crow::Request& req,
1083 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1084{
1085 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1086 {
1087 return;
1088 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001089
Ed Tanous62598e32023-07-17 17:06:25 -07001090 BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
Ed Tanousef4c65b2023-04-24 15:28:50 -07001091 const boost::urls::url certURL = boost::urls::format(
1092 "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001093 std::string objPath =
1094 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1095 getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1096 certURL, "LDAP Certificate");
1097}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001098
Jiaqing Zhao99612242022-09-29 15:31:09 +08001099inline void handleLDAPCertificateDelete(
1100 App& app, const crow::Request& req,
1101 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1102{
1103 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1104 {
1105 return;
1106 }
1107
Ed Tanous62598e32023-07-17 17:06:25 -07001108 BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
Jiaqing Zhao99612242022-09-29 15:31:09 +08001109 std::string objPath =
1110 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1111
1112 deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
1113}
1114
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001115inline void requestRoutesLDAPCertificate(App& app)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001116{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001117 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1118 .privileges(redfish::privileges::getCertificateCollection)
1119 .methods(boost::beast::http::verb::get)(
1120 std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1121
1122 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1123 .privileges(redfish::privileges::postCertificateCollection)
1124 .methods(boost::beast::http::verb::post)(std::bind_front(
1125 handleLDAPCertificateCollectionPost, std::ref(app)));
1126
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001127 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001128 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001129 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001130 std::bind_front(handleLDAPCertificateGet, std::ref(app)));
Jiaqing Zhao99612242022-09-29 15:31:09 +08001131
1132 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1133 .privileges(redfish::privileges::deleteCertificate)
1134 .methods(boost::beast::http::verb::delete_)(
1135 std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001136} // requestRoutesLDAPCertificate
1137
1138inline void handleTrustStoreCertificateCollectionGet(
1139 App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07001140 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1141 const std::string& managerId)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001142{
1143 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1144 {
1145 return;
1146 }
1147
Ed Tanous253f11b2024-05-16 09:38:31 -07001148 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1149 {
1150 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1151 return;
1152 }
1153
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001154 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001155 boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/",
1156 BMCWEB_REDFISH_MANAGER_URI_NAME);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001157 asyncResp->res.jsonValue["@odata.type"] =
1158 "#CertificateCollection.CertificateCollection";
1159 asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
1160 asyncResp->res.jsonValue["Description"] =
1161 "A Collection of TrustStore certificate instances";
1162
1163 getCertificateList(asyncResp, certs::authorityObjectPath,
1164 "/Members"_json_pointer,
1165 "/Members@odata.count"_json_pointer);
1166}
1167
1168inline void handleTrustStoreCertificateCollectionPost(
1169 App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07001170 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1171 const std::string& managerId)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001172{
1173 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1174 {
1175 return;
1176 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001177
1178 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1179 {
1180 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1181 return;
1182 }
1183
Ed Tanousb2896142024-01-31 15:25:47 -08001184 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001185
Ed Tanousb2896142024-01-31 15:25:47 -08001186 if (certHttpBody.empty())
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001187 {
Ed Tanous62598e32023-07-17 17:06:25 -07001188 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001189 messages::unrecognizedRequestBody(asyncResp->res);
1190 return;
1191 }
1192
1193 std::shared_ptr<CertificateFile> certFile =
Ed Tanousb2896142024-01-31 15:25:47 -08001194 std::make_shared<CertificateFile>(certHttpBody);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001195 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001196 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001197 const std::string& objectPath) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001198 if (ec)
1199 {
1200 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
1201 messages::internalError(asyncResp->res);
1202 return;
1203 }
Jiaqing Zhao717b9802022-06-06 20:24:04 +08001204
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001205 sdbusplus::message::object_path path(objectPath);
1206 std::string certId = path.filename();
1207 const boost::urls::url certURL = boost::urls::format(
1208 "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1209 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
1210 getCertificateProperties(asyncResp, objectPath,
1211 certs::authorityServiceName, certId,
1212 certURL, "TrustStore Certificate");
1213 BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
1214 certFile->getCertFilePath());
1215 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001216 certs::authorityServiceName, certs::authorityObjectPath,
1217 certs::certInstallIntf, "Install", certFile->getCertFilePath());
1218}
1219
1220inline void handleTrustStoreCertificateGet(
1221 App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07001222 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1223 const std::string& managerId, const std::string& certId)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001224{
1225 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1226 {
1227 return;
1228 }
1229
Ed Tanous253f11b2024-05-16 09:38:31 -07001230 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1231 {
1232 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1233 return;
1234 }
1235
1236 BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId);
Ed Tanousef4c65b2023-04-24 15:28:50 -07001237 const boost::urls::url certURL = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001238 "/redfish/v1/Managers/{}/Truststore/Certificates/{}",
1239 BMCWEB_REDFISH_MANAGER_URI_NAME, certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001240 std::string objPath =
Ed Tanous253f11b2024-05-16 09:38:31 -07001241 sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001242 getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
Ed Tanous253f11b2024-05-16 09:38:31 -07001243 certId, certURL, "TrustStore Certificate");
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001244}
1245
1246inline void handleTrustStoreCertificateDelete(
1247 App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07001248 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1249 const std::string& managerId, const std::string& certId)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001250{
1251 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1252 {
1253 return;
1254 }
1255
Ed Tanous253f11b2024-05-16 09:38:31 -07001256 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
1257 {
1258 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
1259 return;
1260 }
1261
1262 BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001263 std::string objPath =
Ed Tanous253f11b2024-05-16 09:38:31 -07001264 sdbusplus::message::object_path(certs::authorityObjectPath) / certId;
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001265
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +08001266 deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001267}
1268
1269inline void requestRoutesTrustStoreCertificate(App& app)
Marri Devender Raocfcd5f62019-05-17 08:34:37 -05001270{
Ed Tanous253f11b2024-05-16 09:38:31 -07001271 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001272 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001273 .methods(boost::beast::http::verb::get)(std::bind_front(
1274 handleTrustStoreCertificateCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001275
Ed Tanous253f11b2024-05-16 09:38:31 -07001276 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001277 .privileges(redfish::privileges::postCertificateCollection)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001278 .methods(boost::beast::http::verb::post)(std::bind_front(
1279 handleTrustStoreCertificateCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07001280
Ed Tanous253f11b2024-05-16 09:38:31 -07001281 BMCWEB_ROUTE(app,
1282 "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001283 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001284 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001285 std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001286
Ed Tanous253f11b2024-05-16 09:38:31 -07001287 BMCWEB_ROUTE(app,
1288 "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001289 .privileges(redfish::privileges::deleteCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001290 .methods(boost::beast::http::verb::delete_)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001291 std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001292} // requestRoutesTrustStoreCertificate
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001293} // namespace redfish