blob: a65f33cd0aab31762d69060e258966d1e4d32d01 [file] [log] [blame]
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001#pragma once
2
George Liu7a1dbc42022-12-07 16:03:22 +08003#include "dbus_utility.hpp"
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +02004#include "utils/dbus_utils.hpp"
5
John Edward Broadbent7e860f12021-04-08 15:57:16 -07006#include <app.hpp>
Ed Tanousd9f6c622022-03-17 09:12:17 -07007#include <async_resp.hpp>
Jiaqing Zhao90d2d1e2022-04-13 17:01:57 +08008#include <boost/system/linux_error.hpp>
Ed Tanousd9f6c622022-03-17 09:12:17 -07009#include <http_response.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070010#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070011#include <registries/privilege_registry.hpp>
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020012#include <sdbusplus/asio/property.hpp>
13#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050014
George Liu7a1dbc42022-12-07 16:03:22 +080015#include <array>
16#include <string_view>
17
Marri Devender Rao5968cae2019-01-21 10:27:12 -060018namespace redfish
19{
20namespace certs
21{
Gunnar Mills1214b7e2020-06-04 10:11:30 -050022constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
23constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
24constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
25constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
26constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
27constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050028constexpr char const* httpsServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060029 "xyz.openbmc_project.Certs.Manager.Server.Https";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050030constexpr char const* ldapServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060031 "xyz.openbmc_project.Certs.Manager.Client.Ldap";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050032constexpr char const* authorityServiceName =
Marri Devender Raocfcd5f62019-05-17 08:34:37 -050033 "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
Jiaqing Zhaoc6a8dfb2022-06-03 10:44:23 +080034constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
35constexpr char const* httpsObjectPath =
36 "/xyz/openbmc_project/certs/server/https";
37constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050038constexpr char const* authorityObjectPath =
Marri Devender Raocfcd5f62019-05-17 08:34:37 -050039 "/xyz/openbmc_project/certs/authority/ldap";
Marri Devender Rao5968cae2019-01-21 10:27:12 -060040} // namespace certs
41
42/**
43 * The Certificate schema defines a Certificate Service which represents the
44 * actions available to manage certificates and links to where certificates
45 * are installed.
46 */
Marri Devender Rao5968cae2019-01-21 10:27:12 -060047
zhanghch058d1b46d2021-04-01 11:18:24 +080048inline std::string getCertificateFromReqBody(
49 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
50 const crow::Request& req)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020051{
52 nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
53
54 if (reqJson.is_discarded())
55 {
56 // We did not receive JSON request, proceed as it is RAW data
57 return req.body;
58 }
59
60 std::string certificate;
61 std::optional<std::string> certificateType = "PEM";
62
Willy Tu15ed6782021-12-14 11:03:16 -080063 if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
64 certificate, "CertificateType",
65 certificateType))
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020066 {
67 BMCWEB_LOG_ERROR << "Required parameters are missing";
68 messages::internalError(asyncResp->res);
Ed Tanousabb93cd2021-09-02 14:34:57 -070069 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020070 }
71
72 if (*certificateType != "PEM")
73 {
74 messages::propertyValueNotInList(asyncResp->res, *certificateType,
75 "CertificateType");
Ed Tanousabb93cd2021-09-02 14:34:57 -070076 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020077 }
78
79 return certificate;
80}
81
Marri Devender Rao5968cae2019-01-21 10:27:12 -060082/**
83 * Class to create a temporary certificate file for uploading to system
84 */
85class CertificateFile
86{
87 public:
88 CertificateFile() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050089 CertificateFile(const CertificateFile&) = delete;
90 CertificateFile& operator=(const CertificateFile&) = delete;
91 CertificateFile(CertificateFile&&) = delete;
92 CertificateFile& operator=(CertificateFile&&) = delete;
Ed Tanous4e23a442022-06-06 09:57:26 -070093 explicit CertificateFile(const std::string& certString)
Marri Devender Rao5968cae2019-01-21 10:27:12 -060094 {
Ed Tanous72d52d22020-10-12 07:46:27 -070095 std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
Ed Tanous52074382020-09-28 19:16:18 -070096 'e', 'r', 't', 's', '.', 'X',
97 'X', 'X', 'X', 'X', 'X', '\0'};
98 char* tempDirectory = mkdtemp(dirTemplate.data());
Ed Tanouse662eae2022-01-25 10:39:19 -080099 if (tempDirectory != nullptr)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600100 {
101 certDirectory = tempDirectory;
102 certificateFile = certDirectory / "cert.pem";
103 std::ofstream out(certificateFile, std::ofstream::out |
104 std::ofstream::binary |
105 std::ofstream::trunc);
106 out << certString;
107 out.close();
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800108 BMCWEB_LOG_DEBUG << "Creating certificate file"
109 << certificateFile.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600110 }
111 }
112 ~CertificateFile()
113 {
114 if (std::filesystem::exists(certDirectory))
115 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800116 BMCWEB_LOG_DEBUG << "Removing certificate file"
117 << certificateFile.string();
Ed Tanous23a21a12020-07-25 04:45:05 +0000118 std::error_code ec;
119 std::filesystem::remove_all(certDirectory, ec);
120 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600121 {
122 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800123 << certDirectory.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600124 }
125 }
126 }
127 std::string getCertFilePath()
128 {
129 return certificateFile;
130 }
131
132 private:
133 std::filesystem::path certificateFile;
134 std::filesystem::path certDirectory;
135};
136
137/**
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500138 * @brief Parse and update Certificate Issue/Subject property
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600139 *
140 * @param[in] asyncResp Shared pointer to the response message
141 * @param[in] str Issuer/Subject value in key=value pairs
142 * @param[in] type Issuer/Subject
143 * @return None
144 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500145static void updateCertIssuerOrSubject(nlohmann::json& out,
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600146 const std::string_view value)
147{
148 // example: O=openbmc-project.xyz,CN=localhost
149 std::string_view::iterator i = value.begin();
150 while (i != value.end())
151 {
152 std::string_view::iterator tokenBegin = i;
153 while (i != value.end() && *i != '=')
154 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530155 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600156 }
157 if (i == value.end())
158 {
159 break;
160 }
Ed Tanous271584a2019-07-09 16:24:22 -0700161 const std::string_view key(tokenBegin,
162 static_cast<size_t>(i - tokenBegin));
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530163 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600164 tokenBegin = i;
165 while (i != value.end() && *i != ',')
166 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530167 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600168 }
Ed Tanous271584a2019-07-09 16:24:22 -0700169 const std::string_view val(tokenBegin,
170 static_cast<size_t>(i - tokenBegin));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600171 if (key == "L")
172 {
173 out["City"] = val;
174 }
175 else if (key == "CN")
176 {
177 out["CommonName"] = val;
178 }
179 else if (key == "C")
180 {
181 out["Country"] = val;
182 }
183 else if (key == "O")
184 {
185 out["Organization"] = val;
186 }
187 else if (key == "OU")
188 {
189 out["OrganizationalUnit"] = val;
190 }
191 else if (key == "ST")
192 {
193 out["State"] = val;
194 }
195 // skip comma character
196 if (i != value.end())
197 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530198 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600199 }
200 }
201}
202
203/**
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800204 * @brief Retrieve the installed certificate list
205 *
206 * @param[in] asyncResp Shared pointer to the response message
207 * @param[in] basePath DBus object path to search
208 * @param[in] listPtr Json pointer to the list in asyncResp
209 * @param[in] countPtr Json pointer to the count in asyncResp
210 * @return None
211 */
212static void
213 getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
214 const std::string& basePath,
215 const nlohmann::json::json_pointer& listPtr,
216 const nlohmann::json::json_pointer& countPtr)
217{
George Liu7a1dbc42022-12-07 16:03:22 +0800218 constexpr std::array<std::string_view, 1> interfaces = {
219 certs::certPropIntf};
220 dbus::utility::getSubTreePaths(
221 basePath, 0, interfaces,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800222 [asyncResp, listPtr, countPtr](
George Liu7a1dbc42022-12-07 16:03:22 +0800223 const boost::system::error_code& ec,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800224 const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
225 if (ec)
226 {
227 BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
228 messages::internalError(asyncResp->res);
229 return;
230 }
231
232 nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
233 links = nlohmann::json::array();
234 for (const auto& certPath : certPaths)
235 {
236 sdbusplus::message::object_path objPath(certPath);
237 std::string certId = objPath.filename();
238 if (certId.empty())
239 {
240 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
241 continue;
242 }
243
244 boost::urls::url certURL;
245 if (objPath.parent_path() == certs::httpsObjectPath)
246 {
247 certURL = crow::utility::urlFromPieces(
248 "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
249 "HTTPS", "Certificates", certId);
250 }
251 else if (objPath.parent_path() == certs::ldapObjectPath)
252 {
253 certURL = crow::utility::urlFromPieces("redfish", "v1",
254 "AccountService", "LDAP",
255 "Certificates", certId);
256 }
257 else if (objPath.parent_path() == certs::authorityObjectPath)
258 {
259 certURL = crow::utility::urlFromPieces(
260 "redfish", "v1", "Managers", "bmc", "Truststore",
261 "Certificates", certId);
262 }
263 else
264 {
265 continue;
266 }
267
268 nlohmann::json::object_t link;
269 link["@odata.id"] = certURL;
270 links.emplace_back(std::move(link));
271 }
272
273 asyncResp->res.jsonValue[countPtr] = links.size();
George Liu7a1dbc42022-12-07 16:03:22 +0800274 });
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800275}
276
277/**
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600278 * @brief Retrieve the certificates properties and append to the response
279 * message
280 *
281 * @param[in] asyncResp Shared pointer to the response message
282 * @param[in] objectPath Path of the D-Bus service object
283 * @param[in] certId Id of the certificate
284 * @param[in] certURL URL of the certificate object
285 * @param[in] name name of the certificate
286 * @return None
287 */
288static void getCertificateProperties(
zhanghch058d1b46d2021-04-01 11:18:24 +0800289 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800290 const std::string& objectPath, const std::string& service,
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800291 const std::string& certId, const boost::urls::url& certURL,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800292 const std::string& name)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600293{
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600294 BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
295 << " certId=" << certId << " certURl=" << certURL;
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200296 sdbusplus::asio::getAllProperties(
297 *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800298 [asyncResp, certURL, certId,
299 name](const boost::system::error_code ec,
300 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700301 if (ec)
302 {
303 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800304 messages::resourceNotFound(asyncResp->res, "Certificate", certId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700305 return;
306 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200307
308 const std::string* certificateString = nullptr;
309 const std::vector<std::string>* keyUsage = nullptr;
310 const std::string* issuer = nullptr;
311 const std::string* subject = nullptr;
312 const uint64_t* validNotAfter = nullptr;
313 const uint64_t* validNotBefore = nullptr;
314
315 const bool success = sdbusplus::unpackPropertiesNoThrow(
316 dbus_utils::UnpackErrorPrinter(), properties, "CertificateString",
317 certificateString, "KeyUsage", keyUsage, "Issuer", issuer,
318 "Subject", subject, "ValidNotAfter", validNotAfter,
319 "ValidNotBefore", validNotBefore);
320
321 if (!success)
322 {
323 messages::internalError(asyncResp->res);
324 return;
325 }
326
Ed Tanous002d39b2022-05-31 08:59:27 -0700327 asyncResp->res.jsonValue["@odata.id"] = certURL;
328 asyncResp->res.jsonValue["@odata.type"] =
329 "#Certificate.v1_0_0.Certificate";
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800330 asyncResp->res.jsonValue["Id"] = certId;
Ed Tanous002d39b2022-05-31 08:59:27 -0700331 asyncResp->res.jsonValue["Name"] = name;
332 asyncResp->res.jsonValue["Description"] = name;
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200333 asyncResp->res.jsonValue["CertificateString"] = "";
334 asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
335
336 if (certificateString != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700337 {
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200338 asyncResp->res.jsonValue["CertificateString"] = *certificateString;
Ed Tanous002d39b2022-05-31 08:59:27 -0700339 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200340
341 if (keyUsage != nullptr)
342 {
343 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
344 }
345
346 if (issuer != nullptr)
347 {
348 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
349 *issuer);
350 }
351
352 if (subject != nullptr)
353 {
354 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
355 *subject);
356 }
357
358 if (validNotAfter != nullptr)
359 {
360 asyncResp->res.jsonValue["ValidNotAfter"] =
361 redfish::time_utils::getDateTimeUint(*validNotAfter);
362 }
363
364 if (validNotBefore != nullptr)
365 {
366 asyncResp->res.jsonValue["ValidNotBefore"] =
367 redfish::time_utils::getDateTimeUint(*validNotBefore);
368 }
369
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800370 asyncResp->res.addHeader(
Ed Tanousd9f6c622022-03-17 09:12:17 -0700371 boost::beast::http::field::location,
372 std::string_view(certURL.data(), certURL.size()));
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200373 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600374}
375
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800376static void
377 deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
378 const std::string& service,
379 const sdbusplus::message::object_path& objectPath)
380{
381 crow::connections::systemBus->async_method_call(
382 [asyncResp,
383 id{objectPath.filename()}](const boost::system::error_code ec) {
384 if (ec)
385 {
386 messages::resourceNotFound(asyncResp->res, "Certificate", id);
387 return;
388 }
389 BMCWEB_LOG_INFO << "Certificate deleted";
390 asyncResp->res.result(boost::beast::http::status::no_content);
391 },
392 service, objectPath, certs::objDeleteIntf, "Delete");
393}
394
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800395inline void handleCertificateServiceGet(
396 App& app, const crow::Request& req,
397 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600398{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800399 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
400 {
401 return;
402 }
403
404 asyncResp->res.jsonValue["@odata.type"] =
405 "#CertificateService.v1_0_0.CertificateService";
406 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
407 asyncResp->res.jsonValue["Id"] = "CertificateService";
408 asyncResp->res.jsonValue["Name"] = "Certificate Service";
409 asyncResp->res.jsonValue["Description"] =
410 "Actions available to manage certificates";
411 // /redfish/v1/CertificateService/CertificateLocations is something
412 // only ConfigureManager can access then only display when the user
413 // has permissions ConfigureManager
414 Privileges effectiveUserPrivileges =
415 redfish::getUserPrivileges(req.userRole);
416 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
417 effectiveUserPrivileges))
418 {
419 asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
420 "/redfish/v1/CertificateService/CertificateLocations";
421 }
422 nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
423 nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
424 replace["target"] =
425 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
426 nlohmann::json::array_t allowed;
427 allowed.push_back("PEM");
428 replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
429 actions["#CertificateService.GenerateCSR"]["target"] =
430 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
431}
432
433inline void handleCertificateLocationsGet(
434 App& app, const crow::Request& req,
435 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
436{
437 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
438 {
439 return;
440 }
441 asyncResp->res.jsonValue["@odata.id"] =
442 "/redfish/v1/CertificateService/CertificateLocations";
443 asyncResp->res.jsonValue["@odata.type"] =
444 "#CertificateLocations.v1_0_0.CertificateLocations";
445 asyncResp->res.jsonValue["Name"] = "Certificate Locations";
446 asyncResp->res.jsonValue["Id"] = "CertificateLocations";
447 asyncResp->res.jsonValue["Description"] =
448 "Defines a resource that an administrator can use in order to "
449 "locate all certificates installed on a given service";
450
451 getCertificateList(asyncResp, certs::baseObjectPath,
452 "/Links/Certificates"_json_pointer,
453 "/Links/Certificates@odata.count"_json_pointer);
454}
455
456inline void handleReplaceCertificateAction(
457 App& app, const crow::Request& req,
458 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
459{
460 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
461 {
462 return;
463 }
464 std::string certificate;
465 nlohmann::json certificateUri;
466 std::optional<std::string> certificateType = "PEM";
467
468 if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
469 certificate, "CertificateUri",
470 certificateUri, "CertificateType",
471 certificateType))
472 {
473 BMCWEB_LOG_ERROR << "Required parameters are missing";
474 messages::internalError(asyncResp->res);
475 return;
476 }
477
478 if (!certificateType)
479 {
480 // should never happen, but it never hurts to be paranoid.
481 return;
482 }
483 if (certificateType != "PEM")
484 {
485 messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
486 "ReplaceCertificate");
487 return;
488 }
489
490 std::string certURI;
491 if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
492 "@odata.id", certURI))
493 {
494 messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
495 "CertificateUri");
496 return;
497 }
498 BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI;
499
500 boost::urls::result<boost::urls::url_view> parsedUrl =
501 boost::urls::parse_relative_ref(certURI);
502 if (!parsedUrl)
503 {
504 messages::actionParameterValueFormatError(
505 asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
506 return;
507 }
508
509 std::string id;
510 sdbusplus::message::object_path objectPath;
511 std::string name;
512 std::string service;
513 if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
514 "bmc", "NetworkProtocol", "HTTPS",
515 "Certificates", std::ref(id)))
516 {
517 objectPath =
518 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
519 name = "HTTPS certificate";
520 service = certs::httpsServiceName;
521 }
522 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
523 "AccountService", "LDAP",
524 "Certificates", std::ref(id)))
525 {
526 objectPath =
527 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
528 name = "LDAP certificate";
529 service = certs::ldapServiceName;
530 }
531 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
532 "Managers", "bmc", "Truststore",
533 "Certificates", std::ref(id)))
534 {
535 objectPath =
536 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
537 name = "TrustStore certificate";
538 service = certs::authorityServiceName;
539 }
540 else
541 {
542 messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
543 "ReplaceCertificate");
544 return;
545 }
546
547 std::shared_ptr<CertificateFile> certFile =
548 std::make_shared<CertificateFile>(certificate);
549 crow::connections::systemBus->async_method_call(
550 [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
551 name](const boost::system::error_code ec) {
552 if (ec)
553 {
554 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
555 if (ec.value() ==
556 boost::system::linux_error::bad_request_descriptor)
557 {
558 messages::resourceNotFound(asyncResp->res, "Certificate", id);
559 return;
560 }
561 messages::internalError(asyncResp->res);
562 return;
563 }
564 getCertificateProperties(asyncResp, objectPath, service, id, url, name);
565 BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
566 << certFile->getCertFilePath();
567 },
568 service, objectPath, certs::certReplaceIntf, "Replace",
569 certFile->getCertFilePath());
570}
571
572static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
573/**
574 * @brief Read data from CSR D-bus object and set to response
575 *
576 * @param[in] asyncResp Shared pointer to the response message
577 * @param[in] certURI Link to certifiate collection URI
578 * @param[in] service D-Bus service name
579 * @param[in] certObjPath certificate D-Bus object path
580 * @param[in] csrObjPath CSR D-Bus object path
581 * @return None
582 */
583static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
584 const std::string& certURI, const std::string& service,
585 const std::string& certObjPath,
586 const std::string& csrObjPath)
587{
588 BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
589 << " CSRObjectPath=" << csrObjPath
590 << " service=" << service;
591 crow::connections::systemBus->async_method_call(
592 [asyncResp, certURI](const boost::system::error_code ec,
593 const std::string& csr) {
594 if (ec)
595 {
596 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
597 messages::internalError(asyncResp->res);
598 return;
599 }
600 if (csr.empty())
601 {
602 BMCWEB_LOG_ERROR << "CSR read is empty";
603 messages::internalError(asyncResp->res);
604 return;
605 }
606 asyncResp->res.jsonValue["CSRString"] = csr;
607 asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
608 certURI;
609 },
610 service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
611}
612
613inline void
614 handleGenerateCSRAction(App& app, const crow::Request& req,
615 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
616{
617 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
618 {
619 return;
620 }
621 static const int rsaKeyBitLength = 2048;
622
623 // Required parameters
624 std::string city;
625 std::string commonName;
626 std::string country;
627 std::string organization;
628 std::string organizationalUnit;
629 std::string state;
630 nlohmann::json certificateCollection;
631
632 // Optional parameters
633 std::optional<std::vector<std::string>> optAlternativeNames =
634 std::vector<std::string>();
635 std::optional<std::string> optContactPerson = "";
636 std::optional<std::string> optChallengePassword = "";
637 std::optional<std::string> optEmail = "";
638 std::optional<std::string> optGivenName = "";
639 std::optional<std::string> optInitials = "";
640 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
641 std::optional<std::string> optKeyCurveId = "secp384r1";
642 std::optional<std::string> optKeyPairAlgorithm = "EC";
643 std::optional<std::vector<std::string>> optKeyUsage =
644 std::vector<std::string>();
645 std::optional<std::string> optSurname = "";
646 std::optional<std::string> optUnstructuredName = "";
647 if (!json_util::readJsonAction(
648 req, asyncResp->res, "City", city, "CommonName", commonName,
649 "ContactPerson", optContactPerson, "Country", country,
650 "Organization", organization, "OrganizationalUnit",
651 organizationalUnit, "State", state, "CertificateCollection",
652 certificateCollection, "AlternativeNames", optAlternativeNames,
653 "ChallengePassword", optChallengePassword, "Email", optEmail,
654 "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
655 optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
656 optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
657 "UnstructuredName", optUnstructuredName))
658 {
659 return;
660 }
661
662 // bmcweb has no way to store or decode a private key challenge
663 // password, which will likely cause bmcweb to crash on startup
664 // if this is not set on a post so not allowing the user to set
665 // value
666 if (!optChallengePassword->empty())
667 {
668 messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
669 "ChallengePassword");
670 return;
671 }
672
673 std::string certURI;
674 if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
675 "@odata.id", certURI))
676 {
677 return;
678 }
679
680 std::string objectPath;
681 std::string service;
682 if (certURI.starts_with(
683 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
684 {
685 objectPath = certs::httpsObjectPath;
686 service = certs::httpsServiceName;
687 }
688 else if (certURI.starts_with(
689 "/redfish/v1/AccountService/LDAP/Certificates"))
690 {
691 objectPath = certs::ldapObjectPath;
692 service = certs::ldapServiceName;
693 }
694 else
695 {
696 messages::actionParameterNotSupported(
697 asyncResp->res, "CertificateCollection", "GenerateCSR");
698 return;
699 }
700
701 // supporting only EC and RSA algorithm
702 if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
703 {
704 messages::actionParameterNotSupported(
705 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
706 return;
707 }
708
709 // supporting only 2048 key bit length for RSA algorithm due to
710 // time consumed in generating private key
711 if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
712 {
713 messages::propertyValueNotInList(
714 asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength");
715 return;
716 }
717
718 // validate KeyUsage supporting only 1 type based on URL
719 if (certURI.starts_with(
720 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
721 {
722 if (optKeyUsage->empty())
723 {
724 optKeyUsage->push_back("ServerAuthentication");
725 }
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 {
747 optKeyUsage->push_back("ClientAuthentication");
748 }
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
776 // Make this static so it survives outside this method
777 static boost::asio::steady_timer timeout(*req.ioService);
778 timeout.expires_after(std::chrono::seconds(timeOut));
779 timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
780 csrMatcher = nullptr;
781 if (ec)
782 {
783 // operation_aborted is expected if timer is canceled
784 // before completion.
785 if (ec != boost::asio::error::operation_aborted)
786 {
787 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
788 }
789 return;
790 }
791 BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
792 messages::internalError(asyncResp->res);
793 });
794
795 // create a matcher to wait on CSR object
796 BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
797 std::string match("type='signal',"
798 "interface='org.freedesktop.DBus.ObjectManager',"
799 "path='" +
800 objectPath +
801 "',"
802 "member='InterfacesAdded'");
803 csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
804 *crow::connections::systemBus, match,
805 [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
806 timeout.cancel();
807 if (m.is_method_error())
808 {
809 BMCWEB_LOG_ERROR << "Dbus method error!!!";
810 messages::internalError(asyncResp->res);
811 return;
812 }
813
814 dbus::utility::DBusInteracesMap interfacesProperties;
815
816 sdbusplus::message::object_path csrObjectPath;
817 m.read(csrObjectPath, interfacesProperties);
818 BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
819 for (const auto& interface : interfacesProperties)
820 {
821 if (interface.first == "xyz.openbmc_project.Certs.CSR")
822 {
823 getCSR(asyncResp, certURI, service, objectPath,
824 csrObjectPath.str);
825 break;
826 }
827 }
828 });
829 crow::connections::systemBus->async_method_call(
830 [asyncResp](const boost::system::error_code ec, const std::string&) {
831 if (ec)
832 {
833 BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
834 messages::internalError(asyncResp->res);
835 return;
836 }
837 },
838 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
839 "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
840 commonName, *optContactPerson, country, *optEmail, *optGivenName,
841 *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
842 *optKeyUsage, organization, organizationalUnit, state, *optSurname,
843 *optUnstructuredName);
844}
845
846inline void requestRoutesCertificateService(App& app)
847{
848 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
849 .privileges(redfish::privileges::getCertificateService)
850 .methods(boost::beast::http::verb::get)(
851 std::bind_front(handleCertificateServiceGet, std::ref(app)));
852
853 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
854 .privileges(redfish::privileges::getCertificateLocations)
855 .methods(boost::beast::http::verb::get)(
856 std::bind_front(handleCertificateLocationsGet, std::ref(app)));
857
George Liu0fda0f12021-11-16 10:06:17 +0800858 BMCWEB_ROUTE(
859 app,
860 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
Ed Tanoused398212021-06-09 17:05:54 -0700861 .privileges(redfish::privileges::postCertificateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700862 .methods(boost::beast::http::verb::post)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800863 std::bind_front(handleReplaceCertificateAction, std::ref(app)));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600864
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800865 BMCWEB_ROUTE(
866 app,
867 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
868 .privileges(redfish::privileges::postCertificateService)
869 .methods(boost::beast::http::verb::post)(
870 std::bind_front(handleGenerateCSRAction, std::ref(app)));
871} // requestRoutesCertificateService
872
873inline void handleHTTPSCertificateCollectionGet(
874 App& app, const crow::Request& req,
875 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
876{
877 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
878 {
879 return;
880 }
881
882 asyncResp->res.jsonValue["@odata.id"] =
883 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
884 asyncResp->res.jsonValue["@odata.type"] =
885 "#CertificateCollection.CertificateCollection";
886 asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
887 asyncResp->res.jsonValue["Description"] =
888 "A Collection of HTTPS certificate instances";
889
890 getCertificateList(asyncResp, certs::httpsObjectPath,
891 "/Members"_json_pointer,
892 "/Members@odata.count"_json_pointer);
893}
894
895inline void handleHTTPSCertificateCollectionPost(
896 App& app, const crow::Request& req,
897 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
898{
899 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
900 {
901 return;
902 }
903 BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
904
905 asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
906 asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
907
908 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
909
910 if (certFileBody.empty())
911 {
912 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
913 messages::unrecognizedRequestBody(asyncResp->res);
914 return;
915 }
916
917 std::shared_ptr<CertificateFile> certFile =
918 std::make_shared<CertificateFile>(certFileBody);
919
920 crow::connections::systemBus->async_method_call(
921 [asyncResp, certFile](const boost::system::error_code ec,
922 const std::string& objectPath) {
923 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700924 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800925 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
Ed Tanous002d39b2022-05-31 08:59:27 -0700926 messages::internalError(asyncResp->res);
927 return;
928 }
929
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800930 sdbusplus::message::object_path path(objectPath);
931 std::string certId = path.filename();
932 const boost::urls::url certURL = crow::utility::urlFromPieces(
933 "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
934 "Certificates", certId);
935 getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
936 certId, certURL, "HTTPS Certificate");
937 BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
938 << certFile->getCertFilePath();
939 },
940 certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
941 "Install", certFile->getCertFilePath());
942}
Ed Tanous002d39b2022-05-31 08:59:27 -0700943
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800944inline void handleHTTPSCertificateGet(
945 App& app, const crow::Request& req,
946 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
947{
948 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
949 {
950 return;
951 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700952
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800953 BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id;
954 const boost::urls::url certURL = crow::utility::urlFromPieces(
955 "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
956 "Certificates", id);
957 std::string objPath =
958 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
959 getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
960 certURL, "HTTPS Certificate");
961}
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700962
963inline void requestRoutesHTTPSCertificate(App& app)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600964{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800965 BMCWEB_ROUTE(app,
966 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
967 .privileges(redfish::privileges::getCertificateCollection)
968 .methods(boost::beast::http::verb::get)(std::bind_front(
969 handleHTTPSCertificateCollectionGet, std::ref(app)));
970
971 BMCWEB_ROUTE(app,
972 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
973 .privileges(redfish::privileges::postCertificateCollection)
974 .methods(boost::beast::http::verb::post)(std::bind_front(
975 handleHTTPSCertificateCollectionPost, std::ref(app)));
976
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700977 BMCWEB_ROUTE(
978 app,
979 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700980 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800981 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800982 std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700983}
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600984
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800985inline void handleLDAPCertificateCollectionGet(
986 App& app, const crow::Request& req,
987 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600988{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800989 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
990 {
991 return;
992 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700993
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800994 asyncResp->res.jsonValue["@odata.id"] =
995 "/redfish/v1/AccountService/LDAP/Certificates";
996 asyncResp->res.jsonValue["@odata.type"] =
997 "#CertificateCollection.CertificateCollection";
998 asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
999 asyncResp->res.jsonValue["Description"] =
1000 "A Collection of LDAP certificate instances";
Ed Tanous002d39b2022-05-31 08:59:27 -07001001
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001002 getCertificateList(asyncResp, certs::ldapObjectPath,
1003 "/Members"_json_pointer,
1004 "/Members@odata.count"_json_pointer);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001005}
Marri Devender Rao37cce912019-02-20 01:05:22 -06001006
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001007inline void handleLDAPCertificateCollectionPost(
1008 App& app, const crow::Request& req,
1009 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001010{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001011 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1012 {
1013 return;
1014 }
1015 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1016
1017 if (certFileBody.empty())
1018 {
1019 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1020 messages::unrecognizedRequestBody(asyncResp->res);
1021 return;
1022 }
1023
1024 std::shared_ptr<CertificateFile> certFile =
1025 std::make_shared<CertificateFile>(certFileBody);
1026
1027 crow::connections::systemBus->async_method_call(
1028 [asyncResp, certFile](const boost::system::error_code ec,
1029 const std::string& objectPath) {
1030 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001031 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001032 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1033 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001034 return;
1035 }
1036
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001037 sdbusplus::message::object_path path(objectPath);
1038 std::string certId = path.filename();
1039 const boost::urls::url certURL = crow::utility::urlFromPieces(
1040 "redfish", "v1", "AccountService", "LDAP", "Certificates", certId);
1041 getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1042 certId, certURL, "LDAP Certificate");
1043 BMCWEB_LOG_DEBUG << "LDAP certificate install file="
1044 << certFile->getCertFilePath();
1045 },
1046 certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1047 "Install", certFile->getCertFilePath());
1048}
Ed Tanous002d39b2022-05-31 08:59:27 -07001049
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001050inline void handleLDAPCertificateGet(
1051 App& app, const crow::Request& req,
1052 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1053{
1054 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1055 {
1056 return;
1057 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001058
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001059 BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id;
1060 const boost::urls::url certURL = crow::utility::urlFromPieces(
1061 "redfish", "v1", "AccountService", "LDAP", "Certificates", id);
1062 std::string objPath =
1063 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1064 getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1065 certURL, "LDAP Certificate");
1066}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001067
Jiaqing Zhao99612242022-09-29 15:31:09 +08001068inline void handleLDAPCertificateDelete(
1069 App& app, const crow::Request& req,
1070 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1071{
1072 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1073 {
1074 return;
1075 }
1076
1077 BMCWEB_LOG_DEBUG << "Delete LDAP Certificate ID=" << id;
1078 std::string objPath =
1079 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1080
1081 deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
1082}
1083
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001084inline void requestRoutesLDAPCertificate(App& app)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001085{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001086 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1087 .privileges(redfish::privileges::getCertificateCollection)
1088 .methods(boost::beast::http::verb::get)(
1089 std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1090
1091 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1092 .privileges(redfish::privileges::postCertificateCollection)
1093 .methods(boost::beast::http::verb::post)(std::bind_front(
1094 handleLDAPCertificateCollectionPost, std::ref(app)));
1095
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001096 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001097 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001098 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001099 std::bind_front(handleLDAPCertificateGet, std::ref(app)));
Jiaqing Zhao99612242022-09-29 15:31:09 +08001100
1101 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1102 .privileges(redfish::privileges::deleteCertificate)
1103 .methods(boost::beast::http::verb::delete_)(
1104 std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001105} // requestRoutesLDAPCertificate
1106
1107inline void handleTrustStoreCertificateCollectionGet(
1108 App& app, const crow::Request& req,
1109 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1110{
1111 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1112 {
1113 return;
1114 }
1115
1116 asyncResp->res.jsonValue["@odata.id"] =
1117 "/redfish/v1/Managers/bmc/Truststore/Certificates/";
1118 asyncResp->res.jsonValue["@odata.type"] =
1119 "#CertificateCollection.CertificateCollection";
1120 asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
1121 asyncResp->res.jsonValue["Description"] =
1122 "A Collection of TrustStore certificate instances";
1123
1124 getCertificateList(asyncResp, certs::authorityObjectPath,
1125 "/Members"_json_pointer,
1126 "/Members@odata.count"_json_pointer);
1127}
1128
1129inline void handleTrustStoreCertificateCollectionPost(
1130 App& app, const crow::Request& req,
1131 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1132{
1133 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1134 {
1135 return;
1136 }
1137 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1138
1139 if (certFileBody.empty())
1140 {
1141 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1142 messages::unrecognizedRequestBody(asyncResp->res);
1143 return;
1144 }
1145
1146 std::shared_ptr<CertificateFile> certFile =
1147 std::make_shared<CertificateFile>(certFileBody);
1148 crow::connections::systemBus->async_method_call(
1149 [asyncResp, certFile](const boost::system::error_code ec,
1150 const std::string& objectPath) {
1151 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001152 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001153 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1154 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001155 return;
1156 }
Jiaqing Zhao717b9802022-06-06 20:24:04 +08001157
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001158 sdbusplus::message::object_path path(objectPath);
1159 std::string certId = path.filename();
1160 const boost::urls::url certURL =
1161 crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1162 "Truststore", "Certificates", certId);
1163 getCertificateProperties(asyncResp, objectPath,
1164 certs::authorityServiceName, certId, certURL,
1165 "TrustStore Certificate");
1166 BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1167 << certFile->getCertFilePath();
1168 },
1169 certs::authorityServiceName, certs::authorityObjectPath,
1170 certs::certInstallIntf, "Install", certFile->getCertFilePath());
1171}
1172
1173inline void handleTrustStoreCertificateGet(
1174 App& app, const crow::Request& req,
1175 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1176{
1177 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1178 {
1179 return;
1180 }
1181
1182 BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id;
1183 const boost::urls::url certURL = crow::utility::urlFromPieces(
1184 "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id);
1185 std::string objPath =
1186 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1187 getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1188 id, certURL, "TrustStore Certificate");
1189}
1190
1191inline void handleTrustStoreCertificateDelete(
1192 App& app, const crow::Request& req,
1193 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1194{
1195 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1196 {
1197 return;
1198 }
1199
1200 BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id;
1201 std::string objPath =
1202 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1203
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +08001204 deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001205}
1206
1207inline void requestRoutesTrustStoreCertificate(App& app)
Marri Devender Raocfcd5f62019-05-17 08:34:37 -05001208{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001209 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001210 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001211 .methods(boost::beast::http::verb::get)(std::bind_front(
1212 handleTrustStoreCertificateCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001213
1214 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001215 .privileges(redfish::privileges::postCertificateCollection)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001216 .methods(boost::beast::http::verb::post)(std::bind_front(
1217 handleTrustStoreCertificateCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07001218
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001220 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001221 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001222 std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001223
1224 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001225 .privileges(redfish::privileges::deleteCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001226 .methods(boost::beast::http::verb::delete_)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001227 std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001228} // requestRoutesTrustStoreCertificate
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001229} // namespace redfish