blob: 6fba827371f61b28a84e0282bc076525be41cb24 [file] [log] [blame]
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001#pragma once
2
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08003#include "app.hpp"
4#include "async_resp.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +08005#include "dbus_utility.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01006#include "http/parsing.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08007#include "http_response.hpp"
8#include "query.hpp"
9#include "registries/privilege_registry.hpp"
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020010#include "utils/dbus_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011#include "utils/json_utils.hpp"
12#include "utils/time_utils.hpp"
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020013
Jiaqing Zhao90d2d1e2022-04-13 17:01:57 +080014#include <boost/system/linux_error.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070015#include <boost/url/format.hpp>
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020016#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080017#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +020018#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050019
George Liu7a1dbc42022-12-07 16:03:22 +080020#include <array>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include <memory>
George Liu7a1dbc42022-12-07 16:03:22 +080022#include <string_view>
23
Marri Devender Rao5968cae2019-01-21 10:27:12 -060024namespace redfish
25{
26namespace certs
27{
Patrick Williams89492a12023-05-10 07:51:34 -050028constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install";
29constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace";
30constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete";
31constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate";
32constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties";
33constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
34constexpr const char* httpsServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060035 "xyz.openbmc_project.Certs.Manager.Server.Https";
Patrick Williams89492a12023-05-10 07:51:34 -050036constexpr const char* ldapServiceName =
Marri Devender Rao37cce912019-02-20 01:05:22 -060037 "xyz.openbmc_project.Certs.Manager.Client.Ldap";
Patrick Williams89492a12023-05-10 07:51:34 -050038constexpr const char* authorityServiceName =
Michal Orzelb2254cc2023-07-27 14:08:32 +020039 "xyz.openbmc_project.Certs.Manager.Authority.Truststore";
Patrick Williams89492a12023-05-10 07:51:34 -050040constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs";
41constexpr const char* httpsObjectPath =
Jiaqing Zhaoc6a8dfb2022-06-03 10:44:23 +080042 "/xyz/openbmc_project/certs/server/https";
Patrick Williams89492a12023-05-10 07:51:34 -050043constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap";
44constexpr const char* authorityObjectPath =
Michal Orzelb2254cc2023-07-27 14:08:32 +020045 "/xyz/openbmc_project/certs/authority/truststore";
Marri Devender Rao5968cae2019-01-21 10:27:12 -060046} // namespace certs
47
48/**
49 * The Certificate schema defines a Certificate Service which represents the
50 * actions available to manage certificates and links to where certificates
51 * are installed.
52 */
Marri Devender Rao5968cae2019-01-21 10:27:12 -060053
zhanghch058d1b46d2021-04-01 11:18:24 +080054inline std::string getCertificateFromReqBody(
55 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
56 const crow::Request& req)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020057{
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010058 nlohmann::json reqJson;
59 JsonParseResult ret = parseRequestAsJson(req, reqJson);
60 if (ret != JsonParseResult::Success)
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020061 {
62 // We did not receive JSON request, proceed as it is RAW data
Ed Tanous33c6b582023-02-14 15:05:48 -080063 return req.body();
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020064 }
65
66 std::string certificate;
67 std::optional<std::string> certificateType = "PEM";
68
Willy Tu15ed6782021-12-14 11:03:16 -080069 if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString",
70 certificate, "CertificateType",
71 certificateType))
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020072 {
Ed Tanous62598e32023-07-17 17:06:25 -070073 BMCWEB_LOG_ERROR("Required parameters are missing");
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020074 messages::internalError(asyncResp->res);
Ed Tanousabb93cd2021-09-02 14:34:57 -070075 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020076 }
77
78 if (*certificateType != "PEM")
79 {
80 messages::propertyValueNotInList(asyncResp->res, *certificateType,
81 "CertificateType");
Ed Tanousabb93cd2021-09-02 14:34:57 -070082 return {};
Kowalski, Kamil58eb2382019-08-12 11:54:31 +020083 }
84
85 return certificate;
86}
87
Marri Devender Rao5968cae2019-01-21 10:27:12 -060088/**
89 * Class to create a temporary certificate file for uploading to system
90 */
91class CertificateFile
92{
93 public:
94 CertificateFile() = delete;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050095 CertificateFile(const CertificateFile&) = delete;
96 CertificateFile& operator=(const CertificateFile&) = delete;
97 CertificateFile(CertificateFile&&) = delete;
98 CertificateFile& operator=(CertificateFile&&) = delete;
Ed Tanous4e23a442022-06-06 09:57:26 -070099 explicit CertificateFile(const std::string& certString)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600100 {
Ed Tanous72d52d22020-10-12 07:46:27 -0700101 std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C',
Ed Tanous52074382020-09-28 19:16:18 -0700102 'e', 'r', 't', 's', '.', 'X',
103 'X', 'X', 'X', 'X', 'X', '\0'};
104 char* tempDirectory = mkdtemp(dirTemplate.data());
Ed Tanouse662eae2022-01-25 10:39:19 -0800105 if (tempDirectory != nullptr)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600106 {
107 certDirectory = tempDirectory;
108 certificateFile = certDirectory / "cert.pem";
109 std::ofstream out(certificateFile, std::ofstream::out |
110 std::ofstream::binary |
111 std::ofstream::trunc);
112 out << certString;
113 out.close();
Ed Tanous62598e32023-07-17 17:06:25 -0700114 BMCWEB_LOG_DEBUG("Creating certificate file{}",
115 certificateFile.string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600116 }
117 }
118 ~CertificateFile()
119 {
120 if (std::filesystem::exists(certDirectory))
121 {
Ed Tanous62598e32023-07-17 17:06:25 -0700122 BMCWEB_LOG_DEBUG("Removing certificate file{}",
123 certificateFile.string());
Ed Tanous23a21a12020-07-25 04:45:05 +0000124 std::error_code ec;
125 std::filesystem::remove_all(certDirectory, ec);
126 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600127 {
Ed Tanous62598e32023-07-17 17:06:25 -0700128 BMCWEB_LOG_ERROR("Failed to remove temp directory{}",
129 certDirectory.string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600130 }
131 }
132 }
133 std::string getCertFilePath()
134 {
135 return certificateFile;
136 }
137
138 private:
139 std::filesystem::path certificateFile;
140 std::filesystem::path certDirectory;
141};
142
143/**
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500144 * @brief Parse and update Certificate Issue/Subject property
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600145 *
146 * @param[in] asyncResp Shared pointer to the response message
147 * @param[in] str Issuer/Subject value in key=value pairs
148 * @param[in] type Issuer/Subject
149 * @return None
150 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500151static void updateCertIssuerOrSubject(nlohmann::json& out,
Ed Tanous26ccae32023-02-16 10:28:44 -0800152 std::string_view value)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600153{
154 // example: O=openbmc-project.xyz,CN=localhost
155 std::string_view::iterator i = value.begin();
156 while (i != value.end())
157 {
158 std::string_view::iterator tokenBegin = i;
159 while (i != value.end() && *i != '=')
160 {
Patrick Williams6da47ba2023-05-11 11:53:56 -0500161 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600162 }
163 if (i == value.end())
164 {
165 break;
166 }
Ed Tanous26ccae32023-02-16 10:28:44 -0800167 std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin));
Patrick Williams6da47ba2023-05-11 11:53:56 -0500168 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600169 tokenBegin = i;
170 while (i != value.end() && *i != ',')
171 {
Patrick Williams6da47ba2023-05-11 11:53:56 -0500172 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600173 }
Ed Tanous26ccae32023-02-16 10:28:44 -0800174 std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600175 if (key == "L")
176 {
177 out["City"] = val;
178 }
179 else if (key == "CN")
180 {
181 out["CommonName"] = val;
182 }
183 else if (key == "C")
184 {
185 out["Country"] = val;
186 }
187 else if (key == "O")
188 {
189 out["Organization"] = val;
190 }
191 else if (key == "OU")
192 {
193 out["OrganizationalUnit"] = val;
194 }
195 else if (key == "ST")
196 {
197 out["State"] = val;
198 }
199 // skip comma character
200 if (i != value.end())
201 {
Patrick Williams6da47ba2023-05-11 11:53:56 -0500202 std::advance(i, 1);
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600203 }
204 }
205}
206
207/**
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800208 * @brief Retrieve the installed certificate list
209 *
210 * @param[in] asyncResp Shared pointer to the response message
211 * @param[in] basePath DBus object path to search
212 * @param[in] listPtr Json pointer to the list in asyncResp
213 * @param[in] countPtr Json pointer to the count in asyncResp
214 * @return None
215 */
216static void
217 getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
218 const std::string& basePath,
219 const nlohmann::json::json_pointer& listPtr,
220 const nlohmann::json::json_pointer& countPtr)
221{
George Liu7a1dbc42022-12-07 16:03:22 +0800222 constexpr std::array<std::string_view, 1> interfaces = {
223 certs::certPropIntf};
224 dbus::utility::getSubTreePaths(
225 basePath, 0, interfaces,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800226 [asyncResp, listPtr, countPtr](
George Liu7a1dbc42022-12-07 16:03:22 +0800227 const boost::system::error_code& ec,
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800228 const dbus::utility::MapperGetSubTreePathsResponse& certPaths) {
229 if (ec)
230 {
Ed Tanous62598e32023-07-17 17:06:25 -0700231 BMCWEB_LOG_ERROR("Certificate collection query failed: {}", ec);
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800232 messages::internalError(asyncResp->res);
233 return;
234 }
235
236 nlohmann::json& links = asyncResp->res.jsonValue[listPtr];
237 links = nlohmann::json::array();
238 for (const auto& certPath : certPaths)
239 {
240 sdbusplus::message::object_path objPath(certPath);
241 std::string certId = objPath.filename();
242 if (certId.empty())
243 {
Ed Tanous62598e32023-07-17 17:06:25 -0700244 BMCWEB_LOG_ERROR("Invalid certificate objPath {}", certPath);
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800245 continue;
246 }
247
248 boost::urls::url certURL;
249 if (objPath.parent_path() == certs::httpsObjectPath)
250 {
Ed Tanousef4c65b2023-04-24 15:28:50 -0700251 certURL = boost::urls::format(
252 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}",
253 certId);
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800254 }
255 else if (objPath.parent_path() == certs::ldapObjectPath)
256 {
Ed Tanousef4c65b2023-04-24 15:28:50 -0700257 certURL = boost::urls::format(
258 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800259 }
260 else if (objPath.parent_path() == certs::authorityObjectPath)
261 {
Ed Tanousef4c65b2023-04-24 15:28:50 -0700262 certURL = boost::urls::format(
263 "/redfish/v1/Managers/bmc/Truststore/Certificates/{}",
264 certId);
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800265 }
266 else
267 {
268 continue;
269 }
270
271 nlohmann::json::object_t link;
272 link["@odata.id"] = certURL;
273 links.emplace_back(std::move(link));
274 }
275
276 asyncResp->res.jsonValue[countPtr] = links.size();
Patrick Williams5a39f772023-10-20 11:20:21 -0500277 });
Jiaqing Zhaod3f92ce2022-06-03 11:46:12 +0800278}
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{
Ed Tanous62598e32023-07-17 17:06:25 -0700297 BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}",
298 objectPath, certId, 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,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800302 name](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800303 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700304 if (ec)
305 {
Ed Tanous62598e32023-07-17 17:06:25 -0700306 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()));
Patrick Williams5a39f772023-10-20 11:20:21 -0500376 });
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,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800386 id{objectPath.filename()}](const boost::system::error_code& ec) {
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800387 if (ec)
388 {
389 messages::resourceNotFound(asyncResp->res, "Certificate", id);
390 return;
391 }
Ed Tanous62598e32023-07-17 17:06:25 -0700392 BMCWEB_LOG_INFO("Certificate deleted");
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800393 asyncResp->res.result(boost::beast::http::status::no_content);
Patrick Williams5a39f772023-10-20 11:20:21 -0500394 },
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800395 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
Ninad Palsule3e72c202023-03-27 17:19:55 -0500407 if (req.session == nullptr)
408 {
409 messages::internalError(asyncResp->res);
410 return;
411 }
412
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800413 asyncResp->res.jsonValue["@odata.type"] =
414 "#CertificateService.v1_0_0.CertificateService";
415 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService";
416 asyncResp->res.jsonValue["Id"] = "CertificateService";
417 asyncResp->res.jsonValue["Name"] = "Certificate Service";
418 asyncResp->res.jsonValue["Description"] =
419 "Actions available to manage certificates";
420 // /redfish/v1/CertificateService/CertificateLocations is something
421 // only ConfigureManager can access then only display when the user
422 // has permissions ConfigureManager
423 Privileges effectiveUserPrivileges =
Ninad Palsule3e72c202023-03-27 17:19:55 -0500424 redfish::getUserPrivileges(*req.session);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800425 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
426 effectiveUserPrivileges))
427 {
428 asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] =
429 "/redfish/v1/CertificateService/CertificateLocations";
430 }
431 nlohmann::json& actions = asyncResp->res.jsonValue["Actions"];
432 nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"];
433 replace["target"] =
434 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate";
435 nlohmann::json::array_t allowed;
Patrick Williamsad539542023-05-12 10:10:08 -0500436 allowed.emplace_back("PEM");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800437 replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed);
438 actions["#CertificateService.GenerateCSR"]["target"] =
439 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR";
440}
441
442inline void handleCertificateLocationsGet(
443 App& app, const crow::Request& req,
444 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
445{
446 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
447 {
448 return;
449 }
450 asyncResp->res.jsonValue["@odata.id"] =
451 "/redfish/v1/CertificateService/CertificateLocations";
452 asyncResp->res.jsonValue["@odata.type"] =
453 "#CertificateLocations.v1_0_0.CertificateLocations";
454 asyncResp->res.jsonValue["Name"] = "Certificate Locations";
455 asyncResp->res.jsonValue["Id"] = "CertificateLocations";
456 asyncResp->res.jsonValue["Description"] =
457 "Defines a resource that an administrator can use in order to "
458 "locate all certificates installed on a given service";
459
460 getCertificateList(asyncResp, certs::baseObjectPath,
461 "/Links/Certificates"_json_pointer,
462 "/Links/Certificates@odata.count"_json_pointer);
463}
464
465inline void handleReplaceCertificateAction(
466 App& app, const crow::Request& req,
467 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
468{
469 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
470 {
471 return;
472 }
473 std::string certificate;
Ed Tanous7a31e332024-03-06 12:17:43 -0800474 std::string certURI;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800475 std::optional<std::string> certificateType = "PEM";
476
477 if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
Ed Tanous7a31e332024-03-06 12:17:43 -0800478 certificate, "CertificateUri/@odata.id",
479 certURI, "CertificateType", certificateType))
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800480 {
Ed Tanous62598e32023-07-17 17:06:25 -0700481 BMCWEB_LOG_ERROR("Required parameters are missing");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800482 return;
483 }
484
485 if (!certificateType)
486 {
487 // should never happen, but it never hurts to be paranoid.
488 return;
489 }
490 if (certificateType != "PEM")
491 {
492 messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
493 "ReplaceCertificate");
494 return;
495 }
496
Ed Tanous62598e32023-07-17 17:06:25 -0700497 BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800498
Ed Tanous6fd29552023-10-04 09:40:14 -0700499 boost::system::result<boost::urls::url> parsedUrl =
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800500 boost::urls::parse_relative_ref(certURI);
501 if (!parsedUrl)
502 {
503 messages::actionParameterValueFormatError(
504 asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
505 return;
506 }
507
508 std::string id;
509 sdbusplus::message::object_path objectPath;
510 std::string name;
511 std::string service;
512 if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
513 "bmc", "NetworkProtocol", "HTTPS",
514 "Certificates", std::ref(id)))
515 {
Patrick Williams89492a12023-05-10 07:51:34 -0500516 objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) /
517 id;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800518 name = "HTTPS certificate";
519 service = certs::httpsServiceName;
520 }
521 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
522 "AccountService", "LDAP",
523 "Certificates", std::ref(id)))
524 {
Patrick Williams89492a12023-05-10 07:51:34 -0500525 objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) /
526 id;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800527 name = "LDAP certificate";
528 service = certs::ldapServiceName;
529 }
530 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
531 "Managers", "bmc", "Truststore",
532 "Certificates", std::ref(id)))
533 {
534 objectPath =
535 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
536 name = "TrustStore certificate";
537 service = certs::authorityServiceName;
538 }
539 else
540 {
541 messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
542 "ReplaceCertificate");
543 return;
544 }
545
546 std::shared_ptr<CertificateFile> certFile =
547 std::make_shared<CertificateFile>(certificate);
548 crow::connections::systemBus->async_method_call(
549 [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800550 name](const boost::system::error_code& ec) {
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800551 if (ec)
552 {
Ed Tanous62598e32023-07-17 17:06:25 -0700553 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800554 if (ec.value() ==
555 boost::system::linux_error::bad_request_descriptor)
556 {
557 messages::resourceNotFound(asyncResp->res, "Certificate", id);
558 return;
559 }
560 messages::internalError(asyncResp->res);
561 return;
562 }
563 getCertificateProperties(asyncResp, objectPath, service, id, url, name);
Ed Tanous62598e32023-07-17 17:06:25 -0700564 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
565 certFile->getCertFilePath());
Patrick Williams5a39f772023-10-20 11:20:21 -0500566 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800567 service, objectPath, certs::certReplaceIntf, "Replace",
568 certFile->getCertFilePath());
569}
570
Ed Tanouscf9e4172022-12-21 09:30:16 -0800571// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800572static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
573/**
574 * @brief Read data from CSR D-bus object and set to response
575 *
576 * @param[in] asyncResp Shared pointer to the response message
Ed Tanous8ece0e42024-01-02 13:16:50 -0800577 * @param[in] certURI Link to certificate collection URI
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800578 * @param[in] service D-Bus service name
579 * @param[in] certObjPath certificate D-Bus object path
580 * @param[in] csrObjPath CSR D-Bus object path
581 * @return None
582 */
583static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
584 const std::string& certURI, const std::string& service,
585 const std::string& certObjPath,
586 const std::string& csrObjPath)
587{
Ed Tanous62598e32023-07-17 17:06:25 -0700588 BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}",
589 certObjPath, csrObjPath, service);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800590 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800591 [asyncResp, certURI](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800592 const std::string& csr) {
593 if (ec)
594 {
Ed Tanous62598e32023-07-17 17:06:25 -0700595 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800596 messages::internalError(asyncResp->res);
597 return;
598 }
599 if (csr.empty())
600 {
Ed Tanous62598e32023-07-17 17:06:25 -0700601 BMCWEB_LOG_ERROR("CSR read is empty");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800602 messages::internalError(asyncResp->res);
603 return;
604 }
605 asyncResp->res.jsonValue["CSRString"] = csr;
606 asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
607 certURI;
Patrick Williams5a39f772023-10-20 11:20:21 -0500608 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800609 service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
610}
611
612inline void
613 handleGenerateCSRAction(App& app, const crow::Request& req,
614 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
615{
616 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
617 {
618 return;
619 }
620 static const int rsaKeyBitLength = 2048;
621
622 // Required parameters
623 std::string city;
624 std::string commonName;
625 std::string country;
626 std::string organization;
627 std::string organizationalUnit;
628 std::string state;
Ed Tanous7a31e332024-03-06 12:17:43 -0800629 std::string certURI;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800630
631 // Optional parameters
632 std::optional<std::vector<std::string>> optAlternativeNames =
633 std::vector<std::string>();
634 std::optional<std::string> optContactPerson = "";
635 std::optional<std::string> optChallengePassword = "";
636 std::optional<std::string> optEmail = "";
637 std::optional<std::string> optGivenName = "";
638 std::optional<std::string> optInitials = "";
639 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
640 std::optional<std::string> optKeyCurveId = "secp384r1";
641 std::optional<std::string> optKeyPairAlgorithm = "EC";
642 std::optional<std::vector<std::string>> optKeyUsage =
643 std::vector<std::string>();
644 std::optional<std::string> optSurname = "";
645 std::optional<std::string> optUnstructuredName = "";
646 if (!json_util::readJsonAction(
647 req, asyncResp->res, "City", city, "CommonName", commonName,
648 "ContactPerson", optContactPerson, "Country", country,
649 "Organization", organization, "OrganizationalUnit",
Ed Tanous7a31e332024-03-06 12:17:43 -0800650 organizationalUnit, "State", state,
651 "CertificateCollection/@odata.id", certURI, "AlternativeNames",
652 optAlternativeNames, "ChallengePassword", optChallengePassword,
653 "Email", optEmail, "GivenName", optGivenName, "Initials",
654 optInitials, "KeyBitLength", optKeyBitLength, "KeyCurveId",
655 optKeyCurveId, "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage",
656 optKeyUsage, "Surname", optSurname, "UnstructuredName",
657 optUnstructuredName))
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800658 {
659 return;
660 }
661
662 // bmcweb has no way to store or decode a private key challenge
663 // password, which will likely cause bmcweb to crash on startup
664 // if this is not set on a post so not allowing the user to set
665 // value
666 if (!optChallengePassword->empty())
667 {
668 messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
669 "ChallengePassword");
670 return;
671 }
672
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800673 std::string objectPath;
674 std::string service;
675 if (certURI.starts_with(
676 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
677 {
678 objectPath = certs::httpsObjectPath;
679 service = certs::httpsServiceName;
680 }
681 else if (certURI.starts_with(
682 "/redfish/v1/AccountService/LDAP/Certificates"))
683 {
684 objectPath = certs::ldapObjectPath;
685 service = certs::ldapServiceName;
686 }
687 else
688 {
689 messages::actionParameterNotSupported(
690 asyncResp->res, "CertificateCollection", "GenerateCSR");
691 return;
692 }
693
694 // supporting only EC and RSA algorithm
695 if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
696 {
697 messages::actionParameterNotSupported(
698 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
699 return;
700 }
701
702 // supporting only 2048 key bit length for RSA algorithm due to
703 // time consumed in generating private key
704 if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
705 {
Ed Tanouse2616cc2022-06-27 12:45:55 -0700706 messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
707 "KeyBitLength");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800708 return;
709 }
710
711 // validate KeyUsage supporting only 1 type based on URL
712 if (certURI.starts_with(
713 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
714 {
715 if (optKeyUsage->empty())
716 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500717 optKeyUsage->emplace_back("ServerAuthentication");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800718 }
719 else if (optKeyUsage->size() == 1)
720 {
721 if ((*optKeyUsage)[0] != "ServerAuthentication")
722 {
723 messages::propertyValueNotInList(asyncResp->res,
724 (*optKeyUsage)[0], "KeyUsage");
725 return;
726 }
727 }
728 else
729 {
730 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
731 "GenerateCSR");
732 return;
733 }
734 }
735 else if (certURI.starts_with(
736 "/redfish/v1/AccountService/LDAP/Certificates"))
737 {
738 if (optKeyUsage->empty())
739 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500740 optKeyUsage->emplace_back("ClientAuthentication");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800741 }
742 else if (optKeyUsage->size() == 1)
743 {
744 if ((*optKeyUsage)[0] != "ClientAuthentication")
745 {
746 messages::propertyValueNotInList(asyncResp->res,
747 (*optKeyUsage)[0], "KeyUsage");
748 return;
749 }
750 }
751 else
752 {
753 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
754 "GenerateCSR");
755 return;
756 }
757 }
758
759 // Only allow one CSR matcher at a time so setting retry
760 // time-out and timer expiry to 10 seconds for now.
761 static const int timeOut = 10;
762 if (csrMatcher)
763 {
764 messages::serviceTemporarilyUnavailable(asyncResp->res,
765 std::to_string(timeOut));
766 return;
767 }
768
Ed Tanous8e8245d2024-04-11 22:21:38 -0700769 if (req.ioService == nullptr)
770 {
771 messages::internalError(asyncResp->res);
772 return;
773 }
774
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800775 // Make this static so it survives outside this method
776 static boost::asio::steady_timer timeout(*req.ioService);
777 timeout.expires_after(std::chrono::seconds(timeOut));
778 timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
779 csrMatcher = nullptr;
780 if (ec)
781 {
782 // operation_aborted is expected if timer is canceled
783 // before completion.
784 if (ec != boost::asio::error::operation_aborted)
785 {
Ed Tanous62598e32023-07-17 17:06:25 -0700786 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800787 }
788 return;
789 }
Ed Tanous62598e32023-07-17 17:06:25 -0700790 BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800791 messages::internalError(asyncResp->res);
792 });
793
794 // create a matcher to wait on CSR object
Ed Tanous62598e32023-07-17 17:06:25 -0700795 BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800796 std::string match("type='signal',"
797 "interface='org.freedesktop.DBus.ObjectManager',"
798 "path='" +
799 objectPath +
800 "',"
801 "member='InterfacesAdded'");
802 csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
803 *crow::connections::systemBus, match,
804 [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
805 timeout.cancel();
806 if (m.is_method_error())
807 {
Ed Tanous62598e32023-07-17 17:06:25 -0700808 BMCWEB_LOG_ERROR("Dbus method error!!!");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800809 messages::internalError(asyncResp->res);
810 return;
811 }
812
Michael Shen80f79a42023-08-24 13:41:53 +0000813 dbus::utility::DBusInterfacesMap interfacesProperties;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800814
815 sdbusplus::message::object_path csrObjectPath;
816 m.read(csrObjectPath, interfacesProperties);
Ed Tanous62598e32023-07-17 17:06:25 -0700817 BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800818 for (const auto& interface : interfacesProperties)
819 {
820 if (interface.first == "xyz.openbmc_project.Certs.CSR")
821 {
822 getCSR(asyncResp, certURI, service, objectPath,
823 csrObjectPath.str);
824 break;
825 }
826 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500827 });
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800828 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800829 [asyncResp](const boost::system::error_code& ec, const std::string&) {
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800830 if (ec)
831 {
Ed Tanous62598e32023-07-17 17:06:25 -0700832 BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800833 messages::internalError(asyncResp->res);
834 return;
835 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500836 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800837 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
838 "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
839 commonName, *optContactPerson, country, *optEmail, *optGivenName,
840 *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
841 *optKeyUsage, organization, organizationalUnit, state, *optSurname,
842 *optUnstructuredName);
843}
844
845inline void requestRoutesCertificateService(App& app)
846{
847 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
848 .privileges(redfish::privileges::getCertificateService)
849 .methods(boost::beast::http::verb::get)(
850 std::bind_front(handleCertificateServiceGet, std::ref(app)));
851
852 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
853 .privileges(redfish::privileges::getCertificateLocations)
854 .methods(boost::beast::http::verb::get)(
855 std::bind_front(handleCertificateLocationsGet, std::ref(app)));
856
George Liu0fda0f12021-11-16 10:06:17 +0800857 BMCWEB_ROUTE(
858 app,
859 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
Ed Tanoused398212021-06-09 17:05:54 -0700860 .privileges(redfish::privileges::postCertificateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700861 .methods(boost::beast::http::verb::post)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800862 std::bind_front(handleReplaceCertificateAction, std::ref(app)));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600863
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800864 BMCWEB_ROUTE(
865 app,
866 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
867 .privileges(redfish::privileges::postCertificateService)
868 .methods(boost::beast::http::verb::post)(
869 std::bind_front(handleGenerateCSRAction, std::ref(app)));
870} // requestRoutesCertificateService
871
872inline void handleHTTPSCertificateCollectionGet(
873 App& app, const crow::Request& req,
874 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
875{
876 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
877 {
878 return;
879 }
880
881 asyncResp->res.jsonValue["@odata.id"] =
882 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
883 asyncResp->res.jsonValue["@odata.type"] =
884 "#CertificateCollection.CertificateCollection";
885 asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
886 asyncResp->res.jsonValue["Description"] =
887 "A Collection of HTTPS certificate instances";
888
889 getCertificateList(asyncResp, certs::httpsObjectPath,
890 "/Members"_json_pointer,
891 "/Members@odata.count"_json_pointer);
892}
893
894inline void handleHTTPSCertificateCollectionPost(
895 App& app, const crow::Request& req,
896 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
897{
898 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
899 {
900 return;
901 }
Ed Tanous62598e32023-07-17 17:06:25 -0700902 BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800903
904 asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
905 asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
906
Ed Tanousb2896142024-01-31 15:25:47 -0800907 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800908
Ed Tanousb2896142024-01-31 15:25:47 -0800909 if (certHttpBody.empty())
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800910 {
Ed Tanous62598e32023-07-17 17:06:25 -0700911 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800912 messages::unrecognizedRequestBody(asyncResp->res);
913 return;
914 }
915
916 std::shared_ptr<CertificateFile> certFile =
Ed Tanousb2896142024-01-31 15:25:47 -0800917 std::make_shared<CertificateFile>(certHttpBody);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800918
919 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800920 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800921 const std::string& objectPath) {
922 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700923 {
Ed Tanous62598e32023-07-17 17:06:25 -0700924 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700925 messages::internalError(asyncResp->res);
926 return;
927 }
928
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800929 sdbusplus::message::object_path path(objectPath);
930 std::string certId = path.filename();
Ed Tanousef4c65b2023-04-24 15:28:50 -0700931 const boost::urls::url certURL = boost::urls::format(
932 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}",
933 certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800934 getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
935 certId, certURL, "HTTPS Certificate");
Ed Tanous62598e32023-07-17 17:06:25 -0700936 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
937 certFile->getCertFilePath());
Patrick Williams5a39f772023-10-20 11:20:21 -0500938 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800939 certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
940 "Install", certFile->getCertFilePath());
941}
Ed Tanous002d39b2022-05-31 08:59:27 -0700942
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800943inline void handleHTTPSCertificateGet(
944 App& app, const crow::Request& req,
945 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
946{
947 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
948 {
949 return;
950 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700951
Ed Tanous62598e32023-07-17 17:06:25 -0700952 BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", id);
Ed Tanousef4c65b2023-04-24 15:28:50 -0700953 const boost::urls::url certURL = boost::urls::format(
954 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800955 std::string objPath =
956 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
957 getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
958 certURL, "HTTPS Certificate");
959}
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700960
961inline void requestRoutesHTTPSCertificate(App& app)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600962{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800963 BMCWEB_ROUTE(app,
964 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
965 .privileges(redfish::privileges::getCertificateCollection)
966 .methods(boost::beast::http::verb::get)(std::bind_front(
967 handleHTTPSCertificateCollectionGet, std::ref(app)));
968
969 BMCWEB_ROUTE(app,
970 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
971 .privileges(redfish::privileges::postCertificateCollection)
972 .methods(boost::beast::http::verb::post)(std::bind_front(
973 handleHTTPSCertificateCollectionPost, std::ref(app)));
974
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700975 BMCWEB_ROUTE(
976 app,
977 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700978 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800979 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800980 std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700981}
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600982
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800983inline void handleLDAPCertificateCollectionGet(
984 App& app, const crow::Request& req,
985 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600986{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800987 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
988 {
989 return;
990 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700991
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800992 asyncResp->res.jsonValue["@odata.id"] =
993 "/redfish/v1/AccountService/LDAP/Certificates";
994 asyncResp->res.jsonValue["@odata.type"] =
995 "#CertificateCollection.CertificateCollection";
996 asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
997 asyncResp->res.jsonValue["Description"] =
998 "A Collection of LDAP certificate instances";
Ed Tanous002d39b2022-05-31 08:59:27 -0700999
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001000 getCertificateList(asyncResp, certs::ldapObjectPath,
1001 "/Members"_json_pointer,
1002 "/Members@odata.count"_json_pointer);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001003}
Marri Devender Rao37cce912019-02-20 01:05:22 -06001004
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001005inline void handleLDAPCertificateCollectionPost(
1006 App& app, const crow::Request& req,
1007 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001008{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001009 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1010 {
1011 return;
1012 }
Ed Tanousb2896142024-01-31 15:25:47 -08001013 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001014
Ed Tanousb2896142024-01-31 15:25:47 -08001015 if (certHttpBody.empty())
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001016 {
Ed Tanous62598e32023-07-17 17:06:25 -07001017 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001018 messages::unrecognizedRequestBody(asyncResp->res);
1019 return;
1020 }
1021
1022 std::shared_ptr<CertificateFile> certFile =
Ed Tanousb2896142024-01-31 15:25:47 -08001023 std::make_shared<CertificateFile>(certHttpBody);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001024
1025 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001026 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001027 const std::string& objectPath) {
1028 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001029 {
Ed Tanous62598e32023-07-17 17:06:25 -07001030 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001031 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001032 return;
1033 }
1034
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001035 sdbusplus::message::object_path path(objectPath);
1036 std::string certId = path.filename();
Ed Tanousef4c65b2023-04-24 15:28:50 -07001037 const boost::urls::url certURL = boost::urls::format(
1038 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001039 getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1040 certId, certURL, "LDAP Certificate");
Ed Tanous62598e32023-07-17 17:06:25 -07001041 BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
1042 certFile->getCertFilePath());
Patrick Williams5a39f772023-10-20 11:20:21 -05001043 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001044 certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1045 "Install", certFile->getCertFilePath());
1046}
Ed Tanous002d39b2022-05-31 08:59:27 -07001047
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001048inline void handleLDAPCertificateGet(
1049 App& app, const crow::Request& req,
1050 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1051{
1052 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1053 {
1054 return;
1055 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001056
Ed Tanous62598e32023-07-17 17:06:25 -07001057 BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
Ed Tanousef4c65b2023-04-24 15:28:50 -07001058 const boost::urls::url certURL = boost::urls::format(
1059 "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001060 std::string objPath =
1061 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1062 getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1063 certURL, "LDAP Certificate");
1064}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001065
Jiaqing Zhao99612242022-09-29 15:31:09 +08001066inline void handleLDAPCertificateDelete(
1067 App& app, const crow::Request& req,
1068 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1069{
1070 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1071 {
1072 return;
1073 }
1074
Ed Tanous62598e32023-07-17 17:06:25 -07001075 BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
Jiaqing Zhao99612242022-09-29 15:31:09 +08001076 std::string objPath =
1077 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1078
1079 deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
1080}
1081
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001082inline void requestRoutesLDAPCertificate(App& app)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001083{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001084 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1085 .privileges(redfish::privileges::getCertificateCollection)
1086 .methods(boost::beast::http::verb::get)(
1087 std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1088
1089 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1090 .privileges(redfish::privileges::postCertificateCollection)
1091 .methods(boost::beast::http::verb::post)(std::bind_front(
1092 handleLDAPCertificateCollectionPost, std::ref(app)));
1093
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001094 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001095 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001096 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001097 std::bind_front(handleLDAPCertificateGet, std::ref(app)));
Jiaqing Zhao99612242022-09-29 15:31:09 +08001098
1099 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1100 .privileges(redfish::privileges::deleteCertificate)
1101 .methods(boost::beast::http::verb::delete_)(
1102 std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001103} // requestRoutesLDAPCertificate
1104
1105inline void handleTrustStoreCertificateCollectionGet(
1106 App& app, const crow::Request& req,
1107 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1108{
1109 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1110 {
1111 return;
1112 }
1113
1114 asyncResp->res.jsonValue["@odata.id"] =
1115 "/redfish/v1/Managers/bmc/Truststore/Certificates/";
1116 asyncResp->res.jsonValue["@odata.type"] =
1117 "#CertificateCollection.CertificateCollection";
1118 asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
1119 asyncResp->res.jsonValue["Description"] =
1120 "A Collection of TrustStore certificate instances";
1121
1122 getCertificateList(asyncResp, certs::authorityObjectPath,
1123 "/Members"_json_pointer,
1124 "/Members@odata.count"_json_pointer);
1125}
1126
1127inline void handleTrustStoreCertificateCollectionPost(
1128 App& app, const crow::Request& req,
1129 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1130{
1131 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1132 {
1133 return;
1134 }
Ed Tanousb2896142024-01-31 15:25:47 -08001135 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001136
Ed Tanousb2896142024-01-31 15:25:47 -08001137 if (certHttpBody.empty())
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001138 {
Ed Tanous62598e32023-07-17 17:06:25 -07001139 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001140 messages::unrecognizedRequestBody(asyncResp->res);
1141 return;
1142 }
1143
1144 std::shared_ptr<CertificateFile> certFile =
Ed Tanousb2896142024-01-31 15:25:47 -08001145 std::make_shared<CertificateFile>(certHttpBody);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001146 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001147 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001148 const std::string& objectPath) {
1149 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001150 {
Ed Tanous62598e32023-07-17 17:06:25 -07001151 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001152 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001153 return;
1154 }
Jiaqing Zhao717b9802022-06-06 20:24:04 +08001155
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001156 sdbusplus::message::object_path path(objectPath);
1157 std::string certId = path.filename();
Ed Tanousef4c65b2023-04-24 15:28:50 -07001158 const boost::urls::url certURL = boost::urls::format(
1159 "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001160 getCertificateProperties(asyncResp, objectPath,
1161 certs::authorityServiceName, certId, certURL,
1162 "TrustStore Certificate");
Ed Tanous62598e32023-07-17 17:06:25 -07001163 BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
1164 certFile->getCertFilePath());
Patrick Williams5a39f772023-10-20 11:20:21 -05001165 },
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001166 certs::authorityServiceName, certs::authorityObjectPath,
1167 certs::certInstallIntf, "Install", certFile->getCertFilePath());
1168}
1169
1170inline void handleTrustStoreCertificateGet(
1171 App& app, const crow::Request& req,
1172 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1173{
1174 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1175 {
1176 return;
1177 }
1178
Ed Tanous62598e32023-07-17 17:06:25 -07001179 BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", id);
Ed Tanousef4c65b2023-04-24 15:28:50 -07001180 const boost::urls::url certURL = boost::urls::format(
1181 "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001182 std::string objPath =
1183 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1184 getCertificateProperties(asyncResp, objPath, certs::authorityServiceName,
1185 id, certURL, "TrustStore Certificate");
1186}
1187
1188inline void handleTrustStoreCertificateDelete(
1189 App& app, const crow::Request& req,
1190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1191{
1192 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1193 {
1194 return;
1195 }
1196
Ed Tanous62598e32023-07-17 17:06:25 -07001197 BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001198 std::string objPath =
1199 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
1200
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +08001201 deleteCertificate(asyncResp, certs::authorityServiceName, objPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001202}
1203
1204inline void requestRoutesTrustStoreCertificate(App& app)
Marri Devender Raocfcd5f62019-05-17 08:34:37 -05001205{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001206 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001207 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001208 .methods(boost::beast::http::verb::get)(std::bind_front(
1209 handleTrustStoreCertificateCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001210
1211 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/")
Ed Tanoused398212021-06-09 17:05:54 -07001212 .privileges(redfish::privileges::postCertificateCollection)
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001213 .methods(boost::beast::http::verb::post)(std::bind_front(
1214 handleTrustStoreCertificateCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07001215
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001216 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001217 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001218 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001219 std::bind_front(handleTrustStoreCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001220
1221 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001222 .privileges(redfish::privileges::deleteCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001223 .methods(boost::beast::http::verb::delete_)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001224 std::bind_front(handleTrustStoreCertificateDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001225} // requestRoutesTrustStoreCertificate
Marri Devender Rao5968cae2019-01-21 10:27:12 -06001226} // namespace redfish