blob: 44005966c7c53d46afa9e0f6d4e0a58a9e80319e [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();
George Liu7a1dbc42022-12-07 16:03:22 +0800277 });
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()));
Krzysztof Grobelny9b12d1f2022-08-11 09:52:56 +0200376 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600377}
378
Jiaqing Zhao7a3a8f72022-09-29 15:15:58 +0800379static void
380 deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
381 const std::string& service,
382 const sdbusplus::message::object_path& objectPath)
383{
384 crow::connections::systemBus->async_method_call(
385 [asyncResp,
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);
394 },
395 service, objectPath, certs::objDeleteIntf, "Delete");
396}
397
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800398inline void handleCertificateServiceGet(
399 App& app, const crow::Request& req,
400 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600401{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800402 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
403 {
404 return;
405 }
406
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;
474 nlohmann::json certificateUri;
475 std::optional<std::string> certificateType = "PEM";
476
477 if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString",
478 certificate, "CertificateUri",
479 certificateUri, "CertificateType",
480 certificateType))
481 {
Ed Tanous62598e32023-07-17 17:06:25 -0700482 BMCWEB_LOG_ERROR("Required parameters are missing");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800483 return;
484 }
485
486 if (!certificateType)
487 {
488 // should never happen, but it never hurts to be paranoid.
489 return;
490 }
491 if (certificateType != "PEM")
492 {
493 messages::actionParameterNotSupported(asyncResp->res, "CertificateType",
494 "ReplaceCertificate");
495 return;
496 }
497
498 std::string certURI;
499 if (!redfish::json_util::readJson(certificateUri, asyncResp->res,
500 "@odata.id", certURI))
501 {
502 messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate",
503 "CertificateUri");
504 return;
505 }
Ed Tanous62598e32023-07-17 17:06:25 -0700506 BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800507
Xinnan Xief5f8eaa2023-09-04 17:02:36 +0800508 boost::urls::result<boost::urls::url> parsedUrl =
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800509 boost::urls::parse_relative_ref(certURI);
510 if (!parsedUrl)
511 {
512 messages::actionParameterValueFormatError(
513 asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate");
514 return;
515 }
516
517 std::string id;
518 sdbusplus::message::object_path objectPath;
519 std::string name;
520 std::string service;
521 if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers",
522 "bmc", "NetworkProtocol", "HTTPS",
523 "Certificates", std::ref(id)))
524 {
Patrick Williams89492a12023-05-10 07:51:34 -0500525 objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) /
526 id;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800527 name = "HTTPS certificate";
528 service = certs::httpsServiceName;
529 }
530 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
531 "AccountService", "LDAP",
532 "Certificates", std::ref(id)))
533 {
Patrick Williams89492a12023-05-10 07:51:34 -0500534 objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) /
535 id;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800536 name = "LDAP certificate";
537 service = certs::ldapServiceName;
538 }
539 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1",
540 "Managers", "bmc", "Truststore",
541 "Certificates", std::ref(id)))
542 {
543 objectPath =
544 sdbusplus::message::object_path(certs::authorityObjectPath) / id;
545 name = "TrustStore certificate";
546 service = certs::authorityServiceName;
547 }
548 else
549 {
550 messages::actionParameterNotSupported(asyncResp->res, "CertificateUri",
551 "ReplaceCertificate");
552 return;
553 }
554
555 std::shared_ptr<CertificateFile> certFile =
556 std::make_shared<CertificateFile>(certificate);
557 crow::connections::systemBus->async_method_call(
558 [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800559 name](const boost::system::error_code& ec) {
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800560 if (ec)
561 {
Ed Tanous62598e32023-07-17 17:06:25 -0700562 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800563 if (ec.value() ==
564 boost::system::linux_error::bad_request_descriptor)
565 {
566 messages::resourceNotFound(asyncResp->res, "Certificate", id);
567 return;
568 }
569 messages::internalError(asyncResp->res);
570 return;
571 }
572 getCertificateProperties(asyncResp, objectPath, service, id, url, name);
Ed Tanous62598e32023-07-17 17:06:25 -0700573 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
574 certFile->getCertFilePath());
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800575 },
576 service, objectPath, certs::certReplaceIntf, "Replace",
577 certFile->getCertFilePath());
578}
579
Ed Tanouscf9e4172022-12-21 09:30:16 -0800580// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800581static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher;
582/**
583 * @brief Read data from CSR D-bus object and set to response
584 *
585 * @param[in] asyncResp Shared pointer to the response message
586 * @param[in] certURI Link to certifiate collection URI
587 * @param[in] service D-Bus service name
588 * @param[in] certObjPath certificate D-Bus object path
589 * @param[in] csrObjPath CSR D-Bus object path
590 * @return None
591 */
592static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
593 const std::string& certURI, const std::string& service,
594 const std::string& certObjPath,
595 const std::string& csrObjPath)
596{
Ed Tanous62598e32023-07-17 17:06:25 -0700597 BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}",
598 certObjPath, csrObjPath, service);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800599 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800600 [asyncResp, certURI](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800601 const std::string& csr) {
602 if (ec)
603 {
Ed Tanous62598e32023-07-17 17:06:25 -0700604 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800605 messages::internalError(asyncResp->res);
606 return;
607 }
608 if (csr.empty())
609 {
Ed Tanous62598e32023-07-17 17:06:25 -0700610 BMCWEB_LOG_ERROR("CSR read is empty");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800611 messages::internalError(asyncResp->res);
612 return;
613 }
614 asyncResp->res.jsonValue["CSRString"] = csr;
615 asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] =
616 certURI;
617 },
618 service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR");
619}
620
621inline void
622 handleGenerateCSRAction(App& app, const crow::Request& req,
623 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
624{
625 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
626 {
627 return;
628 }
629 static const int rsaKeyBitLength = 2048;
630
631 // Required parameters
632 std::string city;
633 std::string commonName;
634 std::string country;
635 std::string organization;
636 std::string organizationalUnit;
637 std::string state;
638 nlohmann::json certificateCollection;
639
640 // Optional parameters
641 std::optional<std::vector<std::string>> optAlternativeNames =
642 std::vector<std::string>();
643 std::optional<std::string> optContactPerson = "";
644 std::optional<std::string> optChallengePassword = "";
645 std::optional<std::string> optEmail = "";
646 std::optional<std::string> optGivenName = "";
647 std::optional<std::string> optInitials = "";
648 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength;
649 std::optional<std::string> optKeyCurveId = "secp384r1";
650 std::optional<std::string> optKeyPairAlgorithm = "EC";
651 std::optional<std::vector<std::string>> optKeyUsage =
652 std::vector<std::string>();
653 std::optional<std::string> optSurname = "";
654 std::optional<std::string> optUnstructuredName = "";
655 if (!json_util::readJsonAction(
656 req, asyncResp->res, "City", city, "CommonName", commonName,
657 "ContactPerson", optContactPerson, "Country", country,
658 "Organization", organization, "OrganizationalUnit",
659 organizationalUnit, "State", state, "CertificateCollection",
660 certificateCollection, "AlternativeNames", optAlternativeNames,
661 "ChallengePassword", optChallengePassword, "Email", optEmail,
662 "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength",
663 optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm",
664 optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname,
665 "UnstructuredName", optUnstructuredName))
666 {
667 return;
668 }
669
670 // bmcweb has no way to store or decode a private key challenge
671 // password, which will likely cause bmcweb to crash on startup
672 // if this is not set on a post so not allowing the user to set
673 // value
674 if (!optChallengePassword->empty())
675 {
676 messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR",
677 "ChallengePassword");
678 return;
679 }
680
681 std::string certURI;
682 if (!redfish::json_util::readJson(certificateCollection, asyncResp->res,
683 "@odata.id", certURI))
684 {
685 return;
686 }
687
688 std::string objectPath;
689 std::string service;
690 if (certURI.starts_with(
691 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
692 {
693 objectPath = certs::httpsObjectPath;
694 service = certs::httpsServiceName;
695 }
696 else if (certURI.starts_with(
697 "/redfish/v1/AccountService/LDAP/Certificates"))
698 {
699 objectPath = certs::ldapObjectPath;
700 service = certs::ldapServiceName;
701 }
702 else
703 {
704 messages::actionParameterNotSupported(
705 asyncResp->res, "CertificateCollection", "GenerateCSR");
706 return;
707 }
708
709 // supporting only EC and RSA algorithm
710 if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA")
711 {
712 messages::actionParameterNotSupported(
713 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR");
714 return;
715 }
716
717 // supporting only 2048 key bit length for RSA algorithm due to
718 // time consumed in generating private key
719 if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength)
720 {
Ed Tanouse2616cc2022-06-27 12:45:55 -0700721 messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength,
722 "KeyBitLength");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800723 return;
724 }
725
726 // validate KeyUsage supporting only 1 type based on URL
727 if (certURI.starts_with(
728 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"))
729 {
730 if (optKeyUsage->empty())
731 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500732 optKeyUsage->emplace_back("ServerAuthentication");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800733 }
734 else if (optKeyUsage->size() == 1)
735 {
736 if ((*optKeyUsage)[0] != "ServerAuthentication")
737 {
738 messages::propertyValueNotInList(asyncResp->res,
739 (*optKeyUsage)[0], "KeyUsage");
740 return;
741 }
742 }
743 else
744 {
745 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
746 "GenerateCSR");
747 return;
748 }
749 }
750 else if (certURI.starts_with(
751 "/redfish/v1/AccountService/LDAP/Certificates"))
752 {
753 if (optKeyUsage->empty())
754 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500755 optKeyUsage->emplace_back("ClientAuthentication");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800756 }
757 else if (optKeyUsage->size() == 1)
758 {
759 if ((*optKeyUsage)[0] != "ClientAuthentication")
760 {
761 messages::propertyValueNotInList(asyncResp->res,
762 (*optKeyUsage)[0], "KeyUsage");
763 return;
764 }
765 }
766 else
767 {
768 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage",
769 "GenerateCSR");
770 return;
771 }
772 }
773
774 // Only allow one CSR matcher at a time so setting retry
775 // time-out and timer expiry to 10 seconds for now.
776 static const int timeOut = 10;
777 if (csrMatcher)
778 {
779 messages::serviceTemporarilyUnavailable(asyncResp->res,
780 std::to_string(timeOut));
781 return;
782 }
783
784 // Make this static so it survives outside this method
785 static boost::asio::steady_timer timeout(*req.ioService);
786 timeout.expires_after(std::chrono::seconds(timeOut));
787 timeout.async_wait([asyncResp](const boost::system::error_code& ec) {
788 csrMatcher = nullptr;
789 if (ec)
790 {
791 // operation_aborted is expected if timer is canceled
792 // before completion.
793 if (ec != boost::asio::error::operation_aborted)
794 {
Ed Tanous62598e32023-07-17 17:06:25 -0700795 BMCWEB_LOG_ERROR("Async_wait failed {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800796 }
797 return;
798 }
Ed Tanous62598e32023-07-17 17:06:25 -0700799 BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800800 messages::internalError(asyncResp->res);
801 });
802
803 // create a matcher to wait on CSR object
Ed Tanous62598e32023-07-17 17:06:25 -0700804 BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800805 std::string match("type='signal',"
806 "interface='org.freedesktop.DBus.ObjectManager',"
807 "path='" +
808 objectPath +
809 "',"
810 "member='InterfacesAdded'");
811 csrMatcher = std::make_unique<sdbusplus::bus::match_t>(
812 *crow::connections::systemBus, match,
813 [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) {
814 timeout.cancel();
815 if (m.is_method_error())
816 {
Ed Tanous62598e32023-07-17 17:06:25 -0700817 BMCWEB_LOG_ERROR("Dbus method error!!!");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800818 messages::internalError(asyncResp->res);
819 return;
820 }
821
Michael Shen80f79a42023-08-24 13:41:53 +0000822 dbus::utility::DBusInterfacesMap interfacesProperties;
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800823
824 sdbusplus::message::object_path csrObjectPath;
825 m.read(csrObjectPath, interfacesProperties);
Ed Tanous62598e32023-07-17 17:06:25 -0700826 BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800827 for (const auto& interface : interfacesProperties)
828 {
829 if (interface.first == "xyz.openbmc_project.Certs.CSR")
830 {
831 getCSR(asyncResp, certURI, service, objectPath,
832 csrObjectPath.str);
833 break;
834 }
835 }
836 });
837 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800838 [asyncResp](const boost::system::error_code& ec, const std::string&) {
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800839 if (ec)
840 {
Ed Tanous62598e32023-07-17 17:06:25 -0700841 BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message());
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800842 messages::internalError(asyncResp->res);
843 return;
844 }
845 },
846 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create",
847 "GenerateCSR", *optAlternativeNames, *optChallengePassword, city,
848 commonName, *optContactPerson, country, *optEmail, *optGivenName,
849 *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm,
850 *optKeyUsage, organization, organizationalUnit, state, *optSurname,
851 *optUnstructuredName);
852}
853
854inline void requestRoutesCertificateService(App& app)
855{
856 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/")
857 .privileges(redfish::privileges::getCertificateService)
858 .methods(boost::beast::http::verb::get)(
859 std::bind_front(handleCertificateServiceGet, std::ref(app)));
860
861 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/")
862 .privileges(redfish::privileges::getCertificateLocations)
863 .methods(boost::beast::http::verb::get)(
864 std::bind_front(handleCertificateLocationsGet, std::ref(app)));
865
George Liu0fda0f12021-11-16 10:06:17 +0800866 BMCWEB_ROUTE(
867 app,
868 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/")
Ed Tanoused398212021-06-09 17:05:54 -0700869 .privileges(redfish::privileges::postCertificateService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700870 .methods(boost::beast::http::verb::post)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800871 std::bind_front(handleReplaceCertificateAction, std::ref(app)));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600872
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800873 BMCWEB_ROUTE(
874 app,
875 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/")
876 .privileges(redfish::privileges::postCertificateService)
877 .methods(boost::beast::http::verb::post)(
878 std::bind_front(handleGenerateCSRAction, std::ref(app)));
879} // requestRoutesCertificateService
880
881inline void handleHTTPSCertificateCollectionGet(
882 App& app, const crow::Request& req,
883 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
884{
885 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
886 {
887 return;
888 }
889
890 asyncResp->res.jsonValue["@odata.id"] =
891 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates";
892 asyncResp->res.jsonValue["@odata.type"] =
893 "#CertificateCollection.CertificateCollection";
894 asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection";
895 asyncResp->res.jsonValue["Description"] =
896 "A Collection of HTTPS certificate instances";
897
898 getCertificateList(asyncResp, certs::httpsObjectPath,
899 "/Members"_json_pointer,
900 "/Members@odata.count"_json_pointer);
901}
902
903inline void handleHTTPSCertificateCollectionPost(
904 App& app, const crow::Request& req,
905 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
906{
907 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
908 {
909 return;
910 }
Ed Tanous62598e32023-07-17 17:06:25 -0700911 BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800912
913 asyncResp->res.jsonValue["Name"] = "HTTPS Certificate";
914 asyncResp->res.jsonValue["Description"] = "HTTPS Certificate";
915
916 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
917
918 if (certFileBody.empty())
919 {
Ed Tanous62598e32023-07-17 17:06:25 -0700920 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800921 messages::unrecognizedRequestBody(asyncResp->res);
922 return;
923 }
924
925 std::shared_ptr<CertificateFile> certFile =
926 std::make_shared<CertificateFile>(certFileBody);
927
928 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800929 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800930 const std::string& objectPath) {
931 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700932 {
Ed Tanous62598e32023-07-17 17:06:25 -0700933 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700934 messages::internalError(asyncResp->res);
935 return;
936 }
937
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800938 sdbusplus::message::object_path path(objectPath);
939 std::string certId = path.filename();
Ed Tanousef4c65b2023-04-24 15:28:50 -0700940 const boost::urls::url certURL = boost::urls::format(
941 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}",
942 certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800943 getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName,
944 certId, certURL, "HTTPS Certificate");
Ed Tanous62598e32023-07-17 17:06:25 -0700945 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}",
946 certFile->getCertFilePath());
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800947 },
948 certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf,
949 "Install", certFile->getCertFilePath());
950}
Ed Tanous002d39b2022-05-31 08:59:27 -0700951
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800952inline void handleHTTPSCertificateGet(
953 App& app, const crow::Request& req,
954 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
955{
956 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
957 {
958 return;
959 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700960
Ed Tanous62598e32023-07-17 17:06:25 -0700961 BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", id);
Ed Tanousef4c65b2023-04-24 15:28:50 -0700962 const boost::urls::url certURL = boost::urls::format(
963 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800964 std::string objPath =
965 sdbusplus::message::object_path(certs::httpsObjectPath) / id;
966 getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id,
967 certURL, "HTTPS Certificate");
968}
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700969
970inline void requestRoutesHTTPSCertificate(App& app)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600971{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800972 BMCWEB_ROUTE(app,
973 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
974 .privileges(redfish::privileges::getCertificateCollection)
975 .methods(boost::beast::http::verb::get)(std::bind_front(
976 handleHTTPSCertificateCollectionGet, std::ref(app)));
977
978 BMCWEB_ROUTE(app,
979 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")
980 .privileges(redfish::privileges::postCertificateCollection)
981 .methods(boost::beast::http::verb::post)(std::bind_front(
982 handleHTTPSCertificateCollectionPost, std::ref(app)));
983
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700984 BMCWEB_ROUTE(
985 app,
986 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700987 .privileges(redfish::privileges::getCertificate)
Jiaqing Zhao1e312592022-06-14 12:58:09 +0800988 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800989 std::bind_front(handleHTTPSCertificateGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700990}
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600991
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800992inline void handleLDAPCertificateCollectionGet(
993 App& app, const crow::Request& req,
994 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600995{
Jiaqing Zhao828252d2022-09-30 13:59:19 +0800996 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
997 {
998 return;
999 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001000
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001001 asyncResp->res.jsonValue["@odata.id"] =
1002 "/redfish/v1/AccountService/LDAP/Certificates";
1003 asyncResp->res.jsonValue["@odata.type"] =
1004 "#CertificateCollection.CertificateCollection";
1005 asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection";
1006 asyncResp->res.jsonValue["Description"] =
1007 "A Collection of LDAP certificate instances";
Ed Tanous002d39b2022-05-31 08:59:27 -07001008
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001009 getCertificateList(asyncResp, certs::ldapObjectPath,
1010 "/Members"_json_pointer,
1011 "/Members@odata.count"_json_pointer);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001012}
Marri Devender Rao37cce912019-02-20 01:05:22 -06001013
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001014inline void handleLDAPCertificateCollectionPost(
1015 App& app, const crow::Request& req,
1016 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001017{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001018 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1019 {
1020 return;
1021 }
1022 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1023
1024 if (certFileBody.empty())
1025 {
Ed Tanous62598e32023-07-17 17:06:25 -07001026 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001027 messages::unrecognizedRequestBody(asyncResp->res);
1028 return;
1029 }
1030
1031 std::shared_ptr<CertificateFile> certFile =
1032 std::make_shared<CertificateFile>(certFileBody);
1033
1034 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001035 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001036 const std::string& objectPath) {
1037 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001038 {
Ed Tanous62598e32023-07-17 17:06:25 -07001039 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001040 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001041 return;
1042 }
1043
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001044 sdbusplus::message::object_path path(objectPath);
1045 std::string certId = path.filename();
Ed Tanousef4c65b2023-04-24 15:28:50 -07001046 const boost::urls::url certURL = boost::urls::format(
1047 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001048 getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName,
1049 certId, certURL, "LDAP Certificate");
Ed Tanous62598e32023-07-17 17:06:25 -07001050 BMCWEB_LOG_DEBUG("LDAP certificate install file={}",
1051 certFile->getCertFilePath());
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001052 },
1053 certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf,
1054 "Install", certFile->getCertFilePath());
1055}
Ed Tanous002d39b2022-05-31 08:59:27 -07001056
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001057inline void handleLDAPCertificateGet(
1058 App& app, const crow::Request& req,
1059 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1060{
1061 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1062 {
1063 return;
1064 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001065
Ed Tanous62598e32023-07-17 17:06:25 -07001066 BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id);
Ed Tanousef4c65b2023-04-24 15:28:50 -07001067 const boost::urls::url certURL = boost::urls::format(
1068 "/redfish/v1/AccountService/LDAP/Certificates/{}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001069 std::string objPath =
1070 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1071 getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id,
1072 certURL, "LDAP Certificate");
1073}
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001074
Jiaqing Zhao99612242022-09-29 15:31:09 +08001075inline void handleLDAPCertificateDelete(
1076 App& app, const crow::Request& req,
1077 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1078{
1079 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1080 {
1081 return;
1082 }
1083
Ed Tanous62598e32023-07-17 17:06:25 -07001084 BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id);
Jiaqing Zhao99612242022-09-29 15:31:09 +08001085 std::string objPath =
1086 sdbusplus::message::object_path(certs::ldapObjectPath) / id;
1087
1088 deleteCertificate(asyncResp, certs::ldapServiceName, objPath);
1089}
1090
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001091inline void requestRoutesLDAPCertificate(App& app)
Marri Devender Rao37cce912019-02-20 01:05:22 -06001092{
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001093 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1094 .privileges(redfish::privileges::getCertificateCollection)
1095 .methods(boost::beast::http::verb::get)(
1096 std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app)));
1097
1098 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/")
1099 .privileges(redfish::privileges::postCertificateCollection)
1100 .methods(boost::beast::http::verb::post)(std::bind_front(
1101 handleLDAPCertificateCollectionPost, std::ref(app)));
1102
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001103 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001104 .privileges(redfish::privileges::getCertificate)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001105 .methods(boost::beast::http::verb::get)(
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001106 std::bind_front(handleLDAPCertificateGet, std::ref(app)));
Jiaqing Zhao99612242022-09-29 15:31:09 +08001107
1108 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/")
1109 .privileges(redfish::privileges::deleteCertificate)
1110 .methods(boost::beast::http::verb::delete_)(
1111 std::bind_front(handleLDAPCertificateDelete, std::ref(app)));
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001112} // requestRoutesLDAPCertificate
1113
1114inline void handleTrustStoreCertificateCollectionGet(
1115 App& app, const crow::Request& req,
1116 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1117{
1118 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1119 {
1120 return;
1121 }
1122
1123 asyncResp->res.jsonValue["@odata.id"] =
1124 "/redfish/v1/Managers/bmc/Truststore/Certificates/";
1125 asyncResp->res.jsonValue["@odata.type"] =
1126 "#CertificateCollection.CertificateCollection";
1127 asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection";
1128 asyncResp->res.jsonValue["Description"] =
1129 "A Collection of TrustStore certificate instances";
1130
1131 getCertificateList(asyncResp, certs::authorityObjectPath,
1132 "/Members"_json_pointer,
1133 "/Members@odata.count"_json_pointer);
1134}
1135
1136inline void handleTrustStoreCertificateCollectionPost(
1137 App& app, const crow::Request& req,
1138 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1139{
1140 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1141 {
1142 return;
1143 }
1144 std::string certFileBody = getCertificateFromReqBody(asyncResp, req);
1145
1146 if (certFileBody.empty())
1147 {
Ed Tanous62598e32023-07-17 17:06:25 -07001148 BMCWEB_LOG_ERROR("Cannot get certificate from request body.");
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001149 messages::unrecognizedRequestBody(asyncResp->res);
1150 return;
1151 }
1152
1153 std::shared_ptr<CertificateFile> certFile =
1154 std::make_shared<CertificateFile>(certFileBody);
1155 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001156 [asyncResp, certFile](const boost::system::error_code& ec,
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001157 const std::string& objectPath) {
1158 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -07001159 {
Ed Tanous62598e32023-07-17 17:06:25 -07001160 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001161 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07001162 return;
1163 }
Jiaqing Zhao717b9802022-06-06 20:24:04 +08001164
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001165 sdbusplus::message::object_path path(objectPath);
1166 std::string certId = path.filename();
Ed Tanousef4c65b2023-04-24 15:28:50 -07001167 const boost::urls::url certURL = boost::urls::format(
1168 "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", certId);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001169 getCertificateProperties(asyncResp, objectPath,
1170 certs::authorityServiceName, certId, certURL,
1171 "TrustStore Certificate");
Ed Tanous62598e32023-07-17 17:06:25 -07001172 BMCWEB_LOG_DEBUG("TrustStore certificate install file={}",
1173 certFile->getCertFilePath());
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001174 },
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
Ed Tanous62598e32023-07-17 17:06:25 -07001188 BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", id);
Ed Tanousef4c65b2023-04-24 15:28:50 -07001189 const boost::urls::url certURL = boost::urls::format(
1190 "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001191 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
Ed Tanous62598e32023-07-17 17:06:25 -07001206 BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", id);
Jiaqing Zhao828252d2022-09-30 13:59:19 +08001207 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