1 #pragma once 2 3 #include "app.hpp" 4 #include "async_resp.hpp" 5 #include "dbus_utility.hpp" 6 #include "http/parsing.hpp" 7 #include "http_response.hpp" 8 #include "query.hpp" 9 #include "registries/privilege_registry.hpp" 10 #include "utils/dbus_utils.hpp" 11 #include "utils/json_utils.hpp" 12 #include "utils/time_utils.hpp" 13 14 #include <boost/system/linux_error.hpp> 15 #include <boost/url/format.hpp> 16 #include <sdbusplus/asio/property.hpp> 17 #include <sdbusplus/bus/match.hpp> 18 #include <sdbusplus/unpack_properties.hpp> 19 20 #include <array> 21 #include <memory> 22 #include <string_view> 23 24 namespace redfish 25 { 26 namespace certs 27 { 28 constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 29 constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 30 constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 31 constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 32 constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties"; 33 constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 34 constexpr const char* httpsServiceName = 35 "xyz.openbmc_project.Certs.Manager.Server.Https"; 36 constexpr const char* ldapServiceName = 37 "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 38 constexpr const char* authorityServiceName = 39 "xyz.openbmc_project.Certs.Manager.Authority.Truststore"; 40 constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs"; 41 constexpr const char* httpsObjectPath = 42 "/xyz/openbmc_project/certs/server/https"; 43 constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 44 constexpr const char* authorityObjectPath = 45 "/xyz/openbmc_project/certs/authority/truststore"; 46 } // 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 */ 53 54 inline std::string getCertificateFromReqBody( 55 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 56 const crow::Request& req) 57 { 58 nlohmann::json reqJson; 59 JsonParseResult ret = parseRequestAsJson(req, reqJson); 60 if (ret != JsonParseResult::Success) 61 { 62 // We did not receive JSON request, proceed as it is RAW data 63 return req.body(); 64 } 65 66 std::string certificate; 67 std::optional<std::string> certificateType = "PEM"; 68 69 if (!json_util::readJsonPatch( // 70 req, asyncResp->res, // 71 "CertificateString", certificate, // 72 "CertificateType", certificateType // 73 )) 74 { 75 BMCWEB_LOG_ERROR("Required parameters are missing"); 76 messages::internalError(asyncResp->res); 77 return {}; 78 } 79 80 if (*certificateType != "PEM") 81 { 82 messages::propertyValueNotInList(asyncResp->res, *certificateType, 83 "CertificateType"); 84 return {}; 85 } 86 87 return certificate; 88 } 89 90 /** 91 * Class to create a temporary certificate file for uploading to system 92 */ 93 class CertificateFile 94 { 95 public: 96 CertificateFile() = delete; 97 CertificateFile(const CertificateFile&) = delete; 98 CertificateFile& operator=(const CertificateFile&) = delete; 99 CertificateFile(CertificateFile&&) = delete; 100 CertificateFile& operator=(CertificateFile&&) = delete; 101 explicit CertificateFile(const std::string& certString) 102 { 103 std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 104 'e', 'r', 't', 's', '.', 'X', 105 'X', 'X', 'X', 'X', 'X', '\0'}; 106 char* tempDirectory = mkdtemp(dirTemplate.data()); 107 if (tempDirectory != nullptr) 108 { 109 certDirectory = tempDirectory; 110 certificateFile = certDirectory / "cert.pem"; 111 std::ofstream out(certificateFile, 112 std::ofstream::out | std::ofstream::binary | 113 std::ofstream::trunc); 114 out << certString; 115 out.close(); 116 BMCWEB_LOG_DEBUG("Creating certificate file{}", 117 certificateFile.string()); 118 } 119 } 120 ~CertificateFile() 121 { 122 if (std::filesystem::exists(certDirectory)) 123 { 124 BMCWEB_LOG_DEBUG("Removing certificate file{}", 125 certificateFile.string()); 126 std::error_code ec; 127 std::filesystem::remove_all(certDirectory, ec); 128 if (ec) 129 { 130 BMCWEB_LOG_ERROR("Failed to remove temp directory{}", 131 certDirectory.string()); 132 } 133 } 134 } 135 std::string getCertFilePath() 136 { 137 return certificateFile; 138 } 139 140 private: 141 std::filesystem::path certificateFile; 142 std::filesystem::path certDirectory; 143 }; 144 145 /** 146 * @brief Parse and update Certificate Issue/Subject property 147 * 148 * @param[in] asyncResp Shared pointer to the response message 149 * @param[in] str Issuer/Subject value in key=value pairs 150 * @param[in] type Issuer/Subject 151 * @return None 152 */ 153 inline void updateCertIssuerOrSubject(nlohmann::json& out, 154 std::string_view value) 155 { 156 // example: O=openbmc-project.xyz,CN=localhost 157 std::string_view::iterator i = value.begin(); 158 while (i != value.end()) 159 { 160 std::string_view::iterator tokenBegin = i; 161 while (i != value.end() && *i != '=') 162 { 163 std::advance(i, 1); 164 } 165 if (i == value.end()) 166 { 167 break; 168 } 169 std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin)); 170 std::advance(i, 1); 171 tokenBegin = i; 172 while (i != value.end() && *i != ',') 173 { 174 std::advance(i, 1); 175 } 176 std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin)); 177 if (key == "L") 178 { 179 out["City"] = val; 180 } 181 else if (key == "CN") 182 { 183 out["CommonName"] = val; 184 } 185 else if (key == "C") 186 { 187 out["Country"] = val; 188 } 189 else if (key == "O") 190 { 191 out["Organization"] = val; 192 } 193 else if (key == "OU") 194 { 195 out["OrganizationalUnit"] = val; 196 } 197 else if (key == "ST") 198 { 199 out["State"] = val; 200 } 201 // skip comma character 202 if (i != value.end()) 203 { 204 std::advance(i, 1); 205 } 206 } 207 } 208 209 /** 210 * @brief Retrieve the installed certificate list 211 * 212 * @param[in] asyncResp Shared pointer to the response message 213 * @param[in] basePath DBus object path to search 214 * @param[in] listPtr Json pointer to the list in asyncResp 215 * @param[in] countPtr Json pointer to the count in asyncResp 216 * @return None 217 */ 218 inline void getCertificateList( 219 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 220 const std::string& basePath, const nlohmann::json::json_pointer& listPtr, 221 const nlohmann::json::json_pointer& countPtr) 222 { 223 constexpr std::array<std::string_view, 1> interfaces = { 224 certs::certPropIntf}; 225 dbus::utility::getSubTreePaths( 226 basePath, 0, interfaces, 227 [asyncResp, listPtr, countPtr]( 228 const boost::system::error_code& ec, 229 const dbus::utility::MapperGetSubTreePathsResponse& certPaths) { 230 if (ec) 231 { 232 BMCWEB_LOG_ERROR("Certificate collection query failed: {}", ec); 233 messages::internalError(asyncResp->res); 234 return; 235 } 236 237 nlohmann::json& links = asyncResp->res.jsonValue[listPtr]; 238 links = nlohmann::json::array(); 239 for (const auto& certPath : certPaths) 240 { 241 sdbusplus::message::object_path objPath(certPath); 242 std::string certId = objPath.filename(); 243 if (certId.empty()) 244 { 245 BMCWEB_LOG_ERROR("Invalid certificate objPath {}", 246 certPath); 247 continue; 248 } 249 250 boost::urls::url certURL; 251 if (objPath.parent_path() == certs::httpsObjectPath) 252 { 253 certURL = boost::urls::format( 254 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 255 BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 256 } 257 else if (objPath.parent_path() == certs::ldapObjectPath) 258 { 259 certURL = boost::urls::format( 260 "/redfish/v1/AccountService/LDAP/Certificates/{}", 261 certId); 262 } 263 else if (objPath.parent_path() == certs::authorityObjectPath) 264 { 265 certURL = boost::urls::format( 266 "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 267 BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 268 } 269 else 270 { 271 continue; 272 } 273 274 nlohmann::json::object_t link; 275 link["@odata.id"] = certURL; 276 links.emplace_back(std::move(link)); 277 } 278 279 asyncResp->res.jsonValue[countPtr] = links.size(); 280 }); 281 } 282 283 /** 284 * @brief Retrieve the certificates properties and append to the response 285 * message 286 * 287 * @param[in] asyncResp Shared pointer to the response message 288 * @param[in] objectPath Path of the D-Bus service object 289 * @param[in] certId Id of the certificate 290 * @param[in] certURL URL of the certificate object 291 * @param[in] name name of the certificate 292 * @return None 293 */ 294 inline void getCertificateProperties( 295 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 296 const std::string& objectPath, const std::string& service, 297 const std::string& certId, const boost::urls::url& certURL, 298 const std::string& name) 299 { 300 BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}", 301 objectPath, certId, certURL); 302 dbus::utility::getAllProperties( 303 service, objectPath, certs::certPropIntf, 304 [asyncResp, certURL, certId, 305 name](const boost::system::error_code& ec, 306 const dbus::utility::DBusPropertiesMap& properties) { 307 if (ec) 308 { 309 BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 310 messages::resourceNotFound(asyncResp->res, "Certificate", 311 certId); 312 return; 313 } 314 315 const std::string* certificateString = nullptr; 316 const std::vector<std::string>* keyUsage = nullptr; 317 const std::string* issuer = nullptr; 318 const std::string* subject = nullptr; 319 const uint64_t* validNotAfter = nullptr; 320 const uint64_t* validNotBefore = nullptr; 321 322 const bool success = sdbusplus::unpackPropertiesNoThrow( 323 dbus_utils::UnpackErrorPrinter(), properties, 324 "CertificateString", certificateString, "KeyUsage", keyUsage, 325 "Issuer", issuer, "Subject", subject, "ValidNotAfter", 326 validNotAfter, "ValidNotBefore", validNotBefore); 327 328 if (!success) 329 { 330 messages::internalError(asyncResp->res); 331 return; 332 } 333 334 asyncResp->res.jsonValue["@odata.id"] = certURL; 335 asyncResp->res.jsonValue["@odata.type"] = 336 "#Certificate.v1_0_0.Certificate"; 337 asyncResp->res.jsonValue["Id"] = certId; 338 asyncResp->res.jsonValue["Name"] = name; 339 asyncResp->res.jsonValue["Description"] = name; 340 asyncResp->res.jsonValue["CertificateString"] = ""; 341 asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array(); 342 343 if (certificateString != nullptr) 344 { 345 asyncResp->res.jsonValue["CertificateString"] = 346 *certificateString; 347 } 348 349 if (keyUsage != nullptr) 350 { 351 asyncResp->res.jsonValue["KeyUsage"] = *keyUsage; 352 } 353 354 if (issuer != nullptr) 355 { 356 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"], 357 *issuer); 358 } 359 360 if (subject != nullptr) 361 { 362 updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"], 363 *subject); 364 } 365 366 if (validNotAfter != nullptr) 367 { 368 asyncResp->res.jsonValue["ValidNotAfter"] = 369 redfish::time_utils::getDateTimeUint(*validNotAfter); 370 } 371 372 if (validNotBefore != nullptr) 373 { 374 asyncResp->res.jsonValue["ValidNotBefore"] = 375 redfish::time_utils::getDateTimeUint(*validNotBefore); 376 } 377 378 asyncResp->res.addHeader( 379 boost::beast::http::field::location, 380 std::string_view(certURL.data(), certURL.size())); 381 }); 382 } 383 384 inline void 385 deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 386 const std::string& service, 387 const sdbusplus::message::object_path& objectPath) 388 { 389 crow::connections::systemBus->async_method_call( 390 [asyncResp, 391 id{objectPath.filename()}](const boost::system::error_code& ec) { 392 if (ec) 393 { 394 messages::resourceNotFound(asyncResp->res, "Certificate", id); 395 return; 396 } 397 BMCWEB_LOG_INFO("Certificate deleted"); 398 asyncResp->res.result(boost::beast::http::status::no_content); 399 }, 400 service, objectPath, certs::objDeleteIntf, "Delete"); 401 } 402 403 inline void handleCertificateServiceGet( 404 App& app, const crow::Request& req, 405 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 406 { 407 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 408 { 409 return; 410 } 411 412 if (req.session == nullptr) 413 { 414 messages::internalError(asyncResp->res); 415 return; 416 } 417 418 asyncResp->res.jsonValue["@odata.type"] = 419 "#CertificateService.v1_0_0.CertificateService"; 420 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService"; 421 asyncResp->res.jsonValue["Id"] = "CertificateService"; 422 asyncResp->res.jsonValue["Name"] = "Certificate Service"; 423 asyncResp->res.jsonValue["Description"] = 424 "Actions available to manage certificates"; 425 // /redfish/v1/CertificateService/CertificateLocations is something 426 // only ConfigureManager can access then only display when the user 427 // has permissions ConfigureManager 428 Privileges effectiveUserPrivileges = 429 redfish::getUserPrivileges(*req.session); 430 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 431 effectiveUserPrivileges)) 432 { 433 asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = 434 "/redfish/v1/CertificateService/CertificateLocations"; 435 } 436 nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; 437 nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"]; 438 replace["target"] = 439 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; 440 nlohmann::json::array_t allowed; 441 allowed.emplace_back("PEM"); 442 replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); 443 actions["#CertificateService.GenerateCSR"]["target"] = 444 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; 445 } 446 447 inline void handleCertificateLocationsGet( 448 App& app, const crow::Request& req, 449 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 450 { 451 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 452 { 453 return; 454 } 455 asyncResp->res.jsonValue["@odata.id"] = 456 "/redfish/v1/CertificateService/CertificateLocations"; 457 asyncResp->res.jsonValue["@odata.type"] = 458 "#CertificateLocations.v1_0_0.CertificateLocations"; 459 asyncResp->res.jsonValue["Name"] = "Certificate Locations"; 460 asyncResp->res.jsonValue["Id"] = "CertificateLocations"; 461 asyncResp->res.jsonValue["Description"] = 462 "Defines a resource that an administrator can use in order to " 463 "locate all certificates installed on a given service"; 464 465 getCertificateList(asyncResp, certs::baseObjectPath, 466 "/Links/Certificates"_json_pointer, 467 "/Links/Certificates@odata.count"_json_pointer); 468 } 469 470 inline void handleError(const std::string_view dbusErrorName, 471 const std::string& id, const std::string& certificate, 472 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 473 { 474 if (dbusErrorName == "org.freedesktop.DBus.Error.UnknownObject") 475 { 476 messages::resourceNotFound(asyncResp->res, "Certificate", id); 477 } 478 else if (dbusErrorName == 479 "xyz.openbmc_project.Certs.Error.InvalidCertificate") 480 { 481 messages::propertyValueIncorrect(asyncResp->res, "Certificate", 482 certificate); 483 } 484 else 485 { 486 messages::internalError(asyncResp->res); 487 } 488 } 489 490 inline void handleReplaceCertificateAction( 491 App& app, const crow::Request& req, 492 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 493 { 494 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 495 { 496 return; 497 } 498 std::string certificate; 499 std::string certURI; 500 std::optional<std::string> certificateType = "PEM"; 501 502 if (!json_util::readJsonAction( // 503 req, asyncResp->res, // 504 "CertificateString", certificate, // 505 "CertificateType", certificateType, // 506 "CertificateUri/@odata.id", certURI // 507 )) 508 { 509 BMCWEB_LOG_ERROR("Required parameters are missing"); 510 return; 511 } 512 513 if (!certificateType) 514 { 515 // should never happen, but it never hurts to be paranoid. 516 return; 517 } 518 if (certificateType != "PEM") 519 { 520 messages::actionParameterNotSupported(asyncResp->res, "CertificateType", 521 "ReplaceCertificate"); 522 return; 523 } 524 525 BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI); 526 527 boost::system::result<boost::urls::url> parsedUrl = 528 boost::urls::parse_relative_ref(certURI); 529 if (!parsedUrl) 530 { 531 messages::actionParameterValueFormatError( 532 asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate"); 533 return; 534 } 535 536 std::string id; 537 sdbusplus::message::object_path objectPath; 538 std::string name; 539 std::string service; 540 if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers", 541 "bmc", "NetworkProtocol", "HTTPS", 542 "Certificates", std::ref(id))) 543 { 544 objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) / 545 id; 546 name = "HTTPS certificate"; 547 service = certs::httpsServiceName; 548 } 549 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 550 "AccountService", "LDAP", 551 "Certificates", std::ref(id))) 552 { 553 objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) / 554 id; 555 name = "LDAP certificate"; 556 service = certs::ldapServiceName; 557 } 558 else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 559 "Managers", "bmc", "Truststore", 560 "Certificates", std::ref(id))) 561 { 562 objectPath = 563 sdbusplus::message::object_path(certs::authorityObjectPath) / id; 564 name = "TrustStore certificate"; 565 service = certs::authorityServiceName; 566 } 567 else 568 { 569 messages::actionParameterNotSupported(asyncResp->res, "CertificateUri", 570 "ReplaceCertificate"); 571 return; 572 } 573 574 std::shared_ptr<CertificateFile> certFile = 575 std::make_shared<CertificateFile>(certificate); 576 crow::connections::systemBus->async_method_call( 577 [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, name, 578 certificate](const boost::system::error_code& ec, 579 sdbusplus::message_t& m) { 580 if (ec) 581 { 582 BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 583 const sd_bus_error* dbusError = m.get_error(); 584 if ((dbusError != nullptr) && (dbusError->name != nullptr)) 585 { 586 handleError(dbusError->name, id, certificate, asyncResp); 587 } 588 else 589 { 590 messages::internalError(asyncResp->res); 591 } 592 return; 593 } 594 getCertificateProperties(asyncResp, objectPath, service, id, url, 595 name); 596 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}", 597 certFile->getCertFilePath()); 598 }, 599 service, objectPath, certs::certReplaceIntf, "Replace", 600 certFile->getCertFilePath()); 601 } 602 603 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 604 static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher; 605 /** 606 * @brief Read data from CSR D-bus object and set to response 607 * 608 * @param[in] asyncResp Shared pointer to the response message 609 * @param[in] certURI Link to certificate collection URI 610 * @param[in] service D-Bus service name 611 * @param[in] certObjPath certificate D-Bus object path 612 * @param[in] csrObjPath CSR D-Bus object path 613 * @return None 614 */ 615 inline void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 616 const std::string& certURI, const std::string& service, 617 const std::string& certObjPath, 618 const std::string& csrObjPath) 619 { 620 BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}", 621 certObjPath, csrObjPath, service); 622 crow::connections::systemBus->async_method_call( 623 [asyncResp, 624 certURI](const boost::system::error_code& ec, const std::string& csr) { 625 if (ec) 626 { 627 BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 628 messages::internalError(asyncResp->res); 629 return; 630 } 631 if (csr.empty()) 632 { 633 BMCWEB_LOG_ERROR("CSR read is empty"); 634 messages::internalError(asyncResp->res); 635 return; 636 } 637 asyncResp->res.jsonValue["CSRString"] = csr; 638 asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = 639 certURI; 640 }, 641 service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 642 } 643 644 inline void 645 handleGenerateCSRAction(App& app, const crow::Request& req, 646 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 647 { 648 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 649 { 650 return; 651 } 652 static const int rsaKeyBitLength = 2048; 653 654 // Required parameters 655 std::string city; 656 std::string commonName; 657 std::string country; 658 std::string organization; 659 std::string organizationalUnit; 660 std::string state; 661 std::string certURI; 662 663 // Optional parameters 664 std::optional<std::vector<std::string>> optAlternativeNames = 665 std::vector<std::string>(); 666 std::optional<std::string> optContactPerson = ""; 667 std::optional<std::string> optChallengePassword = ""; 668 std::optional<std::string> optEmail = ""; 669 std::optional<std::string> optGivenName = ""; 670 std::optional<std::string> optInitials = ""; 671 std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 672 std::optional<std::string> optKeyCurveId = "secp384r1"; 673 std::optional<std::string> optKeyPairAlgorithm = "EC"; 674 std::optional<std::vector<std::string>> optKeyUsage = 675 std::vector<std::string>(); 676 std::optional<std::string> optSurname = ""; 677 std::optional<std::string> optUnstructuredName = ""; 678 if (!json_util::readJsonAction( // 679 req, asyncResp->res, // 680 "AlternativeNames", optAlternativeNames, // 681 "CertificateCollection/@odata.id", certURI, // 682 "ChallengePassword", optChallengePassword, // 683 "City", city, // 684 "CommonName", commonName, // 685 "ContactPerson", optContactPerson, // 686 "Country", country, // 687 "Email", optEmail, // 688 "GivenName", optGivenName, // 689 "Initials", optInitials, // 690 "KeyBitLength", optKeyBitLength, // 691 "KeyCurveId", optKeyCurveId, // 692 "KeyPairAlgorithm", optKeyPairAlgorithm, // 693 "KeyUsage", optKeyUsage, // 694 "Organization", organization, // 695 "OrganizationalUnit", organizationalUnit, // 696 "State", state, // 697 "Surname", optSurname, // 698 "UnstructuredName", optUnstructuredName // 699 )) 700 { 701 return; 702 } 703 704 // bmcweb has no way to store or decode a private key challenge 705 // password, which will likely cause bmcweb to crash on startup 706 // if this is not set on a post so not allowing the user to set 707 // value 708 if (!optChallengePassword->empty()) 709 { 710 messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 711 "ChallengePassword"); 712 return; 713 } 714 715 std::string objectPath; 716 std::string service; 717 if (certURI.starts_with(std::format( 718 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 719 BMCWEB_REDFISH_MANAGER_URI_NAME))) 720 { 721 objectPath = certs::httpsObjectPath; 722 service = certs::httpsServiceName; 723 } 724 else if (certURI.starts_with( 725 "/redfish/v1/AccountService/LDAP/Certificates")) 726 { 727 objectPath = certs::ldapObjectPath; 728 service = certs::ldapServiceName; 729 } 730 else 731 { 732 messages::actionParameterNotSupported( 733 asyncResp->res, "CertificateCollection", "GenerateCSR"); 734 return; 735 } 736 737 // supporting only EC and RSA algorithm 738 if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 739 { 740 messages::actionParameterNotSupported( 741 asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 742 return; 743 } 744 745 // supporting only 2048 key bit length for RSA algorithm due to 746 // time consumed in generating private key 747 if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength) 748 { 749 messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength, 750 "KeyBitLength"); 751 return; 752 } 753 754 // validate KeyUsage supporting only 1 type based on URL 755 if (certURI.starts_with(std::format( 756 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 757 BMCWEB_REDFISH_MANAGER_URI_NAME))) 758 { 759 if (optKeyUsage->empty()) 760 { 761 optKeyUsage->emplace_back("ServerAuthentication"); 762 } 763 else if (optKeyUsage->size() == 1) 764 { 765 if ((*optKeyUsage)[0] != "ServerAuthentication") 766 { 767 messages::propertyValueNotInList(asyncResp->res, 768 (*optKeyUsage)[0], "KeyUsage"); 769 return; 770 } 771 } 772 else 773 { 774 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 775 "GenerateCSR"); 776 return; 777 } 778 } 779 else if (certURI.starts_with( 780 "/redfish/v1/AccountService/LDAP/Certificates")) 781 { 782 if (optKeyUsage->empty()) 783 { 784 optKeyUsage->emplace_back("ClientAuthentication"); 785 } 786 else if (optKeyUsage->size() == 1) 787 { 788 if ((*optKeyUsage)[0] != "ClientAuthentication") 789 { 790 messages::propertyValueNotInList(asyncResp->res, 791 (*optKeyUsage)[0], "KeyUsage"); 792 return; 793 } 794 } 795 else 796 { 797 messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 798 "GenerateCSR"); 799 return; 800 } 801 } 802 803 // Only allow one CSR matcher at a time so setting retry 804 // time-out and timer expiry to 10 seconds for now. 805 static const int timeOut = 10; 806 if (csrMatcher) 807 { 808 messages::serviceTemporarilyUnavailable(asyncResp->res, 809 std::to_string(timeOut)); 810 return; 811 } 812 813 if (req.ioService == nullptr) 814 { 815 messages::internalError(asyncResp->res); 816 return; 817 } 818 819 // Make this static so it survives outside this method 820 static boost::asio::steady_timer timeout(*req.ioService); 821 timeout.expires_after(std::chrono::seconds(timeOut)); 822 timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 823 csrMatcher = nullptr; 824 if (ec) 825 { 826 // operation_aborted is expected if timer is canceled 827 // before completion. 828 if (ec != boost::asio::error::operation_aborted) 829 { 830 BMCWEB_LOG_ERROR("Async_wait failed {}", ec); 831 } 832 return; 833 } 834 BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR"); 835 messages::internalError(asyncResp->res); 836 }); 837 838 // create a matcher to wait on CSR object 839 BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath); 840 std::string match("type='signal'," 841 "interface='org.freedesktop.DBus.ObjectManager'," 842 "path='" + 843 objectPath + 844 "'," 845 "member='InterfacesAdded'"); 846 csrMatcher = std::make_unique<sdbusplus::bus::match_t>( 847 *crow::connections::systemBus, match, 848 [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { 849 timeout.cancel(); 850 if (m.is_method_error()) 851 { 852 BMCWEB_LOG_ERROR("Dbus method error!!!"); 853 messages::internalError(asyncResp->res); 854 return; 855 } 856 857 dbus::utility::DBusInterfacesMap interfacesProperties; 858 859 sdbusplus::message::object_path csrObjectPath; 860 m.read(csrObjectPath, interfacesProperties); 861 BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str); 862 for (const auto& interface : interfacesProperties) 863 { 864 if (interface.first == "xyz.openbmc_project.Certs.CSR") 865 { 866 getCSR(asyncResp, certURI, service, objectPath, 867 csrObjectPath.str); 868 break; 869 } 870 } 871 }); 872 crow::connections::systemBus->async_method_call( 873 [asyncResp](const boost::system::error_code& ec, const std::string&) { 874 if (ec) 875 { 876 BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message()); 877 messages::internalError(asyncResp->res); 878 return; 879 } 880 }, 881 service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 882 "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 883 commonName, *optContactPerson, country, *optEmail, *optGivenName, 884 *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm, 885 *optKeyUsage, organization, organizationalUnit, state, *optSurname, 886 *optUnstructuredName); 887 } 888 889 inline void requestRoutesCertificateService(App& app) 890 { 891 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") 892 .privileges(redfish::privileges::getCertificateService) 893 .methods(boost::beast::http::verb::get)( 894 std::bind_front(handleCertificateServiceGet, std::ref(app))); 895 896 BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 897 .privileges(redfish::privileges::getCertificateLocations) 898 .methods(boost::beast::http::verb::get)( 899 std::bind_front(handleCertificateLocationsGet, std::ref(app))); 900 901 BMCWEB_ROUTE( 902 app, 903 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 904 .privileges(redfish::privileges::postCertificateService) 905 .methods(boost::beast::http::verb::post)( 906 std::bind_front(handleReplaceCertificateAction, std::ref(app))); 907 908 BMCWEB_ROUTE( 909 app, 910 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 911 .privileges(redfish::privileges::postCertificateService) 912 .methods(boost::beast::http::verb::post)( 913 std::bind_front(handleGenerateCSRAction, std::ref(app))); 914 } // requestRoutesCertificateService 915 916 inline void handleHTTPSCertificateCollectionGet( 917 App& app, const crow::Request& req, 918 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 919 const std::string& managerId) 920 { 921 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 922 { 923 return; 924 } 925 926 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 927 { 928 messages::resourceNotFound(asyncResp->res, "Manager", managerId); 929 return; 930 } 931 932 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 933 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 934 BMCWEB_REDFISH_MANAGER_URI_NAME); 935 asyncResp->res.jsonValue["@odata.type"] = 936 "#CertificateCollection.CertificateCollection"; 937 asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; 938 asyncResp->res.jsonValue["Description"] = 939 "A Collection of HTTPS certificate instances"; 940 941 getCertificateList(asyncResp, certs::httpsObjectPath, 942 "/Members"_json_pointer, 943 "/Members@odata.count"_json_pointer); 944 } 945 946 inline void handleHTTPSCertificateCollectionPost( 947 App& app, const crow::Request& req, 948 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 949 const std::string& managerId) 950 { 951 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 952 { 953 return; 954 } 955 956 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 957 { 958 messages::resourceNotFound(asyncResp->res, "Manager", managerId); 959 return; 960 } 961 962 BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost"); 963 964 asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; 965 asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; 966 967 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 968 969 if (certHttpBody.empty()) 970 { 971 BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 972 messages::unrecognizedRequestBody(asyncResp->res); 973 return; 974 } 975 976 std::shared_ptr<CertificateFile> certFile = 977 std::make_shared<CertificateFile>(certHttpBody); 978 979 crow::connections::systemBus->async_method_call( 980 [asyncResp, certFile](const boost::system::error_code& ec, 981 const std::string& objectPath) { 982 if (ec) 983 { 984 BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 985 messages::internalError(asyncResp->res); 986 return; 987 } 988 989 sdbusplus::message::object_path path(objectPath); 990 std::string certId = path.filename(); 991 const boost::urls::url certURL = boost::urls::format( 992 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 993 BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 994 getCertificateProperties(asyncResp, objectPath, 995 certs::httpsServiceName, certId, certURL, 996 "HTTPS Certificate"); 997 BMCWEB_LOG_DEBUG("HTTPS certificate install file={}", 998 certFile->getCertFilePath()); 999 }, 1000 certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf, 1001 "Install", certFile->getCertFilePath()); 1002 } 1003 1004 inline void handleHTTPSCertificateGet( 1005 App& app, const crow::Request& req, 1006 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1007 const std::string& managerId, const std::string& certId) 1008 { 1009 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1010 { 1011 return; 1012 } 1013 1014 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1015 { 1016 messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1017 return; 1018 } 1019 1020 BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId); 1021 const boost::urls::url certURL = boost::urls::format( 1022 "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 1023 BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1024 std::string objPath = 1025 sdbusplus::message::object_path(certs::httpsObjectPath) / certId; 1026 getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, 1027 certId, certURL, "HTTPS Certificate"); 1028 } 1029 1030 inline void requestRoutesHTTPSCertificate(App& app) 1031 { 1032 BMCWEB_ROUTE( 1033 app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/") 1034 .privileges(redfish::privileges::getCertificateCollection) 1035 .methods(boost::beast::http::verb::get)(std::bind_front( 1036 handleHTTPSCertificateCollectionGet, std::ref(app))); 1037 1038 BMCWEB_ROUTE( 1039 app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/") 1040 .privileges(redfish::privileges::postCertificateCollection) 1041 .methods(boost::beast::http::verb::post)(std::bind_front( 1042 handleHTTPSCertificateCollectionPost, std::ref(app))); 1043 1044 BMCWEB_ROUTE( 1045 app, 1046 "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/") 1047 .privileges(redfish::privileges::getCertificate) 1048 .methods(boost::beast::http::verb::get)( 1049 std::bind_front(handleHTTPSCertificateGet, std::ref(app))); 1050 } 1051 1052 inline void handleLDAPCertificateCollectionGet( 1053 App& app, const crow::Request& req, 1054 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1055 { 1056 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1057 { 1058 return; 1059 } 1060 1061 asyncResp->res.jsonValue["@odata.id"] = 1062 "/redfish/v1/AccountService/LDAP/Certificates"; 1063 asyncResp->res.jsonValue["@odata.type"] = 1064 "#CertificateCollection.CertificateCollection"; 1065 asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; 1066 asyncResp->res.jsonValue["Description"] = 1067 "A Collection of LDAP certificate instances"; 1068 1069 getCertificateList(asyncResp, certs::ldapObjectPath, 1070 "/Members"_json_pointer, 1071 "/Members@odata.count"_json_pointer); 1072 } 1073 1074 inline void handleLDAPCertificateCollectionPost( 1075 App& app, const crow::Request& req, 1076 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1077 { 1078 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1079 { 1080 return; 1081 } 1082 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 1083 1084 if (certHttpBody.empty()) 1085 { 1086 BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 1087 messages::unrecognizedRequestBody(asyncResp->res); 1088 return; 1089 } 1090 1091 std::shared_ptr<CertificateFile> certFile = 1092 std::make_shared<CertificateFile>(certHttpBody); 1093 1094 crow::connections::systemBus->async_method_call( 1095 [asyncResp, certFile](const boost::system::error_code& ec, 1096 const std::string& objectPath) { 1097 if (ec) 1098 { 1099 BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 1100 messages::internalError(asyncResp->res); 1101 return; 1102 } 1103 1104 sdbusplus::message::object_path path(objectPath); 1105 std::string certId = path.filename(); 1106 const boost::urls::url certURL = boost::urls::format( 1107 "/redfish/v1/AccountService/LDAP/Certificates/{}", certId); 1108 getCertificateProperties(asyncResp, objectPath, 1109 certs::ldapServiceName, certId, certURL, 1110 "LDAP Certificate"); 1111 BMCWEB_LOG_DEBUG("LDAP certificate install file={}", 1112 certFile->getCertFilePath()); 1113 }, 1114 certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf, 1115 "Install", certFile->getCertFilePath()); 1116 } 1117 1118 inline void handleLDAPCertificateGet( 1119 App& app, const crow::Request& req, 1120 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1121 { 1122 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1123 { 1124 return; 1125 } 1126 1127 BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id); 1128 const boost::urls::url certURL = boost::urls::format( 1129 "/redfish/v1/AccountService/LDAP/Certificates/{}", id); 1130 std::string objPath = 1131 sdbusplus::message::object_path(certs::ldapObjectPath) / id; 1132 getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, 1133 certURL, "LDAP Certificate"); 1134 } 1135 1136 inline void handleLDAPCertificateDelete( 1137 App& app, const crow::Request& req, 1138 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1139 { 1140 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1141 { 1142 return; 1143 } 1144 1145 BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id); 1146 std::string objPath = 1147 sdbusplus::message::object_path(certs::ldapObjectPath) / id; 1148 1149 deleteCertificate(asyncResp, certs::ldapServiceName, objPath); 1150 } 1151 1152 inline void requestRoutesLDAPCertificate(App& app) 1153 { 1154 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1155 .privileges(redfish::privileges::getCertificateCollection) 1156 .methods(boost::beast::http::verb::get)( 1157 std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app))); 1158 1159 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1160 .privileges(redfish::privileges::postCertificateCollection) 1161 .methods(boost::beast::http::verb::post)(std::bind_front( 1162 handleLDAPCertificateCollectionPost, std::ref(app))); 1163 1164 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1165 .privileges(redfish::privileges::getCertificate) 1166 .methods(boost::beast::http::verb::get)( 1167 std::bind_front(handleLDAPCertificateGet, std::ref(app))); 1168 1169 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1170 .privileges(redfish::privileges::deleteCertificate) 1171 .methods(boost::beast::http::verb::delete_)( 1172 std::bind_front(handleLDAPCertificateDelete, std::ref(app))); 1173 } // requestRoutesLDAPCertificate 1174 1175 inline void handleTrustStoreCertificateCollectionGet( 1176 App& app, const crow::Request& req, 1177 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1178 const std::string& managerId) 1179 { 1180 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1181 { 1182 return; 1183 } 1184 1185 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1186 { 1187 messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1188 return; 1189 } 1190 1191 asyncResp->res.jsonValue["@odata.id"] = 1192 boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/", 1193 BMCWEB_REDFISH_MANAGER_URI_NAME); 1194 asyncResp->res.jsonValue["@odata.type"] = 1195 "#CertificateCollection.CertificateCollection"; 1196 asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; 1197 asyncResp->res.jsonValue["Description"] = 1198 "A Collection of TrustStore certificate instances"; 1199 1200 getCertificateList(asyncResp, certs::authorityObjectPath, 1201 "/Members"_json_pointer, 1202 "/Members@odata.count"_json_pointer); 1203 } 1204 1205 inline void handleTrustStoreCertificateCollectionPost( 1206 App& app, const crow::Request& req, 1207 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1208 const std::string& managerId) 1209 { 1210 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1211 { 1212 return; 1213 } 1214 1215 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1216 { 1217 messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1218 return; 1219 } 1220 1221 std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 1222 1223 if (certHttpBody.empty()) 1224 { 1225 BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 1226 messages::unrecognizedRequestBody(asyncResp->res); 1227 return; 1228 } 1229 1230 std::shared_ptr<CertificateFile> certFile = 1231 std::make_shared<CertificateFile>(certHttpBody); 1232 crow::connections::systemBus->async_method_call( 1233 [asyncResp, certFile](const boost::system::error_code& ec, 1234 const std::string& objectPath) { 1235 if (ec) 1236 { 1237 BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 1238 messages::internalError(asyncResp->res); 1239 return; 1240 } 1241 1242 sdbusplus::message::object_path path(objectPath); 1243 std::string certId = path.filename(); 1244 const boost::urls::url certURL = boost::urls::format( 1245 "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 1246 BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1247 getCertificateProperties(asyncResp, objectPath, 1248 certs::authorityServiceName, certId, 1249 certURL, "TrustStore Certificate"); 1250 BMCWEB_LOG_DEBUG("TrustStore certificate install file={}", 1251 certFile->getCertFilePath()); 1252 }, 1253 certs::authorityServiceName, certs::authorityObjectPath, 1254 certs::certInstallIntf, "Install", certFile->getCertFilePath()); 1255 } 1256 1257 inline void handleTrustStoreCertificateGet( 1258 App& app, const crow::Request& req, 1259 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1260 const std::string& managerId, const std::string& certId) 1261 { 1262 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1263 { 1264 return; 1265 } 1266 1267 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1268 { 1269 messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1270 return; 1271 } 1272 1273 BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId); 1274 const boost::urls::url certURL = boost::urls::format( 1275 "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 1276 BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1277 std::string objPath = 1278 sdbusplus::message::object_path(certs::authorityObjectPath) / certId; 1279 getCertificateProperties(asyncResp, objPath, certs::authorityServiceName, 1280 certId, certURL, "TrustStore Certificate"); 1281 } 1282 1283 inline void handleTrustStoreCertificateDelete( 1284 App& app, const crow::Request& req, 1285 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1286 const std::string& managerId, const std::string& certId) 1287 { 1288 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1289 { 1290 return; 1291 } 1292 1293 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1294 { 1295 messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1296 return; 1297 } 1298 1299 BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId); 1300 std::string objPath = 1301 sdbusplus::message::object_path(certs::authorityObjectPath) / certId; 1302 1303 deleteCertificate(asyncResp, certs::authorityServiceName, objPath); 1304 } 1305 1306 inline void requestRoutesTrustStoreCertificate(App& app) 1307 { 1308 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/") 1309 .privileges(redfish::privileges::getCertificate) 1310 .methods(boost::beast::http::verb::get)(std::bind_front( 1311 handleTrustStoreCertificateCollectionGet, std::ref(app))); 1312 1313 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/") 1314 .privileges(redfish::privileges::postCertificateCollection) 1315 .methods(boost::beast::http::verb::post)(std::bind_front( 1316 handleTrustStoreCertificateCollectionPost, std::ref(app))); 1317 1318 BMCWEB_ROUTE(app, 1319 "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/") 1320 .privileges(redfish::privileges::getCertificate) 1321 .methods(boost::beast::http::verb::get)( 1322 std::bind_front(handleTrustStoreCertificateGet, std::ref(app))); 1323 1324 BMCWEB_ROUTE(app, 1325 "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/") 1326 .privileges(redfish::privileges::deleteCertificate) 1327 .methods(boost::beast::http::verb::delete_)( 1328 std::bind_front(handleTrustStoreCertificateDelete, std::ref(app))); 1329 } // requestRoutesTrustStoreCertificate 1330 } // namespace redfish 1331