blob: 16f26e37b29d80d1ee88eb04302c8891b626828a [file] [log] [blame]
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001#pragma once
2
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08003#include "app.hpp"
4#include "async_resp.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +08005#include "dbus_utility.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01006#include "http/parsing.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08007#include "http_response.hpp"
8#include "query.hpp"
9#include "registries/privilege_registry.hpp"
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020010#include "utils/dbus_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011#include "utils/json_utils.hpp"
12#include "utils/time_utils.hpp"
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020013
Jiaqing Zhao90d2d1e2022-04-13 17:01:57 +080014#include <boost/system/linux_error.hpp>
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020015#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080016#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020017#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050018
George Liu7a1dbc42022-12-07 16:03:22 +080019#include <array>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include <memory>
George Liu7a1dbc42022-12-07 16:03:22 +080021#include <string_view>
22
Marri Devender Rao5968cae2019-01-21 10:27:12 -060023namespace redfish
24{
25namespace certs
26{
Gunnar Mills1214b7e2020-06-04 10:11:30 -050027constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install";
28constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
29constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
30constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
31constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties";
32constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050033constexpr char const* httpsServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060034 "xyz.openbmc_project.Certs.Manager.Server.Https";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035constexpr char const* ldapServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060036 "xyz.openbmc_project.Certs.Manager.Client.Ldap";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050037constexpr char const* authorityServiceName =
Marri Devender Raocfcd5f62019-05-17 08:34:37 -050038 "xyz.openbmc_project.Certs.Manager.Authority.Ldap";
Jiaqing Zhaoc6a8dfb2022-06-03 10:44:23 +080039constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs";
40constexpr char const* httpsObjectPath =
41 "/xyz/openbmc_project/certs/server/https";
42constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050043constexpr char const* authorityObjectPath =
Marri Devender Raocfcd5f62019-05-17 08:34:37 -050044 "/xyz/openbmc_project/certs/authority/ldap";
Marri Devender Rao5968cae2019-01-21 10:27:12 -060045} // namespace certs
46
47/**
48 * The Certificate schema defines a Certificate Service which represents the
49 * actions available to manage certificates and links to where certificates
50 * are installed.
51 */
Marri Devender Rao5968cae2019-01-21 10:27:12 -060052
zhanghch058d1b46d2021-04-01 11:18:24 +080053inline std::string getCertificateFromReqBody(
54 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
55 const crow::Request& req)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020056{
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010057 nlohmann::json reqJson;
58 JsonParseResult ret = parseRequestAsJson(req, reqJson);
59 if (ret != JsonParseResult::Success)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020060 {
61 // We did not receive JSON request, proceed as it is RAW data
62 return req.body;
63 }
64
65 std::string certificate;
66 std::optional<std::string> certificateType = "PEM";
67
Willy Tu15ed6782021-12-14 11:03:16 -080068 if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
69 certificate, "CertificateType",
70 certificateType))
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020071 {
72 BMCWEB_LOG_ERROR << "Required parameters are missing";
73 messages::internalError(asyncResp->res);
Ed Tanousabb93cd2021-09-02 14:34:57 -070074 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020075 }
76
77 if (*certificateType != "PEM")
78 {
79 messages::propertyValueNotInList(asyncResp->res, *certificateType,
80 "CertificateType");
Ed Tanousabb93cd2021-09-02 14:34:57 -070081 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020082 }
83
84 return certificate;
85}
86
Marri Devender Rao5968cae2019-01-21 10:27:12 -060087/**
88 * Class to create a temporary certificate file for uploading to system
89 */
90class CertificateFile
91{
92 public:
93 CertificateFile() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050094 CertificateFile(const CertificateFile&) = delete;
95 CertificateFile& operator=(const CertificateFile&) = delete;
96 CertificateFile(CertificateFile&&) = delete;
97 CertificateFile& operator=(CertificateFile&&) = delete;
Ed Tanous4e23a442022-06-06 09:57:26 -070098 explicit CertificateFile(const std::string& certString)
Marri Devender Rao5968cae2019-01-21 10:27:12 -060099 {
Ed Tanous72d52d22020-10-12 07:46:27 -0700100 std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
Ed Tanous52074382020-09-28 19:16:18 -0700101 'e', 'r', 't', 's', '.', 'X',
102 'X', 'X', 'X', 'X', 'X', '\0'};
103 char* tempDirectory = mkdtemp(dirTemplate.data());
Ed Tanouse662eae2022-01-25 10:39:19 -0800104 if (tempDirectory != nullptr)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600105 {
106 certDirectory = tempDirectory;
107 certificateFile = certDirectory / "cert.pem";
108 std::ofstream out(certificateFile, std::ofstream::out |
109 std::ofstream::binary |
110 std::ofstream::trunc);
111 out << certString;
112 out.close();
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800113 BMCWEB_LOG_DEBUG << "Creating certificate file"
114 << certificateFile.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600115 }
116 }
117 ~CertificateFile()
118 {
119 if (std::filesystem::exists(certDirectory))
120 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800121 BMCWEB_LOG_DEBUG << "Removing certificate file"
122 << certificateFile.string();
Ed Tanous23a21a12020-07-25 04:45:05 +0000123 std::error_code ec;
124 std::filesystem::remove_all(certDirectory, ec);
125 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600126 {
127 BMCWEB_LOG_ERROR << "Failed to remove temp directory"
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800128 << certDirectory.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600129 }
130 }
131 }
132 std::string getCertFilePath()
133 {
134 return certificateFile;
135 }
136
137 private:
138 std::filesystem::path certificateFile;
139 std::filesystem::path certDirectory;
140};
141
142/**
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500143 * @brief Parse and update Certificate Issue/Subject property
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600144 *
145 * @param[in] asyncResp Shared pointer to the response message
146 * @param[in] str Issuer/Subject value in key=value pairs
147 * @param[in] type Issuer/Subject
148 * @return None
149 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500150static void updateCertIssuerOrSubject(nlohmann::json& out,
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600151 const std::string_view value)
152{
153 // example: O=openbmc-project.xyz,CN=localhost
154 std::string_view::iterator i = value.begin();
155 while (i != value.end())
156 {
157 std::string_view::iterator tokenBegin = i;
158 while (i != value.end() && *i != '=')
159 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530160 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600161 }
162 if (i == value.end())
163 {
164 break;
165 }
Ed Tanous271584a2019-07-09 16:24:22 -0700166 const std::string_view key(tokenBegin,
167 static_cast<size_t>(i - tokenBegin));
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530168 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600169 tokenBegin = i;
170 while (i != value.end() && *i != ',')
171 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530172 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600173 }
Ed Tanous271584a2019-07-09 16:24:22 -0700174 const std::string_view val(tokenBegin,
175 static_cast<size_t>(i - tokenBegin));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600176 if (key == "L")
177 {
178 out["City"] = val;
179 }
180 else if (key == "CN")
181 {
182 out["CommonName"] = val;
183 }
184 else if (key == "C")
185 {
186 out["Country"] = val;
187 }
188 else if (key == "O")
189 {
190 out["Organization"] = val;
191 }
192 else if (key == "OU")
193 {
194 out["OrganizationalUnit"] = val;
195 }
196 else if (key == "ST")
197 {
198 out["State"] = val;
199 }
200 // skip comma character
201 if (i != value.end())
202 {
Manojkiran Eda17a897d2020-09-12 15:31:58 +0530203 ++i;
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600204 }
205 }
206}
207
208/**
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800209 * @brief Retrieve the installed certificate list
210 *
211 * @param[in] asyncResp Shared pointer to the response message
212 * @param[in] basePath DBus object path to search
213 * @param[in] listPtr Json pointer to the list in asyncResp
214 * @param[in] countPtr Json pointer to the count in asyncResp
215 * @return None
216 */
217static void
218 getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
219 const std::string& basePath,
220 const nlohmann::json::json_pointer& listPtr,
221 const nlohmann::json::json_pointer& countPtr)
222{
George Liu7a1dbc42022-12-07 16:03:22 +0800223 constexpr std::array<std::string_view, 1> interfaces = {
224 certs::certPropIntf};
225 dbus::utility::getSubTreePaths(
226 basePath, 0, interfaces,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800227 [asyncResp, listPtr, countPtr](
George Liu7a1dbc42022-12-07 16:03:22 +0800228 const boost::system::error_code& ec,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800229 const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
230 if (ec)
231 {
232 BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec;
233 messages::internalError(asyncResp->res);
234 return;
235 }
236
237 nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
238 links = nlohmann::json::array();
239 for (const auto& certPath : certPaths)
240 {
241 sdbusplus::message::object_path objPath(certPath);
242 std::string certId = objPath.filename();
243 if (certId.empty())
244 {
245 BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath;
246 continue;
247 }
248
249 boost::urls::url certURL;
250 if (objPath.parent_path() == certs::httpsObjectPath)
251 {
252 certURL = crow::utility::urlFromPieces(
253 "redfish", "v1", "Managers", "bmc", "NetworkProtocol",
254 "HTTPS", "Certificates", certId);
255 }
256 else if (objPath.parent_path() == certs::ldapObjectPath)
257 {
258 certURL = crow::utility::urlFromPieces("redfish", "v1",
259 "AccountService", "LDAP",
260 "Certificates", certId);
261 }
262 else if (objPath.parent_path() == certs::authorityObjectPath)
263 {
264 certURL = crow::utility::urlFromPieces(
265 "redfish", "v1", "Managers", "bmc", "Truststore",
266 "Certificates", certId);
267 }
268 else
269 {
270 continue;
271 }
272
273 nlohmann::json::object_t link;
274 link["@odata.id"] = certURL;
275 links.emplace_back(std::move(link));
276 }
277
278 asyncResp->res.jsonValue[countPtr] = links.size();
George Liu7a1dbc42022-12-07 16:03:22 +0800279 });
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800280}
281
282/**
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600283 * @brief Retrieve the certificates properties and append to the response
284 * message
285 *
286 * @param[in] asyncResp Shared pointer to the response message
287 * @param[in] objectPath Path of the D-Bus service object
288 * @param[in] certId Id of the certificate
289 * @param[in] certURL URL of the certificate object
290 * @param[in] name name of the certificate
291 * @return None
292 */
293static void getCertificateProperties(
zhanghch058d1b46d2021-04-01 11:18:24 +0800294 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800295 const std::string& objectPath, const std::string& service,
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800296 const std::string& certId, const boost::urls::url& certURL,
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800297 const std::string& name)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600298{
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600299 BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath
300 << " certId=" << certId << " certURl=" << certURL;
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200301 sdbusplus::asio::getAllProperties(
302 *crow::connections::systemBus, service, objectPath, certs::certPropIntf,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800303 [asyncResp, certURL, certId,
304 name](const boost::system::error_code ec,
305 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700306 if (ec)
307 {
308 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800309 messages::resourceNotFound(asyncResp->res, "Certificate", certId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700310 return;
311 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200312
313 const std::string* certificateString = nullptr;
314 const std::vector<std::string>* keyUsage = nullptr;
315 const std::string* issuer = nullptr;
316 const std::string* subject = nullptr;
317 const uint64_t* validNotAfter = nullptr;
318 const uint64_t* validNotBefore = nullptr;
319
320 const bool success = sdbusplus::unpackPropertiesNoThrow(
321 dbus_utils::UnpackErrorPrinter(), properties, "CertificateString",
322 certificateString, "KeyUsage", keyUsage, "Issuer", issuer,
323 "Subject", subject, "ValidNotAfter", validNotAfter,
324 "ValidNotBefore", validNotBefore);
325
326 if (!success)
327 {
328 messages::internalError(asyncResp->res);
329 return;
330 }
331
Ed Tanous002d39b2022-05-31 08:59:27 -0700332 asyncResp->res.jsonValue["@odata.id"] = certURL;
333 asyncResp->res.jsonValue["@odata.type"] =
334 "#Certificate.v1_0_0.Certificate";
Jiaqing Zhaoe19e97e2022-06-06 19:43:39 +0800335 asyncResp->res.jsonValue["Id"] = certId;
Ed Tanous002d39b2022-05-31 08:59:27 -0700336 asyncResp->res.jsonValue["Name"] = name;
337 asyncResp->res.jsonValue["Description"] = name;
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200338 asyncResp->res.jsonValue["CertificateString"] = "";
339 asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array();
340
341 if (certificateString != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700342 {
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200343 asyncResp->res.jsonValue["CertificateString"] = *certificateString;
Ed Tanous002d39b2022-05-31 08:59:27 -0700344 }
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200345
346 if (keyUsage != nullptr)
347 {
348 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage;
349 }
350
351 if (issuer != nullptr)
352 {
353 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"],
354 *issuer);
355 }
356
357 if (subject != nullptr)
358 {
359 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"],
360 *subject);
361 }
362
363 if (validNotAfter != nullptr)
364 {
365 asyncResp->res.jsonValue["ValidNotAfter"] =
366 redfish::time_utils::getDateTimeUint(*validNotAfter);
367 }
368
369 if (validNotBefore != nullptr)
370 {
371 asyncResp->res.jsonValue["ValidNotBefore"] =
372 redfish::time_utils::getDateTimeUint(*validNotBefore);
373 }
374
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800375 asyncResp->res.addHeader(
Ed Tanousd9f6c622022-03-17 09:12:17 -0700376 boost::beast::http::field::location,
377 std::string_view(certURL.data(), certURL.size()));
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200378 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600379}
380
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800381static void
382 deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
383 const std::string& service,
384 const sdbusplus::message::object_path& objectPath)
385{
386 crow::connections::systemBus->async_method_call(
387 [asyncResp,
388 id{objectPath.filename()}](const boost::system::error_code ec) {
389 if (ec)
390 {
391 messages::resourceNotFound(asyncResp->res, "Certificate", id);
392 return;
393 }
394 BMCWEB_LOG_INFO << "Certificate deleted";
395 asyncResp->res.result(boost::beast::http::status::no_content);
396 },
397 service, objectPath, certs::objDeleteIntf, "Delete");
398}
399
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800400inline void handleCertificateServiceGet(
401 App& app, const crow::Request& req,
402 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600403{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800404 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
405 {
406 return;
407 }
408
409 asyncResp->res.jsonValue["@odata.type"] =
410 "#CertificateService.v1_0_0.CertificateService";
411 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
412 asyncResp->res.jsonValue["Id"] = "CertificateService";
413 asyncResp->res.jsonValue["Name"] = "Certificate Service";
414 asyncResp->res.jsonValue["Description"] =
415 "Actions available to manage certificates";
416 // /redfish/v1/CertificateService/CertificateLocations is something
417 // only ConfigureManager can access then only display when the user
418 // has permissions ConfigureManager
419 Privileges effectiveUserPrivileges =
420 redfish::getUserPrivileges(req.userRole);
421 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
422 effectiveUserPrivileges))
423 {
424 asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
425 "/redfish/v1/CertificateService/CertificateLocations";
426 }
427 nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
428 nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
429 replace["target"] =
430 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
431 nlohmann::json::array_t allowed;
432 allowed.push_back("PEM");
433 replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
434 actions["#CertificateService.GenerateCSR"]["target"] =
435 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
436}
437
438inline void handleCertificateLocationsGet(
439 App& app, const crow::Request& req,
440 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
441{
442 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
443 {
444 return;
445 }
446 asyncResp->res.jsonValue["@odata.id"] =
447 "/redfish/v1/CertificateService/CertificateLocations";
448 asyncResp->res.jsonValue["@odata.type"] =
449 "#CertificateLocations.v1_0_0.CertificateLocations";
450 asyncResp->res.jsonValue["Name"] = "Certificate Locations";
451 asyncResp->res.jsonValue["Id"] = "CertificateLocations";
452 asyncResp->res.jsonValue["Description"] =
453 "Defines a resource that an administrator can use in order to "
454 "locate all certificates installed on a given service";
455
456 getCertificateList(asyncResp, certs::baseObjectPath,
457 "/Links/Certificates"_json_pointer,
458 "/Links/Certificates@odata.count"_json_pointer);
459}
460
461inline void handleReplaceCertificateAction(
462 App& app, const crow::Request& req,
463 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
464{
465 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
466 {
467 return;
468 }
469 std::string certificate;
470 nlohmann::json certificateUri;
471 std::optional<std::string> certificateType = "PEM";
472
473 if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
474 certificate, "CertificateUri",
475 certificateUri, "CertificateType",
476 certificateType))
477 {
478 BMCWEB_LOG_ERROR << "Required parameters are missing";
479 messages::internalError(asyncResp->res);
480 return;
481 }
482
483 if (!certificateType)
484 {
485 // should never happen, but it never hurts to be paranoid.
486 return;
487 }
488 if (certificateType != "PEM")
489 {
490 messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
491 "ReplaceCertificate");
492 return;
493 }
494
495 std::string certURI;
496 if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
497 "@odata.id", certURI))
498 {
499 messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
500 "CertificateUri");
501 return;
502 }
503 BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI;
504
505 boost::urls::result<boost::urls::url_view> parsedUrl =
506 boost::urls::parse_relative_ref(certURI);
507 if (!parsedUrl)
508 {
509 messages::actionParameterValueFormatError(
510 asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
511 return;
512 }
513
514 std::string id;
515 sdbusplus::message::object_path objectPath;
516 std::string name;
517 std::string service;
518 if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
519 "bmc", "NetworkProtocol", "HTTPS",
520 "Certificates", std::ref(id)))
521 {
522 objectPath =
523 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
524 name = "HTTPS certificate";
525 service = certs::httpsServiceName;
526 }
527 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
528 "AccountService", "LDAP",
529 "Certificates", std::ref(id)))
530 {
531 objectPath =
532 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
533 name = "LDAP certificate";
534 service = certs::ldapServiceName;
535 }
536 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
537 "Managers", "bmc", "Truststore",
538 "Certificates", std::ref(id)))
539 {
540 objectPath =
541 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
542 name = "TrustStore certificate";
543 service = certs::authorityServiceName;
544 }
545 else
546 {
547 messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
548 "ReplaceCertificate");
549 return;
550 }
551
552 std::shared_ptr<CertificateFile> certFile =
553 std::make_shared<CertificateFile>(certificate);
554 crow::connections::systemBus->async_method_call(
555 [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
556 name](const boost::system::error_code ec) {
557 if (ec)
558 {
559 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
560 if (ec.value() ==
561 boost::system::linux_error::bad_request_descriptor)
562 {
563 messages::resourceNotFound(asyncResp->res, "Certificate", id);
564 return;
565 }
566 messages::internalError(asyncResp->res);
567 return;
568 }
569 getCertificateProperties(asyncResp, objectPath, service, id, url, name);
570 BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
571 << certFile->getCertFilePath();
572 },
573 service, objectPath, certs::certReplaceIntf, "Replace",
574 certFile->getCertFilePath());
575}
576
Ed Tanouscf9e4172022-12-21 09:30:16 -0800577// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800578static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
579/**
580 * @brief Read data from CSR D-bus object and set to response
581 *
582 * @param[in] asyncResp Shared pointer to the response message
583 * @param[in] certURI Link to certifiate collection URI
584 * @param[in] service D-Bus service name
585 * @param[in] certObjPath certificate D-Bus object path
586 * @param[in] csrObjPath CSR D-Bus object path
587 * @return None
588 */
589static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
590 const std::string& certURI, const std::string& service,
591 const std::string& certObjPath,
592 const std::string& csrObjPath)
593{
594 BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath
595 << " CSRObjectPath=" << csrObjPath
596 << " service=" << service;
597 crow::connections::systemBus->async_method_call(
598 [asyncResp, certURI](const boost::system::error_code ec,
599 const std::string& csr) {
600 if (ec)
601 {
602 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
603 messages::internalError(asyncResp->res);
604 return;
605 }
606 if (csr.empty())
607 {
608 BMCWEB_LOG_ERROR << "CSR read is empty";
609 messages::internalError(asyncResp->res);
610 return;
611 }
612 asyncResp->res.jsonValue["CSRString"] = csr;
613 asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
614 certURI;
615 },
616 service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
617}
618
619inline void
620 handleGenerateCSRAction(App& app, const crow::Request& req,
621 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
622{
623 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
624 {
625 return;
626 }
627 static const int rsaKeyBitLength = 2048;
628
629 // Required parameters
630 std::string city;
631 std::string commonName;
632 std::string country;
633 std::string organization;
634 std::string organizationalUnit;
635 std::string state;
636 nlohmann::json certificateCollection;
637
638 // Optional parameters
639 std::optional<std::vector<std::string>> optAlternativeNames =
640 std::vector<std::string>();
641 std::optional<std::string> optContactPerson = "";
642 std::optional<std::string> optChallengePassword = "";
643 std::optional<std::string> optEmail = "";
644 std::optional<std::string> optGivenName = "";
645 std::optional<std::string> optInitials = "";
646 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
647 std::optional<std::string> optKeyCurveId = "secp384r1";
648 std::optional<std::string> optKeyPairAlgorithm = "EC";
649 std::optional<std::vector<std::string>> optKeyUsage =
650 std::vector<std::string>();
651 std::optional<std::string> optSurname = "";
652 std::optional<std::string> optUnstructuredName = "";
653 if (!json_util::readJsonAction(
654 req, asyncResp->res, "City", city, "CommonName", commonName,
655 "ContactPerson", optContactPerson, "Country", country,
656 "Organization", organization, "OrganizationalUnit",
657 organizationalUnit, "State", state, "CertificateCollection",
658 certificateCollection, "AlternativeNames", optAlternativeNames,
659 "ChallengePassword", optChallengePassword, "Email", optEmail,
660 "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
661 optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
662 optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
663 "UnstructuredName", optUnstructuredName))
664 {
665 return;
666 }
667
668 // bmcweb has no way to store or decode a private key challenge
669 // password, which will likely cause bmcweb to crash on startup
670 // if this is not set on a post so not allowing the user to set
671 // value
672 if (!optChallengePassword->empty())
673 {
674 messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
675 "ChallengePassword");
676 return;
677 }
678
679 std::string certURI;
680 if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
681 "@odata.id", certURI))
682 {
683 return;
684 }
685
686 std::string objectPath;
687 std::string service;
688 if (certURI.starts_with(
689 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
690 {
691 objectPath = certs::httpsObjectPath;
692 service = certs::httpsServiceName;
693 }
694 else if (certURI.starts_with(
695 "/redfish/v1/AccountService/LDAP/Certificates"))
696 {
697 objectPath = certs::ldapObjectPath;
698 service = certs::ldapServiceName;
699 }
700 else
701 {
702 messages::actionParameterNotSupported(
703 asyncResp->res, "CertificateCollection", "GenerateCSR");
704 return;
705 }
706
707 // supporting only EC and RSA algorithm
708 if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
709 {
710 messages::actionParameterNotSupported(
711 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
712 return;
713 }
714
715 // supporting only 2048 key bit length for RSA algorithm due to
716 // time consumed in generating private key
717 if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
718 {
719 messages::propertyValueNotInList(
720 asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength");
721 return;
722 }
723
724 // validate KeyUsage supporting only 1 type based on URL
725 if (certURI.starts_with(
726 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
727 {
728 if (optKeyUsage->empty())
729 {
730 optKeyUsage->push_back("ServerAuthentication");
731 }
732 else if (optKeyUsage->size() == 1)
733 {
734 if ((*optKeyUsage)[0] != "ServerAuthentication")
735 {
736 messages::propertyValueNotInList(asyncResp->res,
737 (*optKeyUsage)[0], "KeyUsage");
738 return;
739 }
740 }
741 else
742 {
743 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
744 "GenerateCSR");
745 return;
746 }
747 }
748 else if (certURI.starts_with(
749 "/redfish/v1/AccountService/LDAP/Certificates"))
750 {
751 if (optKeyUsage->empty())
752 {
753 optKeyUsage->push_back("ClientAuthentication");
754 }
755 else if (optKeyUsage->size() == 1)
756 {
757 if ((*optKeyUsage)[0] != "ClientAuthentication")
758 {
759 messages::propertyValueNotInList(asyncResp->res,
760 (*optKeyUsage)[0], "KeyUsage");
761 return;
762 }
763 }
764 else
765 {
766 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
767 "GenerateCSR");
768 return;
769 }
770 }
771
772 // Only allow one CSR matcher at a time so setting retry
773 // time-out and timer expiry to 10 seconds for now.
774 static const int timeOut = 10;
775 if (csrMatcher)
776 {
777 messages::serviceTemporarilyUnavailable(asyncResp->res,
778 std::to_string(timeOut));
779 return;
780 }
781
782 // Make this static so it survives outside this method
783 static boost::asio::steady_timer timeout(*req.ioService);
784 timeout.expires_after(std::chrono::seconds(timeOut));
785 timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
786 csrMatcher = nullptr;
787 if (ec)
788 {
789 // operation_aborted is expected if timer is canceled
790 // before completion.
791 if (ec != boost::asio::error::operation_aborted)
792 {
793 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
794 }
795 return;
796 }
797 BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR";
798 messages::internalError(asyncResp->res);
799 });
800
801 // create a matcher to wait on CSR object
802 BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath;
803 std::string match("type='signal',"
804 "interface='org.freedesktop.DBus.ObjectManager',"
805 "path='" +
806 objectPath +
807 "',"
808 "member='InterfacesAdded'");
809 csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
810 *crow::connections::systemBus, match,
811 [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
812 timeout.cancel();
813 if (m.is_method_error())
814 {
815 BMCWEB_LOG_ERROR << "Dbus method error!!!";
816 messages::internalError(asyncResp->res);
817 return;
818 }
819
820 dbus::utility::DBusInteracesMap interfacesProperties;
821
822 sdbusplus::message::object_path csrObjectPath;
823 m.read(csrObjectPath, interfacesProperties);
824 BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str;
825 for (const auto& interface : interfacesProperties)
826 {
827 if (interface.first == "xyz.openbmc_project.Certs.CSR")
828 {
829 getCSR(asyncResp, certURI, service, objectPath,
830 csrObjectPath.str);
831 break;
832 }
833 }
834 });
835 crow::connections::systemBus->async_method_call(
836 [asyncResp](const boost::system::error_code ec, const std::string&) {
837 if (ec)
838 {
839 BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message();
840 messages::internalError(asyncResp->res);
841 return;
842 }
843 },
844 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
845 "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
846 commonName, *optContactPerson, country, *optEmail, *optGivenName,
847 *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
848 *optKeyUsage, organization, organizationalUnit, state, *optSurname,
849 *optUnstructuredName);
850}
851
852inline void requestRoutesCertificateService(App& app)
853{
854 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
855 .privileges(redfish::privileges::getCertificateService)
856 .methods(boost::beast::http::verb::get)(
857 std::bind_front(handleCertificateServiceGet, std::ref(app)));
858
859 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
860 .privileges(redfish::privileges::getCertificateLocations)
861 .methods(boost::beast::http::verb::get)(
862 std::bind_front(handleCertificateLocationsGet, std::ref(app)));
863
George Liu0fda0f12021-11-16 10:06:17 +0800864 BMCWEB_ROUTE(
865 app,
866 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
Ed Tanoused398212021-06-09 17:05:54 -0700867 .privileges(redfish::privileges::postCertificateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700868 .methods(boost::beast::http::verb::post)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800869 std::bind_front(handleReplaceCertificateAction, std::ref(app)));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600870
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800871 BMCWEB_ROUTE(
872 app,
873 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
874 .privileges(redfish::privileges::postCertificateService)
875 .methods(boost::beast::http::verb::post)(
876 std::bind_front(handleGenerateCSRAction, std::ref(app)));
877} // requestRoutesCertificateService
878
879inline void handleHTTPSCertificateCollectionGet(
880 App& app, const crow::Request& req,
881 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
882{
883 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
884 {
885 return;
886 }
887
888 asyncResp->res.jsonValue["@odata.id"] =
889 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
890 asyncResp->res.jsonValue["@odata.type"] =
891 "#CertificateCollection.CertificateCollection";
892 asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
893 asyncResp->res.jsonValue["Description"] =
894 "A Collection of HTTPS certificate instances";
895
896 getCertificateList(asyncResp, certs::httpsObjectPath,
897 "/Members"_json_pointer,
898 "/Members@odata.count"_json_pointer);
899}
900
901inline void handleHTTPSCertificateCollectionPost(
902 App& app, const crow::Request& req,
903 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
904{
905 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
906 {
907 return;
908 }
909 BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost";
910
911 asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
912 asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
913
914 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
915
916 if (certFileBody.empty())
917 {
918 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
919 messages::unrecognizedRequestBody(asyncResp->res);
920 return;
921 }
922
923 std::shared_ptr<CertificateFile> certFile =
924 std::make_shared<CertificateFile>(certFileBody);
925
926 crow::connections::systemBus->async_method_call(
927 [asyncResp, certFile](const boost::system::error_code ec,
928 const std::string& objectPath) {
929 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700930 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800931 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
Ed Tanous002d39b2022-05-31 08:59:27 -0700932 messages::internalError(asyncResp->res);
933 return;
934 }
935
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800936 sdbusplus::message::object_path path(objectPath);
937 std::string certId = path.filename();
938 const boost::urls::url certURL = crow::utility::urlFromPieces(
939 "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
940 "Certificates", certId);
941 getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
942 certId, certURL, "HTTPS Certificate");
943 BMCWEB_LOG_DEBUG << "HTTPS certificate install file="
944 << certFile->getCertFilePath();
945 },
946 certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
947 "Install", certFile->getCertFilePath());
948}
Ed Tanous002d39b2022-05-31 08:59:27 -0700949
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800950inline void handleHTTPSCertificateGet(
951 App& app, const crow::Request& req,
952 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
953{
954 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
955 {
956 return;
957 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700958
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800959 BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id;
960 const boost::urls::url certURL = crow::utility::urlFromPieces(
961 "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS",
962 "Certificates", id);
963 std::string objPath =
964 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
965 getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
966 certURL, "HTTPS Certificate");
967}
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700968
969inline void requestRoutesHTTPSCertificate(App& app)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600970{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800971 BMCWEB_ROUTE(app,
972 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
973 .privileges(redfish::privileges::getCertificateCollection)
974 .methods(boost::beast::http::verb::get)(std::bind_front(
975 handleHTTPSCertificateCollectionGet, std::ref(app)));
976
977 BMCWEB_ROUTE(app,
978 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
979 .privileges(redfish::privileges::postCertificateCollection)
980 .methods(boost::beast::http::verb::post)(std::bind_front(
981 handleHTTPSCertificateCollectionPost, std::ref(app)));
982
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700983 BMCWEB_ROUTE(
984 app,
985 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700986 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800987 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800988 std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700989}
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600990
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800991inline void handleLDAPCertificateCollectionGet(
992 App& app, const crow::Request& req,
993 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600994{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800995 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
996 {
997 return;
998 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700999
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001000 asyncResp->res.jsonValue["@odata.id"] =
1001 "/redfish/v1/AccountService/LDAP/Certificates";
1002 asyncResp->res.jsonValue["@odata.type"] =
1003 "#CertificateCollection.CertificateCollection";
1004 asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
1005 asyncResp->res.jsonValue["Description"] =
1006 "A Collection of LDAP certificate instances";
Ed Tanous002d39b2022-05-31 08:59:27 -07001007
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001008 getCertificateList(asyncResp, certs::ldapObjectPath,
1009 "/Members"_json_pointer,
1010 "/Members@odata.count"_json_pointer);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001011}
Marri Devender Rao37cce912019-02-20 01:05:22 -06001012
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001013inline void handleLDAPCertificateCollectionPost(
1014 App& app, const crow::Request& req,
1015 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001016{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001017 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1018 {
1019 return;
1020 }
1021 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1022
1023 if (certFileBody.empty())
1024 {
1025 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1026 messages::unrecognizedRequestBody(asyncResp->res);
1027 return;
1028 }
1029
1030 std::shared_ptr<CertificateFile> certFile =
1031 std::make_shared<CertificateFile>(certFileBody);
1032
1033 crow::connections::systemBus->async_method_call(
1034 [asyncResp, certFile](const boost::system::error_code ec,
1035 const std::string& objectPath) {
1036 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001037 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001038 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1039 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001040 return;
1041 }
1042
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001043 sdbusplus::message::object_path path(objectPath);
1044 std::string certId = path.filename();
1045 const boost::urls::url certURL = crow::utility::urlFromPieces(
1046 "redfish", "v1", "AccountService", "LDAP", "Certificates", certId);
1047 getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1048 certId, certURL, "LDAP Certificate");
1049 BMCWEB_LOG_DEBUG << "LDAP certificate install file="
1050 << certFile->getCertFilePath();
1051 },
1052 certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1053 "Install", certFile->getCertFilePath());
1054}
Ed Tanous002d39b2022-05-31 08:59:27 -07001055
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001056inline void handleLDAPCertificateGet(
1057 App& app, const crow::Request& req,
1058 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1059{
1060 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1061 {
1062 return;
1063 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001064
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001065 BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id;
1066 const boost::urls::url certURL = crow::utility::urlFromPieces(
1067 "redfish", "v1", "AccountService", "LDAP", "Certificates", id);
1068 std::string objPath =
1069 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1070 getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1071 certURL, "LDAP Certificate");
1072}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001073
Jiaqing Zhao99612242022-09-29 15:31:09 +08001074inline void handleLDAPCertificateDelete(
1075 App& app, const crow::Request& req,
1076 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1077{
1078 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1079 {
1080 return;
1081 }
1082
1083 BMCWEB_LOG_DEBUG << "Delete LDAP Certificate ID=" << id;
1084 std::string objPath =
1085 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1086
1087 deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
1088}
1089
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001090inline void requestRoutesLDAPCertificate(App& app)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001091{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001092 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1093 .privileges(redfish::privileges::getCertificateCollection)
1094 .methods(boost::beast::http::verb::get)(
1095 std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1096
1097 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1098 .privileges(redfish::privileges::postCertificateCollection)
1099 .methods(boost::beast::http::verb::post)(std::bind_front(
1100 handleLDAPCertificateCollectionPost, std::ref(app)));
1101
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001102 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001103 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001104 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001105 std::bind_front(handleLDAPCertificateGet, std::ref(app)));
Jiaqing Zhao99612242022-09-29 15:31:09 +08001106
1107 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1108 .privileges(redfish::privileges::deleteCertificate)
1109 .methods(boost::beast::http::verb::delete_)(
1110 std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001111} // requestRoutesLDAPCertificate
1112
1113inline void handleTrustStoreCertificateCollectionGet(
1114 App& app, const crow::Request& req,
1115 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1116{
1117 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1118 {
1119 return;
1120 }
1121
1122 asyncResp->res.jsonValue["@odata.id"] =
1123 "/redfish/v1/Managers/bmc/Truststore/Certificates/";
1124 asyncResp->res.jsonValue["@odata.type"] =
1125 "#CertificateCollection.CertificateCollection";
1126 asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
1127 asyncResp->res.jsonValue["Description"] =
1128 "A Collection of TrustStore certificate instances";
1129
1130 getCertificateList(asyncResp, certs::authorityObjectPath,
1131 "/Members"_json_pointer,
1132 "/Members@odata.count"_json_pointer);
1133}
1134
1135inline void handleTrustStoreCertificateCollectionPost(
1136 App& app, const crow::Request& req,
1137 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1138{
1139 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1140 {
1141 return;
1142 }
1143 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1144
1145 if (certFileBody.empty())
1146 {
1147 BMCWEB_LOG_ERROR << "Cannot get certificate from request body.";
1148 messages::unrecognizedRequestBody(asyncResp->res);
1149 return;
1150 }
1151
1152 std::shared_ptr<CertificateFile> certFile =
1153 std::make_shared<CertificateFile>(certFileBody);
1154 crow::connections::systemBus->async_method_call(
1155 [asyncResp, certFile](const boost::system::error_code ec,
1156 const std::string& objectPath) {
1157 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001158 {
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001159 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
1160 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001161 return;
1162 }
Jiaqing Zhao717b9802022-06-06 20:24:04 +08001163
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001164 sdbusplus::message::object_path path(objectPath);
1165 std::string certId = path.filename();
1166 const boost::urls::url certURL =
1167 crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1168 "Truststore", "Certificates", certId);
1169 getCertificateProperties(asyncResp, objectPath,
1170 certs::authorityServiceName, certId, certURL,
1171 "TrustStore Certificate");
1172 BMCWEB_LOG_DEBUG << "TrustStore certificate install file="
1173 << certFile->getCertFilePath();
1174 },
1175 certs::authorityServiceName, certs::authorityObjectPath,
1176 certs::certInstallIntf, "Install", certFile->getCertFilePath());
1177}
1178
1179inline void handleTrustStoreCertificateGet(
1180 App& app, const crow::Request& req,
1181 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1182{
1183 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1184 {
1185 return;
1186 }
1187
1188 BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id;
1189 const boost::urls::url certURL = crow::utility::urlFromPieces(
1190 "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id);
1191 std::string objPath =
1192 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1193 getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1194 id, certURL, "TrustStore Certificate");
1195}
1196
1197inline void handleTrustStoreCertificateDelete(
1198 App& app, const crow::Request& req,
1199 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1200{
1201 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1202 {
1203 return;
1204 }
1205
1206 BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id;
1207 std::string objPath =
1208 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1209
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +08001210 deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001211}
1212
1213inline void requestRoutesTrustStoreCertificate(App& app)
Marri Devender Raocfcd5f62019-05-17 08:34:37 -05001214{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001215 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001216 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001217 .methods(boost::beast::http::verb::get)(std::bind_front(
1218 handleTrustStoreCertificateCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219
1220 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001221 .privileges(redfish::privileges::postCertificateCollection)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001222 .methods(boost::beast::http::verb::post)(std::bind_front(
1223 handleTrustStoreCertificateCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07001224
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001225 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001226 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001227 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001228 std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001229
1230 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001231 .privileges(redfish::privileges::deleteCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001232 .methods(boost::beast::http::verb::delete_)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001233 std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001234} // requestRoutesTrustStoreCertificate
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001235} // namespace redfish