blob: cb8979277ece6dece0c2474a85094bd834f19c14 [file] [log] [blame]
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001#pragma once
2
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +02003#include "utils/dbus_utils.hpp"
4
John Edward Broadbent7e860f12021-04-08 15:57:16 -07005#include <app.hpp>
Ed Tanousd9f6c622022-03-17 09:12:17 -07006#include <async_resp.hpp>
Jiaqing Zhao90d2d1e2022-04-13 17:01:57 +08007#include <boost/system/linux_error.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -08008#include <dbus_utility.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
Marri Devender Rao5968cae2019-01-21 10:27:12 -060015namespace redfish
16{
17namespace certs
18{
Gunnar Mills1214b7e2020-06-04 10:11:30 -050019constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
20constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
21constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
22constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
23constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
24constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050025constexpr char const* httpsServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060026 "xyz.openbmc_project.Certs.Manager.Server.Https";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050027constexpr char const* ldapServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060028 "xyz.openbmc_project.Certs.Manager.Client.Ldap";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050029constexpr char const* authorityServiceName =
Marri Devender Raocfcd5f62019-05-17 08:34:37 -050030 "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
Jiaqing Zhaoc6a8dfb2022-06-03 10:44:23 +080031constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
32constexpr char const* httpsObjectPath =
33 "/xyz/openbmc_project/certs/server/https";
34constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035constexpr char const* authorityObjectPath =
Marri Devender Raocfcd5f62019-05-17 08:34:37 -050036 "/xyz/openbmc_project/certs/authority/ldap";
Marri Devender Rao5968cae2019-01-21 10:27:12 -060037} // namespace certs
38
39/**
40 * The Certificate schema defines a Certificate Service which represents the
41 * actions available to manage certificates and links to where certificates
42 * are installed.
43 */
Marri Devender Rao5968cae2019-01-21 10:27:12 -060044
John Edward Broadbent7e860f12021-04-08 15:57:16 -070045// TODO: Issue#61 No entries are available for Certificate
46// service at https://www.dmtf.org/standards/redfish
47// "redfish standard registries". Need to modify after DMTF
48// publish Privilege details for certificate service
49
zhanghch058d1b46d2021-04-01 11:18:24 +080050inline std::string getCertificateFromReqBody(
51 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
52 const crow::Request& req)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020053{
54 nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false);
55
56 if (reqJson.is_discarded())
57 {
58 // We did not receive JSON request, proceed as it is RAW data
59 return req.body;
60 }
61
62 std::string certificate;
63 std::optional<std::string> certificateType = "PEM";
64
Willy Tu15ed6782021-12-14 11:03:16 -080065 if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
66 certificate, "CertificateType",
67 certificateType))
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020068 {
69 BMCWEB_LOG_ERROR << "Required parameters are missing";
70 messages::internalError(asyncResp->res);
Ed Tanousabb93cd2021-09-02 14:34:57 -070071 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020072 }
73
74 if (*certificateType != "PEM")
75 {
76 messages::propertyValueNotInList(asyncResp->res, *certificateType,
77 "CertificateType");
Ed Tanousabb93cd2021-09-02 14:34:57 -070078 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020079 }
80
81 return certificate;
82}
83
Marri Devender Rao5968cae2019-01-21 10:27:12 -060084/**
85 * Class to create a temporary certificate file for uploading to system
86 */
87class CertificateFile
88{
89 public:
90 CertificateFile() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050091 CertificateFile(const CertificateFile&) = delete;
92 CertificateFile& operator=(const CertificateFile&) = delete;
93 CertificateFile(CertificateFile&&) = delete;
94 CertificateFile& operator=(CertificateFile&&) = delete;
Ed Tanous4e23a442022-06-06 09:57:26 -070095 explicit CertificateFile(const std::string& certString)
Marri Devender Rao5968cae2019-01-21 10:27:12 -060096 {
Ed Tanous72d52d22020-10-12 07:46:27 -070097 std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
Ed Tanous52074382020-09-28 19:16:18 -070098 'e', 'r', 't', 's', '.', 'X',
99 'X', 'X', 'X', 'X', 'X', '\0'};
100 char* tempDirectory = mkdtemp(dirTemplate.data());
Ed Tanouse662eae2022-01-25 10:39:19 -0800101 if (tempDirectory != nullptr)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600102 {
103 certDirectory = tempDirectory;
104 certificateFile = certDirectory / "cert.pem";
105 std::ofstream out(certificateFile, std::ofstream::out |
106 std::ofstream::binary |
107 std::ofstream::trunc);
108 out << certString;
109 out.close();
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800110 BMCWEB_LOG_DEBUG << "Creating certificate file"
111 << certificateFile.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600112 }
113 }
114 ~CertificateFile()
115 {
116 if (std::filesystem::exists(certDirectory))
117 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800118 BMCWEB_LOG_DEBUG << "Removing certificate file"
119 << certificateFile.string();
Ed Tanous23a21a12020-07-25 04:45:05 +0000120 std::error_code ec;
121 std::filesystem::remove_all(certDirectory, ec);
122 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600123 {
124 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800125 << certDirectory.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600126 }
127 }
128 }
129 std::string getCertFilePath()
130 {
131 return certificateFile;
132 }
133
134 private:
135 std::filesystem::path certificateFile;
136 std::filesystem::path certDirectory;
137};
138
139/**
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500140 * @brief Parse and update Certificate Issue/Subject property
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600141 *
142 * @param[in] asyncResp Shared pointer to the response message
143 * @param[in] str Issuer/Subject value in key=value pairs
144 * @param[in] type Issuer/Subject
145 * @return None
146 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500147static void updateCertIssuerOrSubject(nlohmann::json& out,
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600148 const std::string_view value)
149{
150 // example: O=openbmc-project.xyz,CN=localhost
151 std::string_view::iterator i = value.begin();
152 while (i != value.end())
153 {
154 std::string_view::iterator tokenBegin = i;
155 while (i != value.end() && *i != '=')
156 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530157 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600158 }
159 if (i == value.end())
160 {
161 break;
162 }
Ed Tanous271584a2019-07-09 16:24:22 -0700163 const std::string_view key(tokenBegin,
164 static_cast<size_t>(i - tokenBegin));
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530165 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600166 tokenBegin = i;
167 while (i != value.end() && *i != ',')
168 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530169 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600170 }
Ed Tanous271584a2019-07-09 16:24:22 -0700171 const std::string_view val(tokenBegin,
172 static_cast<size_t>(i - tokenBegin));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600173 if (key == "L")
174 {
175 out["City"] = val;
176 }
177 else if (key == "CN")
178 {
179 out["CommonName"] = val;
180 }
181 else if (key == "C")
182 {
183 out["Country"] = val;
184 }
185 else if (key == "O")
186 {
187 out["Organization"] = val;
188 }
189 else if (key == "OU")
190 {
191 out["OrganizationalUnit"] = val;
192 }
193 else if (key == "ST")
194 {
195 out["State"] = val;
196 }
197 // skip comma character
198 if (i != value.end())
199 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530200 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600201 }
202 }
203}
204
205/**
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800206 * @brief Retrieve the installed certificate list
207 *
208 * @param[in] asyncResp Shared pointer to the response message
209 * @param[in] basePath DBus object path to search
210 * @param[in] listPtr Json pointer to the list in asyncResp
211 * @param[in] countPtr Json pointer to the count in asyncResp
212 * @return None
213 */
214static void
215 getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
216 const std::string& basePath,
217 const nlohmann::json::json_pointer& listPtr,
218 const nlohmann::json::json_pointer& countPtr)
219{
220 crow::connections::systemBus->async_method_call(
221 [asyncResp, listPtr, countPtr](
222 const boost::system::error_code ec,
223 const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
224 if (ec)
225 {
226 BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
227 messages::internalError(asyncResp->res);
228 return;
229 }
230
231 nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
232 links = nlohmann::json::array();
233 for (const auto& certPath : certPaths)
234 {
235 sdbusplus::message::object_path objPath(certPath);
236 std::string certId = objPath.filename();
237 if (certId.empty())
238 {
239 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
240 continue;
241 }
242
243 boost::urls::url certURL;
244 if (objPath.parent_path() == certs::httpsObjectPath)
245 {
246 certURL = crow::utility::urlFromPieces(
247 "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
248 "HTTPS", "Certificates", certId);
249 }
250 else if (objPath.parent_path() == certs::ldapObjectPath)
251 {
252 certURL = crow::utility::urlFromPieces("redfish", "v1",
253 "AccountService", "LDAP",
254 "Certificates", certId);
255 }
256 else if (objPath.parent_path() == certs::authorityObjectPath)
257 {
258 certURL = crow::utility::urlFromPieces(
259 "redfish", "v1", "Managers", "bmc", "Truststore",
260 "Certificates", certId);
261 }
262 else
263 {
264 continue;
265 }
266
267 nlohmann::json::object_t link;
268 link["@odata.id"] = certURL;
269 links.emplace_back(std::move(link));
270 }
271
272 asyncResp->res.jsonValue[countPtr] = links.size();
273 },
274 "xyz.openbmc_project.ObjectMapper",
275 "/xyz/openbmc_project/object_mapper",
276 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", basePath, 0,
277 std::array<const char*, 1>{certs::certPropIntf});
278}
279
280/**
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600281 * @brief Retrieve the certificates properties and append to the response
282 * message
283 *
284 * @param[in] asyncResp Shared pointer to the response message
285 * @param[in] objectPath Path of the D-Bus service object
286 * @param[in] certId Id of the certificate
287 * @param[in] certURL URL of the certificate object
288 * @param[in] name name of the certificate
289 * @return None
290 */
291static void getCertificateProperties(
zhanghch058d1b46d2021-04-01 11:18:24 +0800292 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800293 const std::string& objectPath, const std::string& service,
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800294 const std::string& certId, const boost::urls::url& certURL,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800295 const std::string& name)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600296{
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600297 BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
298 << " certId=" << certId << " certURl=" << certURL;
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200299 sdbusplus::asio::getAllProperties(
300 *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800301 [asyncResp, certURL, certId,
302 name](const boost::system::error_code ec,
303 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700304 if (ec)
305 {
306 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800307 messages::resourceNotFound(asyncResp->res, "Certificate", certId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700308 return;
309 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200310
311 const std::string* certificateString = nullptr;
312 const std::vector<std::string>* keyUsage = nullptr;
313 const std::string* issuer = nullptr;
314 const std::string* subject = nullptr;
315 const uint64_t* validNotAfter = nullptr;
316 const uint64_t* validNotBefore = nullptr;
317
318 const bool success = sdbusplus::unpackPropertiesNoThrow(
319 dbus_utils::UnpackErrorPrinter(), properties, "CertificateString",
320 certificateString, "KeyUsage", keyUsage, "Issuer", issuer,
321 "Subject", subject, "ValidNotAfter", validNotAfter,
322 "ValidNotBefore", validNotBefore);
323
324 if (!success)
325 {
326 messages::internalError(asyncResp->res);
327 return;
328 }
329
Ed Tanous002d39b2022-05-31 08:59:27 -0700330 asyncResp->res.jsonValue["@odata.id"] = certURL;
331 asyncResp->res.jsonValue["@odata.type"] =
332 "#Certificate.v1_0_0.Certificate";
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800333 asyncResp->res.jsonValue["Id"] = certId;
Ed Tanous002d39b2022-05-31 08:59:27 -0700334 asyncResp->res.jsonValue["Name"] = name;
335 asyncResp->res.jsonValue["Description"] = name;
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200336 asyncResp->res.jsonValue["CertificateString"] = "";
337 asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
338
339 if (certificateString != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 {
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200341 asyncResp->res.jsonValue["CertificateString"] = *certificateString;
Ed Tanous002d39b2022-05-31 08:59:27 -0700342 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200343
344 if (keyUsage != nullptr)
345 {
346 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
347 }
348
349 if (issuer != nullptr)
350 {
351 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
352 *issuer);
353 }
354
355 if (subject != nullptr)
356 {
357 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
358 *subject);
359 }
360
361 if (validNotAfter != nullptr)
362 {
363 asyncResp->res.jsonValue["ValidNotAfter"] =
364 redfish::time_utils::getDateTimeUint(*validNotAfter);
365 }
366
367 if (validNotBefore != nullptr)
368 {
369 asyncResp->res.jsonValue["ValidNotBefore"] =
370 redfish::time_utils::getDateTimeUint(*validNotBefore);
371 }
372
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800373 asyncResp->res.addHeader(
Ed Tanousd9f6c622022-03-17 09:12:17 -0700374 boost::beast::http::field::location,
375 std::string_view(certURL.data(), certURL.size()));
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200376 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600377}
378
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800379static void
380 deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
381 const std::string& service,
382 const sdbusplus::message::object_path& objectPath)
383{
384 crow::connections::systemBus->async_method_call(
385 [asyncResp,
386 id{objectPath.filename()}](const boost::system::error_code ec) {
387 if (ec)
388 {
389 messages::resourceNotFound(asyncResp->res, "Certificate", id);
390 return;
391 }
392 BMCWEB_LOG_INFO << "Certificate deleted";
393 asyncResp->res.result(boost::beast::http::status::no_content);
394 },
395 service, objectPath, certs::objDeleteIntf, "Delete");
396}
397
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800398inline void handleCertificateServiceGet(
399 App& app, const crow::Request& req,
400 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600401{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800402 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
403 {
404 return;
405 }
406
407 asyncResp->res.jsonValue["@odata.type"] =
408 "#CertificateService.v1_0_0.CertificateService";
409 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
410 asyncResp->res.jsonValue["Id"] = "CertificateService";
411 asyncResp->res.jsonValue["Name"] = "Certificate Service";
412 asyncResp->res.jsonValue["Description"] =
413 "Actions available to manage certificates";
414 // /redfish/v1/CertificateService/CertificateLocations is something
415 // only ConfigureManager can access then only display when the user
416 // has permissions ConfigureManager
417 Privileges effectiveUserPrivileges =
418 redfish::getUserPrivileges(req.userRole);
419 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
420 effectiveUserPrivileges))
421 {
422 asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
423 "/redfish/v1/CertificateService/CertificateLocations";
424 }
425 nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
426 nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
427 replace["target"] =
428 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
429 nlohmann::json::array_t allowed;
430 allowed.push_back("PEM");
431 replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
432 actions["#CertificateService.GenerateCSR"]["target"] =
433 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
434}
435
436inline void handleCertificateLocationsGet(
437 App& app, const crow::Request& req,
438 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
439{
440 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
441 {
442 return;
443 }
444 asyncResp->res.jsonValue["@odata.id"] =
445 "/redfish/v1/CertificateService/CertificateLocations";
446 asyncResp->res.jsonValue["@odata.type"] =
447 "#CertificateLocations.v1_0_0.CertificateLocations";
448 asyncResp->res.jsonValue["Name"] = "Certificate Locations";
449 asyncResp->res.jsonValue["Id"] = "CertificateLocations";
450 asyncResp->res.jsonValue["Description"] =
451 "Defines a resource that an administrator can use in order to "
452 "locate all certificates installed on a given service";
453
454 getCertificateList(asyncResp, certs::baseObjectPath,
455 "/Links/Certificates"_json_pointer,
456 "/Links/Certificates@odata.count"_json_pointer);
457}
458
459inline void handleReplaceCertificateAction(
460 App& app, const crow::Request& req,
461 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
462{
463 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
464 {
465 return;
466 }
467 std::string certificate;
468 nlohmann::json certificateUri;
469 std::optional<std::string> certificateType = "PEM";
470
471 if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
472 certificate, "CertificateUri",
473 certificateUri, "CertificateType",
474 certificateType))
475 {
476 BMCWEB_LOG_ERROR << "Required parameters are missing";
477 messages::internalError(asyncResp->res);
478 return;
479 }
480
481 if (!certificateType)
482 {
483 // should never happen, but it never hurts to be paranoid.
484 return;
485 }
486 if (certificateType != "PEM")
487 {
488 messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
489 "ReplaceCertificate");
490 return;
491 }
492
493 std::string certURI;
494 if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
495 "@odata.id", certURI))
496 {
497 messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
498 "CertificateUri");
499 return;
500 }
501 BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI;
502
503 boost::urls::result<boost::urls::url_view> parsedUrl =
504 boost::urls::parse_relative_ref(certURI);
505 if (!parsedUrl)
506 {
507 messages::actionParameterValueFormatError(
508 asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
509 return;
510 }
511
512 std::string id;
513 sdbusplus::message::object_path objectPath;
514 std::string name;
515 std::string service;
516 if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
517 "bmc", "NetworkProtocol", "HTTPS",
518 "Certificates", std::ref(id)))
519 {
520 objectPath =
521 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
522 name = "HTTPS certificate";
523 service = certs::httpsServiceName;
524 }
525 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
526 "AccountService", "LDAP",
527 "Certificates", std::ref(id)))
528 {
529 objectPath =
530 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
531 name = "LDAP certificate";
532 service = certs::ldapServiceName;
533 }
534 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
535 "Managers", "bmc", "Truststore",
536 "Certificates", std::ref(id)))
537 {
538 objectPath =
539 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
540 name = "TrustStore certificate";
541 service = certs::authorityServiceName;
542 }
543 else
544 {
545 messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
546 "ReplaceCertificate");
547 return;
548 }
549
550 std::shared_ptr<CertificateFile> certFile =
551 std::make_shared<CertificateFile>(certificate);
552 crow::connections::systemBus->async_method_call(
553 [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
554 name](const boost::system::error_code ec) {
555 if (ec)
556 {
557 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
558 if (ec.value() ==
559 boost::system::linux_error::bad_request_descriptor)
560 {
561 messages::resourceNotFound(asyncResp->res, "Certificate", id);
562 return;
563 }
564 messages::internalError(asyncResp->res);
565 return;
566 }
567 getCertificateProperties(asyncResp, objectPath, service, id, url, name);
568 BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
569 << certFile->getCertFilePath();
570 },
571 service, objectPath, certs::certReplaceIntf, "Replace",
572 certFile->getCertFilePath());
573}
574
575static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
576/**
577 * @brief Read data from CSR D-bus object and set to response
578 *
579 * @param[in] asyncResp Shared pointer to the response message
580 * @param[in] certURI Link to certifiate collection URI
581 * @param[in] service D-Bus service name
582 * @param[in] certObjPath certificate D-Bus object path
583 * @param[in] csrObjPath CSR D-Bus object path
584 * @return None
585 */
586static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
587 const std::string& certURI, const std::string& service,
588 const std::string& certObjPath,
589 const std::string& csrObjPath)
590{
591 BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
592 << " CSRObjectPath=" << csrObjPath
593 << " service=" << service;
594 crow::connections::systemBus->async_method_call(
595 [asyncResp, certURI](const boost::system::error_code ec,
596 const std::string& csr) {
597 if (ec)
598 {
599 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
600 messages::internalError(asyncResp->res);
601 return;
602 }
603 if (csr.empty())
604 {
605 BMCWEB_LOG_ERROR << "CSR read is empty";
606 messages::internalError(asyncResp->res);
607 return;
608 }
609 asyncResp->res.jsonValue["CSRString"] = csr;
610 asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
611 certURI;
612 },
613 service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
614}
615
616inline void
617 handleGenerateCSRAction(App& app, const crow::Request& req,
618 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
619{
620 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
621 {
622 return;
623 }
624 static const int rsaKeyBitLength = 2048;
625
626 // Required parameters
627 std::string city;
628 std::string commonName;
629 std::string country;
630 std::string organization;
631 std::string organizationalUnit;
632 std::string state;
633 nlohmann::json certificateCollection;
634
635 // Optional parameters
636 std::optional<std::vector<std::string>> optAlternativeNames =
637 std::vector<std::string>();
638 std::optional<std::string> optContactPerson = "";
639 std::optional<std::string> optChallengePassword = "";
640 std::optional<std::string> optEmail = "";
641 std::optional<std::string> optGivenName = "";
642 std::optional<std::string> optInitials = "";
643 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
644 std::optional<std::string> optKeyCurveId = "secp384r1";
645 std::optional<std::string> optKeyPairAlgorithm = "EC";
646 std::optional<std::vector<std::string>> optKeyUsage =
647 std::vector<std::string>();
648 std::optional<std::string> optSurname = "";
649 std::optional<std::string> optUnstructuredName = "";
650 if (!json_util::readJsonAction(
651 req, asyncResp->res, "City", city, "CommonName", commonName,
652 "ContactPerson", optContactPerson, "Country", country,
653 "Organization", organization, "OrganizationalUnit",
654 organizationalUnit, "State", state, "CertificateCollection",
655 certificateCollection, "AlternativeNames", optAlternativeNames,
656 "ChallengePassword", optChallengePassword, "Email", optEmail,
657 "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
658 optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
659 optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
660 "UnstructuredName", optUnstructuredName))
661 {
662 return;
663 }
664
665 // bmcweb has no way to store or decode a private key challenge
666 // password, which will likely cause bmcweb to crash on startup
667 // if this is not set on a post so not allowing the user to set
668 // value
669 if (!optChallengePassword->empty())
670 {
671 messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
672 "ChallengePassword");
673 return;
674 }
675
676 std::string certURI;
677 if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
678 "@odata.id", certURI))
679 {
680 return;
681 }
682
683 std::string objectPath;
684 std::string service;
685 if (certURI.starts_with(
686 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
687 {
688 objectPath = certs::httpsObjectPath;
689 service = certs::httpsServiceName;
690 }
691 else if (certURI.starts_with(
692 "/redfish/v1/AccountService/LDAP/Certificates"))
693 {
694 objectPath = certs::ldapObjectPath;
695 service = certs::ldapServiceName;
696 }
697 else
698 {
699 messages::actionParameterNotSupported(
700 asyncResp->res, "CertificateCollection", "GenerateCSR");
701 return;
702 }
703
704 // supporting only EC and RSA algorithm
705 if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
706 {
707 messages::actionParameterNotSupported(
708 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
709 return;
710 }
711
712 // supporting only 2048 key bit length for RSA algorithm due to
713 // time consumed in generating private key
714 if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
715 {
716 messages::propertyValueNotInList(
717 asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength");
718 return;
719 }
720
721 // validate KeyUsage supporting only 1 type based on URL
722 if (certURI.starts_with(
723 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
724 {
725 if (optKeyUsage->empty())
726 {
727 optKeyUsage->push_back("ServerAuthentication");
728 }
729 else if (optKeyUsage->size() == 1)
730 {
731 if ((*optKeyUsage)[0] != "ServerAuthentication")
732 {
733 messages::propertyValueNotInList(asyncResp->res,
734 (*optKeyUsage)[0], "KeyUsage");
735 return;
736 }
737 }
738 else
739 {
740 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
741 "GenerateCSR");
742 return;
743 }
744 }
745 else if (certURI.starts_with(
746 "/redfish/v1/AccountService/LDAP/Certificates"))
747 {
748 if (optKeyUsage->empty())
749 {
750 optKeyUsage->push_back("ClientAuthentication");
751 }
752 else if (optKeyUsage->size() == 1)
753 {
754 if ((*optKeyUsage)[0] != "ClientAuthentication")
755 {
756 messages::propertyValueNotInList(asyncResp->res,
757 (*optKeyUsage)[0], "KeyUsage");
758 return;
759 }
760 }
761 else
762 {
763 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
764 "GenerateCSR");
765 return;
766 }
767 }
768
769 // Only allow one CSR matcher at a time so setting retry
770 // time-out and timer expiry to 10 seconds for now.
771 static const int timeOut = 10;
772 if (csrMatcher)
773 {
774 messages::serviceTemporarilyUnavailable(asyncResp->res,
775 std::to_string(timeOut));
776 return;
777 }
778
779 // Make this static so it survives outside this method
780 static boost::asio::steady_timer timeout(*req.ioService);
781 timeout.expires_after(std::chrono::seconds(timeOut));
782 timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
783 csrMatcher = nullptr;
784 if (ec)
785 {
786 // operation_aborted is expected if timer is canceled
787 // before completion.
788 if (ec != boost::asio::error::operation_aborted)
789 {
790 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
791 }
792 return;
793 }
794 BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
795 messages::internalError(asyncResp->res);
796 });
797
798 // create a matcher to wait on CSR object
799 BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
800 std::string match("type='signal',"
801 "interface='org.freedesktop.DBus.ObjectManager',"
802 "path='" +
803 objectPath +
804 "',"
805 "member='InterfacesAdded'");
806 csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
807 *crow::connections::systemBus, match,
808 [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
809 timeout.cancel();
810 if (m.is_method_error())
811 {
812 BMCWEB_LOG_ERROR << "Dbus method error!!!";
813 messages::internalError(asyncResp->res);
814 return;
815 }
816
817 dbus::utility::DBusInteracesMap interfacesProperties;
818
819 sdbusplus::message::object_path csrObjectPath;
820 m.read(csrObjectPath, interfacesProperties);
821 BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
822 for (const auto& interface : interfacesProperties)
823 {
824 if (interface.first == "xyz.openbmc_project.Certs.CSR")
825 {
826 getCSR(asyncResp, certURI, service, objectPath,
827 csrObjectPath.str);
828 break;
829 }
830 }
831 });
832 crow::connections::systemBus->async_method_call(
833 [asyncResp](const boost::system::error_code ec, const std::string&) {
834 if (ec)
835 {
836 BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
837 messages::internalError(asyncResp->res);
838 return;
839 }
840 },
841 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
842 "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
843 commonName, *optContactPerson, country, *optEmail, *optGivenName,
844 *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
845 *optKeyUsage, organization, organizationalUnit, state, *optSurname,
846 *optUnstructuredName);
847}
848
849inline void requestRoutesCertificateService(App& app)
850{
851 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
852 .privileges(redfish::privileges::getCertificateService)
853 .methods(boost::beast::http::verb::get)(
854 std::bind_front(handleCertificateServiceGet, std::ref(app)));
855
856 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
857 .privileges(redfish::privileges::getCertificateLocations)
858 .methods(boost::beast::http::verb::get)(
859 std::bind_front(handleCertificateLocationsGet, std::ref(app)));
860
George Liu0fda0f12021-11-16 10:06:17 +0800861 BMCWEB_ROUTE(
862 app,
863 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
Ed Tanoused398212021-06-09 17:05:54 -0700864 .privileges(redfish::privileges::postCertificateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700865 .methods(boost::beast::http::verb::post)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800866 std::bind_front(handleReplaceCertificateAction, std::ref(app)));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600867
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800868 BMCWEB_ROUTE(
869 app,
870 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
871 .privileges(redfish::privileges::postCertificateService)
872 .methods(boost::beast::http::verb::post)(
873 std::bind_front(handleGenerateCSRAction, std::ref(app)));
874} // requestRoutesCertificateService
875
876inline void handleHTTPSCertificateCollectionGet(
877 App& app, const crow::Request& req,
878 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
879{
880 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
881 {
882 return;
883 }
884
885 asyncResp->res.jsonValue["@odata.id"] =
886 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
887 asyncResp->res.jsonValue["@odata.type"] =
888 "#CertificateCollection.CertificateCollection";
889 asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
890 asyncResp->res.jsonValue["Description"] =
891 "A Collection of HTTPS certificate instances";
892
893 getCertificateList(asyncResp, certs::httpsObjectPath,
894 "/Members"_json_pointer,
895 "/Members@odata.count"_json_pointer);
896}
897
898inline void handleHTTPSCertificateCollectionPost(
899 App& app, const crow::Request& req,
900 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
901{
902 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
903 {
904 return;
905 }
906 BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
907
908 asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
909 asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
910
911 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
912
913 if (certFileBody.empty())
914 {
915 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
916 messages::unrecognizedRequestBody(asyncResp->res);
917 return;
918 }
919
920 std::shared_ptr<CertificateFile> certFile =
921 std::make_shared<CertificateFile>(certFileBody);
922
923 crow::connections::systemBus->async_method_call(
924 [asyncResp, certFile](const boost::system::error_code ec,
925 const std::string& objectPath) {
926 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700927 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800928 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
Ed Tanous002d39b2022-05-31 08:59:27 -0700929 messages::internalError(asyncResp->res);
930 return;
931 }
932
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800933 sdbusplus::message::object_path path(objectPath);
934 std::string certId = path.filename();
935 const boost::urls::url certURL = crow::utility::urlFromPieces(
936 "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
937 "Certificates", certId);
938 getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
939 certId, certURL, "HTTPS Certificate");
940 BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
941 << certFile->getCertFilePath();
942 },
943 certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
944 "Install", certFile->getCertFilePath());
945}
Ed Tanous002d39b2022-05-31 08:59:27 -0700946
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800947inline void handleHTTPSCertificateGet(
948 App& app, const crow::Request& req,
949 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
950{
951 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
952 {
953 return;
954 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700955
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800956 BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id;
957 const boost::urls::url certURL = crow::utility::urlFromPieces(
958 "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
959 "Certificates", id);
960 std::string objPath =
961 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
962 getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
963 certURL, "HTTPS Certificate");
964}
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700965
966inline void requestRoutesHTTPSCertificate(App& app)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600967{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800968 BMCWEB_ROUTE(app,
969 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
970 .privileges(redfish::privileges::getCertificateCollection)
971 .methods(boost::beast::http::verb::get)(std::bind_front(
972 handleHTTPSCertificateCollectionGet, std::ref(app)));
973
974 BMCWEB_ROUTE(app,
975 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
976 .privileges(redfish::privileges::postCertificateCollection)
977 .methods(boost::beast::http::verb::post)(std::bind_front(
978 handleHTTPSCertificateCollectionPost, std::ref(app)));
979
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700980 BMCWEB_ROUTE(
981 app,
982 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700983 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800984 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800985 std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700986}
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600987
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800988inline void handleLDAPCertificateCollectionGet(
989 App& app, const crow::Request& req,
990 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600991{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800992 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
993 {
994 return;
995 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700996
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800997 asyncResp->res.jsonValue["@odata.id"] =
998 "/redfish/v1/AccountService/LDAP/Certificates";
999 asyncResp->res.jsonValue["@odata.type"] =
1000 "#CertificateCollection.CertificateCollection";
1001 asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
1002 asyncResp->res.jsonValue["Description"] =
1003 "A Collection of LDAP certificate instances";
Ed Tanous002d39b2022-05-31 08:59:27 -07001004
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001005 getCertificateList(asyncResp, certs::ldapObjectPath,
1006 "/Members"_json_pointer,
1007 "/Members@odata.count"_json_pointer);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001008}
Marri Devender Rao37cce912019-02-20 01:05:22 -06001009
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001010inline void handleLDAPCertificateCollectionPost(
1011 App& app, const crow::Request& req,
1012 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001013{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001014 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1015 {
1016 return;
1017 }
1018 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1019
1020 if (certFileBody.empty())
1021 {
1022 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1023 messages::unrecognizedRequestBody(asyncResp->res);
1024 return;
1025 }
1026
1027 std::shared_ptr<CertificateFile> certFile =
1028 std::make_shared<CertificateFile>(certFileBody);
1029
1030 crow::connections::systemBus->async_method_call(
1031 [asyncResp, certFile](const boost::system::error_code ec,
1032 const std::string& objectPath) {
1033 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001034 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001035 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1036 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001037 return;
1038 }
1039
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001040 sdbusplus::message::object_path path(objectPath);
1041 std::string certId = path.filename();
1042 const boost::urls::url certURL = crow::utility::urlFromPieces(
1043 "redfish", "v1", "AccountService", "LDAP", "Certificates", certId);
1044 getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1045 certId, certURL, "LDAP Certificate");
1046 BMCWEB_LOG_DEBUG << "LDAP certificate install file="
1047 << certFile->getCertFilePath();
1048 },
1049 certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1050 "Install", certFile->getCertFilePath());
1051}
Ed Tanous002d39b2022-05-31 08:59:27 -07001052
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001053inline void handleLDAPCertificateGet(
1054 App& app, const crow::Request& req,
1055 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1056{
1057 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1058 {
1059 return;
1060 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001061
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001062 BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id;
1063 const boost::urls::url certURL = crow::utility::urlFromPieces(
1064 "redfish", "v1", "AccountService", "LDAP", "Certificates", id);
1065 std::string objPath =
1066 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1067 getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1068 certURL, "LDAP Certificate");
1069}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001070
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001071inline void requestRoutesLDAPCertificate(App& app)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001072{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001073 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1074 .privileges(redfish::privileges::getCertificateCollection)
1075 .methods(boost::beast::http::verb::get)(
1076 std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1077
1078 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1079 .privileges(redfish::privileges::postCertificateCollection)
1080 .methods(boost::beast::http::verb::post)(std::bind_front(
1081 handleLDAPCertificateCollectionPost, std::ref(app)));
1082
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001083 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001084 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001085 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001086 std::bind_front(handleLDAPCertificateGet, std::ref(app)));
1087} // requestRoutesLDAPCertificate
1088
1089inline void handleTrustStoreCertificateCollectionGet(
1090 App& app, const crow::Request& req,
1091 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1092{
1093 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1094 {
1095 return;
1096 }
1097
1098 asyncResp->res.jsonValue["@odata.id"] =
1099 "/redfish/v1/Managers/bmc/Truststore/Certificates/";
1100 asyncResp->res.jsonValue["@odata.type"] =
1101 "#CertificateCollection.CertificateCollection";
1102 asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
1103 asyncResp->res.jsonValue["Description"] =
1104 "A Collection of TrustStore certificate instances";
1105
1106 getCertificateList(asyncResp, certs::authorityObjectPath,
1107 "/Members"_json_pointer,
1108 "/Members@odata.count"_json_pointer);
1109}
1110
1111inline void handleTrustStoreCertificateCollectionPost(
1112 App& app, const crow::Request& req,
1113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1114{
1115 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1116 {
1117 return;
1118 }
1119 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1120
1121 if (certFileBody.empty())
1122 {
1123 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1124 messages::unrecognizedRequestBody(asyncResp->res);
1125 return;
1126 }
1127
1128 std::shared_ptr<CertificateFile> certFile =
1129 std::make_shared<CertificateFile>(certFileBody);
1130 crow::connections::systemBus->async_method_call(
1131 [asyncResp, certFile](const boost::system::error_code ec,
1132 const std::string& objectPath) {
1133 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001134 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001135 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1136 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001137 return;
1138 }
Jiaqing Zhao717b9802022-06-06 20:24:04 +08001139
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001140 sdbusplus::message::object_path path(objectPath);
1141 std::string certId = path.filename();
1142 const boost::urls::url certURL =
1143 crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1144 "Truststore", "Certificates", certId);
1145 getCertificateProperties(asyncResp, objectPath,
1146 certs::authorityServiceName, certId, certURL,
1147 "TrustStore Certificate");
1148 BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1149 << certFile->getCertFilePath();
1150 },
1151 certs::authorityServiceName, certs::authorityObjectPath,
1152 certs::certInstallIntf, "Install", certFile->getCertFilePath());
1153}
1154
1155inline void handleTrustStoreCertificateGet(
1156 App& app, const crow::Request& req,
1157 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1158{
1159 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1160 {
1161 return;
1162 }
1163
1164 BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id;
1165 const boost::urls::url certURL = crow::utility::urlFromPieces(
1166 "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id);
1167 std::string objPath =
1168 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1169 getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1170 id, certURL, "TrustStore Certificate");
1171}
1172
1173inline void handleTrustStoreCertificateDelete(
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 << "Delete TrustStore Certificate ID=" << id;
1183 std::string objPath =
1184 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1185
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +08001186 deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001187}
1188
1189inline void requestRoutesTrustStoreCertificate(App& app)
Marri Devender Raocfcd5f62019-05-17 08:34:37 -05001190{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001191 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001192 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001193 .methods(boost::beast::http::verb::get)(std::bind_front(
1194 handleTrustStoreCertificateCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001195
1196 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001197 .privileges(redfish::privileges::postCertificateCollection)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001198 .methods(boost::beast::http::verb::post)(std::bind_front(
1199 handleTrustStoreCertificateCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07001200
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001201 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001202 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001203 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001204 std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001205
1206 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001207 .privileges(redfish::privileges::deleteCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001208 .methods(boost::beast::http::verb::delete_)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001209 std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001210} // requestRoutesTrustStoreCertificate
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001211} // namespace redfish