140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 35968caeeSMarri Devender Rao #pragma once 45968caeeSMarri Devender Rao 5*d7857201SEd Tanous #include "bmcweb_config.h" 6*d7857201SEd Tanous 73ccb3adbSEd Tanous #include "app.hpp" 83ccb3adbSEd Tanous #include "async_resp.hpp" 9*d7857201SEd Tanous #include "dbus_singleton.hpp" 107a1dbc48SGeorge Liu #include "dbus_utility.hpp" 11*d7857201SEd Tanous #include "error_messages.hpp" 121aa0c2b8SEd Tanous #include "http/parsing.hpp" 13*d7857201SEd Tanous #include "http_request.hpp" 143ccb3adbSEd Tanous #include "http_response.hpp" 15*d7857201SEd Tanous #include "logging.hpp" 16*d7857201SEd Tanous #include "privileges.hpp" 173ccb3adbSEd Tanous #include "query.hpp" 183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 19*d7857201SEd Tanous #include "utility.hpp" 209b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp" 213ccb3adbSEd Tanous #include "utils/json_utils.hpp" 223ccb3adbSEd Tanous #include "utils/time_utils.hpp" 239b12d1f9SKrzysztof Grobelny 24*d7857201SEd Tanous // NOLINTNEXTLINE(modernize-deprecated-headers) 25*d7857201SEd Tanous #include <stdlib.h> 26*d7857201SEd Tanous #include <systemd/sd-bus.h> 27*d7857201SEd Tanous 28*d7857201SEd Tanous #include <boost/asio/error.hpp> 29*d7857201SEd Tanous #include <boost/asio/steady_timer.hpp> 30*d7857201SEd Tanous #include <boost/beast/http/field.hpp> 31*d7857201SEd Tanous #include <boost/beast/http/status.hpp> 32*d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 33*d7857201SEd Tanous #include <boost/system/result.hpp> 34ef4c65b7SEd Tanous #include <boost/url/format.hpp> 35*d7857201SEd Tanous #include <boost/url/parse.hpp> 36*d7857201SEd Tanous #include <boost/url/url.hpp> 37*d7857201SEd Tanous #include <nlohmann/json.hpp> 383ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp> 39*d7857201SEd Tanous #include <sdbusplus/message.hpp> 40*d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 419b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 421214b7e7SGunnar Mills 437a1dbc48SGeorge Liu #include <array> 44*d7857201SEd Tanous #include <chrono> 45*d7857201SEd Tanous #include <cstddef> 46*d7857201SEd Tanous #include <cstdint> 47*d7857201SEd Tanous #include <cstdlib> 48*d7857201SEd Tanous #include <filesystem> 49*d7857201SEd Tanous #include <format> 50*d7857201SEd Tanous #include <fstream> 51*d7857201SEd Tanous #include <functional> 52*d7857201SEd Tanous #include <iterator> 533ccb3adbSEd Tanous #include <memory> 54*d7857201SEd Tanous #include <optional> 55*d7857201SEd Tanous #include <string> 567a1dbc48SGeorge Liu #include <string_view> 57*d7857201SEd Tanous #include <system_error> 58*d7857201SEd Tanous #include <utility> 59*d7857201SEd Tanous #include <vector> 607a1dbc48SGeorge Liu 615968caeeSMarri Devender Rao namespace redfish 625968caeeSMarri Devender Rao { 635968caeeSMarri Devender Rao namespace certs 645968caeeSMarri Devender Rao { 6589492a15SPatrick Williams constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 6689492a15SPatrick Williams constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 6789492a15SPatrick Williams constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 6889492a15SPatrick Williams constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 6989492a15SPatrick Williams constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties"; 7089492a15SPatrick Williams constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 7189492a15SPatrick Williams constexpr const char* httpsServiceName = 7237cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Server.Https"; 7389492a15SPatrick Williams constexpr const char* ldapServiceName = 7437cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 7589492a15SPatrick Williams constexpr const char* authorityServiceName = 76b2254ccdSMichal Orzel "xyz.openbmc_project.Certs.Manager.Authority.Truststore"; 7789492a15SPatrick Williams constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs"; 7889492a15SPatrick Williams constexpr const char* httpsObjectPath = 79c6a8dfb1SJiaqing Zhao "/xyz/openbmc_project/certs/server/https"; 8089492a15SPatrick Williams constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 8189492a15SPatrick Williams constexpr const char* authorityObjectPath = 82b2254ccdSMichal Orzel "/xyz/openbmc_project/certs/authority/truststore"; 835968caeeSMarri Devender Rao } // namespace certs 845968caeeSMarri Devender Rao 855968caeeSMarri Devender Rao /** 865968caeeSMarri Devender Rao * The Certificate schema defines a Certificate Service which represents the 875968caeeSMarri Devender Rao * actions available to manage certificates and links to where certificates 885968caeeSMarri Devender Rao * are installed. 895968caeeSMarri Devender Rao */ 907e860f15SJohn Edward Broadbent 918d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody( 928d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9358eb238fSKowalski, Kamil const crow::Request& req) 9458eb238fSKowalski, Kamil { 951aa0c2b8SEd Tanous nlohmann::json reqJson; 961aa0c2b8SEd Tanous JsonParseResult ret = parseRequestAsJson(req, reqJson); 971aa0c2b8SEd Tanous if (ret != JsonParseResult::Success) 9858eb238fSKowalski, Kamil { 9958eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 10033c6b580SEd Tanous return req.body(); 10158eb238fSKowalski, Kamil } 10258eb238fSKowalski, Kamil 10358eb238fSKowalski, Kamil std::string certificate; 10458eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 10558eb238fSKowalski, Kamil 106afc474aeSMyung Bae if (!json_util::readJsonPatch( // 107afc474aeSMyung Bae req, asyncResp->res, // 108afc474aeSMyung Bae "CertificateString", certificate, // 109afc474aeSMyung Bae "CertificateType", certificateType // 110afc474aeSMyung Bae )) 11158eb238fSKowalski, Kamil { 11262598e31SEd Tanous BMCWEB_LOG_ERROR("Required parameters are missing"); 11358eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 114abb93cddSEd Tanous return {}; 11558eb238fSKowalski, Kamil } 11658eb238fSKowalski, Kamil 11758eb238fSKowalski, Kamil if (*certificateType != "PEM") 11858eb238fSKowalski, Kamil { 11958eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 12058eb238fSKowalski, Kamil "CertificateType"); 121abb93cddSEd Tanous return {}; 12258eb238fSKowalski, Kamil } 12358eb238fSKowalski, Kamil 12458eb238fSKowalski, Kamil return certificate; 12558eb238fSKowalski, Kamil } 12658eb238fSKowalski, Kamil 1275968caeeSMarri Devender Rao /** 1285968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 1295968caeeSMarri Devender Rao */ 1305968caeeSMarri Devender Rao class CertificateFile 1315968caeeSMarri Devender Rao { 1325968caeeSMarri Devender Rao public: 1335968caeeSMarri Devender Rao CertificateFile() = delete; 1345968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 1355968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 1365968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 1375968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 1384e23a444SEd Tanous explicit CertificateFile(const std::string& certString) 1395968caeeSMarri Devender Rao { 14072d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 1415207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 1425207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 1435207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 144e662eae8SEd Tanous if (tempDirectory != nullptr) 1455968caeeSMarri Devender Rao { 1465968caeeSMarri Devender Rao certDirectory = tempDirectory; 1475968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 148bd79bce8SPatrick Williams std::ofstream out(certificateFile, 149bd79bce8SPatrick Williams std::ofstream::out | std::ofstream::binary | 1505968caeeSMarri Devender Rao std::ofstream::trunc); 1515968caeeSMarri Devender Rao out << certString; 1525968caeeSMarri Devender Rao out.close(); 15362598e31SEd Tanous BMCWEB_LOG_DEBUG("Creating certificate file{}", 15462598e31SEd Tanous certificateFile.string()); 1555968caeeSMarri Devender Rao } 1565968caeeSMarri Devender Rao } 1575968caeeSMarri Devender Rao ~CertificateFile() 1585968caeeSMarri Devender Rao { 1595968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1605968caeeSMarri Devender Rao { 16162598e31SEd Tanous BMCWEB_LOG_DEBUG("Removing certificate file{}", 16262598e31SEd Tanous certificateFile.string()); 16323a21a1cSEd Tanous std::error_code ec; 16423a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 16523a21a1cSEd Tanous if (ec) 1665968caeeSMarri Devender Rao { 16762598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to remove temp directory{}", 16862598e31SEd Tanous certDirectory.string()); 1695968caeeSMarri Devender Rao } 1705968caeeSMarri Devender Rao } 1715968caeeSMarri Devender Rao } 1725968caeeSMarri Devender Rao std::string getCertFilePath() 1735968caeeSMarri Devender Rao { 1745968caeeSMarri Devender Rao return certificateFile; 1755968caeeSMarri Devender Rao } 1765968caeeSMarri Devender Rao 1775968caeeSMarri Devender Rao private: 1785968caeeSMarri Devender Rao std::filesystem::path certificateFile; 1795968caeeSMarri Devender Rao std::filesystem::path certDirectory; 1805968caeeSMarri Devender Rao }; 1815968caeeSMarri Devender Rao 1825968caeeSMarri Devender Rao /** 1834e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 1845968caeeSMarri Devender Rao * 1855968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 1865968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 1875968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 1885968caeeSMarri Devender Rao * @return None 1895968caeeSMarri Devender Rao */ 1904ff0f1f4SEd Tanous inline void updateCertIssuerOrSubject(nlohmann::json& out, 19126ccae32SEd Tanous std::string_view value) 1925968caeeSMarri Devender Rao { 1935968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 1945968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 1955968caeeSMarri Devender Rao while (i != value.end()) 1965968caeeSMarri Devender Rao { 1975968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 1985968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 1995968caeeSMarri Devender Rao { 2006da47babSPatrick Williams std::advance(i, 1); 2015968caeeSMarri Devender Rao } 2025968caeeSMarri Devender Rao if (i == value.end()) 2035968caeeSMarri Devender Rao { 2045968caeeSMarri Devender Rao break; 2055968caeeSMarri Devender Rao } 20626ccae32SEd Tanous std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin)); 2076da47babSPatrick Williams std::advance(i, 1); 2085968caeeSMarri Devender Rao tokenBegin = i; 2095968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 2105968caeeSMarri Devender Rao { 2116da47babSPatrick Williams std::advance(i, 1); 2125968caeeSMarri Devender Rao } 21326ccae32SEd Tanous std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin)); 2145968caeeSMarri Devender Rao if (key == "L") 2155968caeeSMarri Devender Rao { 2165968caeeSMarri Devender Rao out["City"] = val; 2175968caeeSMarri Devender Rao } 2185968caeeSMarri Devender Rao else if (key == "CN") 2195968caeeSMarri Devender Rao { 2205968caeeSMarri Devender Rao out["CommonName"] = val; 2215968caeeSMarri Devender Rao } 2225968caeeSMarri Devender Rao else if (key == "C") 2235968caeeSMarri Devender Rao { 2245968caeeSMarri Devender Rao out["Country"] = val; 2255968caeeSMarri Devender Rao } 2265968caeeSMarri Devender Rao else if (key == "O") 2275968caeeSMarri Devender Rao { 2285968caeeSMarri Devender Rao out["Organization"] = val; 2295968caeeSMarri Devender Rao } 2305968caeeSMarri Devender Rao else if (key == "OU") 2315968caeeSMarri Devender Rao { 2325968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 2335968caeeSMarri Devender Rao } 2345968caeeSMarri Devender Rao else if (key == "ST") 2355968caeeSMarri Devender Rao { 2365968caeeSMarri Devender Rao out["State"] = val; 2375968caeeSMarri Devender Rao } 2385968caeeSMarri Devender Rao // skip comma character 2395968caeeSMarri Devender Rao if (i != value.end()) 2405968caeeSMarri Devender Rao { 2416da47babSPatrick Williams std::advance(i, 1); 2425968caeeSMarri Devender Rao } 2435968caeeSMarri Devender Rao } 2445968caeeSMarri Devender Rao } 2455968caeeSMarri Devender Rao 2465968caeeSMarri Devender Rao /** 247d3f92ce7SJiaqing Zhao * @brief Retrieve the installed certificate list 248d3f92ce7SJiaqing Zhao * 249d3f92ce7SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 250d3f92ce7SJiaqing Zhao * @param[in] basePath DBus object path to search 251d3f92ce7SJiaqing Zhao * @param[in] listPtr Json pointer to the list in asyncResp 252d3f92ce7SJiaqing Zhao * @param[in] countPtr Json pointer to the count in asyncResp 253d3f92ce7SJiaqing Zhao * @return None 254d3f92ce7SJiaqing Zhao */ 2554ff0f1f4SEd Tanous inline void getCertificateList( 256bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 257bd79bce8SPatrick Williams const std::string& basePath, const nlohmann::json::json_pointer& listPtr, 258d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& countPtr) 259d3f92ce7SJiaqing Zhao { 2607a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 2617a1dbc48SGeorge Liu certs::certPropIntf}; 2627a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 2637a1dbc48SGeorge Liu basePath, 0, interfaces, 264d3f92ce7SJiaqing Zhao [asyncResp, listPtr, countPtr]( 2657a1dbc48SGeorge Liu const boost::system::error_code& ec, 266d3f92ce7SJiaqing Zhao const dbus::utility::MapperGetSubTreePathsResponse& certPaths) { 267d3f92ce7SJiaqing Zhao if (ec) 268d3f92ce7SJiaqing Zhao { 26962598e31SEd Tanous BMCWEB_LOG_ERROR("Certificate collection query failed: {}", ec); 270d3f92ce7SJiaqing Zhao messages::internalError(asyncResp->res); 271d3f92ce7SJiaqing Zhao return; 272d3f92ce7SJiaqing Zhao } 273d3f92ce7SJiaqing Zhao 274d3f92ce7SJiaqing Zhao nlohmann::json& links = asyncResp->res.jsonValue[listPtr]; 275d3f92ce7SJiaqing Zhao links = nlohmann::json::array(); 276d3f92ce7SJiaqing Zhao for (const auto& certPath : certPaths) 277d3f92ce7SJiaqing Zhao { 278d3f92ce7SJiaqing Zhao sdbusplus::message::object_path objPath(certPath); 279d3f92ce7SJiaqing Zhao std::string certId = objPath.filename(); 280d3f92ce7SJiaqing Zhao if (certId.empty()) 281d3f92ce7SJiaqing Zhao { 282bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("Invalid certificate objPath {}", 283bd79bce8SPatrick Williams certPath); 284d3f92ce7SJiaqing Zhao continue; 285d3f92ce7SJiaqing Zhao } 286d3f92ce7SJiaqing Zhao 287d3f92ce7SJiaqing Zhao boost::urls::url certURL; 288d3f92ce7SJiaqing Zhao if (objPath.parent_path() == certs::httpsObjectPath) 289d3f92ce7SJiaqing Zhao { 290ef4c65b7SEd Tanous certURL = boost::urls::format( 291253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 292253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 293d3f92ce7SJiaqing Zhao } 294d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::ldapObjectPath) 295d3f92ce7SJiaqing Zhao { 296ef4c65b7SEd Tanous certURL = boost::urls::format( 297bd79bce8SPatrick Williams "/redfish/v1/AccountService/LDAP/Certificates/{}", 298bd79bce8SPatrick Williams certId); 299d3f92ce7SJiaqing Zhao } 300d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::authorityObjectPath) 301d3f92ce7SJiaqing Zhao { 302ef4c65b7SEd Tanous certURL = boost::urls::format( 303253f11b8SEd Tanous "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 304253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 305d3f92ce7SJiaqing Zhao } 306d3f92ce7SJiaqing Zhao else 307d3f92ce7SJiaqing Zhao { 308d3f92ce7SJiaqing Zhao continue; 309d3f92ce7SJiaqing Zhao } 310d3f92ce7SJiaqing Zhao 311d3f92ce7SJiaqing Zhao nlohmann::json::object_t link; 312d3f92ce7SJiaqing Zhao link["@odata.id"] = certURL; 313d3f92ce7SJiaqing Zhao links.emplace_back(std::move(link)); 314d3f92ce7SJiaqing Zhao } 315d3f92ce7SJiaqing Zhao 316d3f92ce7SJiaqing Zhao asyncResp->res.jsonValue[countPtr] = links.size(); 3177a1dbc48SGeorge Liu }); 318d3f92ce7SJiaqing Zhao } 319d3f92ce7SJiaqing Zhao 320d3f92ce7SJiaqing Zhao /** 3215968caeeSMarri Devender Rao * @brief Retrieve the certificates properties and append to the response 3225968caeeSMarri Devender Rao * message 3235968caeeSMarri Devender Rao * 3245968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 3255968caeeSMarri Devender Rao * @param[in] objectPath Path of the D-Bus service object 3265968caeeSMarri Devender Rao * @param[in] certId Id of the certificate 3275968caeeSMarri Devender Rao * @param[in] certURL URL of the certificate object 3285968caeeSMarri Devender Rao * @param[in] name name of the certificate 3295968caeeSMarri Devender Rao * @return None 3305968caeeSMarri Devender Rao */ 3314ff0f1f4SEd Tanous inline void getCertificateProperties( 3328d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 333e19e97e2SJiaqing Zhao const std::string& objectPath, const std::string& service, 3341e312598SJiaqing Zhao const std::string& certId, const boost::urls::url& certURL, 335e19e97e2SJiaqing Zhao const std::string& name) 3365968caeeSMarri Devender Rao { 33762598e31SEd Tanous BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}", 33862598e31SEd Tanous objectPath, certId, certURL); 339deae6a78SEd Tanous dbus::utility::getAllProperties( 340deae6a78SEd Tanous service, objectPath, certs::certPropIntf, 341b9d36b47SEd Tanous [asyncResp, certURL, certId, 3425e7e2dc5SEd Tanous name](const boost::system::error_code& ec, 343b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& properties) { 3445968caeeSMarri Devender Rao if (ec) 3455968caeeSMarri Devender Rao { 34662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 347bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Certificate", 348bd79bce8SPatrick Williams certId); 3495968caeeSMarri Devender Rao return; 3505968caeeSMarri Devender Rao } 3519b12d1f9SKrzysztof Grobelny 3529b12d1f9SKrzysztof Grobelny const std::string* certificateString = nullptr; 3539b12d1f9SKrzysztof Grobelny const std::vector<std::string>* keyUsage = nullptr; 3549b12d1f9SKrzysztof Grobelny const std::string* issuer = nullptr; 3559b12d1f9SKrzysztof Grobelny const std::string* subject = nullptr; 3569b12d1f9SKrzysztof Grobelny const uint64_t* validNotAfter = nullptr; 3579b12d1f9SKrzysztof Grobelny const uint64_t* validNotBefore = nullptr; 3589b12d1f9SKrzysztof Grobelny 3599b12d1f9SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 360bd79bce8SPatrick Williams dbus_utils::UnpackErrorPrinter(), properties, 361bd79bce8SPatrick Williams "CertificateString", certificateString, "KeyUsage", keyUsage, 362bd79bce8SPatrick Williams "Issuer", issuer, "Subject", subject, "ValidNotAfter", 363bd79bce8SPatrick Williams validNotAfter, "ValidNotBefore", validNotBefore); 3649b12d1f9SKrzysztof Grobelny 3659b12d1f9SKrzysztof Grobelny if (!success) 3669b12d1f9SKrzysztof Grobelny { 3679b12d1f9SKrzysztof Grobelny messages::internalError(asyncResp->res); 3689b12d1f9SKrzysztof Grobelny return; 3699b12d1f9SKrzysztof Grobelny } 3709b12d1f9SKrzysztof Grobelny 3711476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = certURL; 3721476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3731476687dSEd Tanous "#Certificate.v1_0_0.Certificate"; 374e19e97e2SJiaqing Zhao asyncResp->res.jsonValue["Id"] = certId; 3751476687dSEd Tanous asyncResp->res.jsonValue["Name"] = name; 3761476687dSEd Tanous asyncResp->res.jsonValue["Description"] = name; 3775968caeeSMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = ""; 3789b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array(); 3799b12d1f9SKrzysztof Grobelny 3809b12d1f9SKrzysztof Grobelny if (certificateString != nullptr) 3815968caeeSMarri Devender Rao { 382bd79bce8SPatrick Williams asyncResp->res.jsonValue["CertificateString"] = 383bd79bce8SPatrick Williams *certificateString; 3845968caeeSMarri Devender Rao } 3859b12d1f9SKrzysztof Grobelny 3869b12d1f9SKrzysztof Grobelny if (keyUsage != nullptr) 3875968caeeSMarri Devender Rao { 3889b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = *keyUsage; 3895968caeeSMarri Devender Rao } 3909b12d1f9SKrzysztof Grobelny 3919b12d1f9SKrzysztof Grobelny if (issuer != nullptr) 3925968caeeSMarri Devender Rao { 3939b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"], 3949b12d1f9SKrzysztof Grobelny *issuer); 3955968caeeSMarri Devender Rao } 3969b12d1f9SKrzysztof Grobelny 3979b12d1f9SKrzysztof Grobelny if (subject != nullptr) 3985968caeeSMarri Devender Rao { 3999b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"], 4009b12d1f9SKrzysztof Grobelny *subject); 4015968caeeSMarri Devender Rao } 4029b12d1f9SKrzysztof Grobelny 4039b12d1f9SKrzysztof Grobelny if (validNotAfter != nullptr) 4045968caeeSMarri Devender Rao { 4055968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotAfter"] = 4069b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotAfter); 4075968caeeSMarri Devender Rao } 4089b12d1f9SKrzysztof Grobelny 4099b12d1f9SKrzysztof Grobelny if (validNotBefore != nullptr) 4105968caeeSMarri Devender Rao { 4115968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotBefore"] = 4129b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotBefore); 4135968caeeSMarri Devender Rao } 4149b12d1f9SKrzysztof Grobelny 4151e312598SJiaqing Zhao asyncResp->res.addHeader( 416d9f6c621SEd Tanous boost::beast::http::field::location, 417d9f6c621SEd Tanous std::string_view(certURL.data(), certURL.size())); 4189b12d1f9SKrzysztof Grobelny }); 4195968caeeSMarri Devender Rao } 4205968caeeSMarri Devender Rao 4214ff0f1f4SEd Tanous inline void 4227a3a8f7aSJiaqing Zhao deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4237a3a8f7aSJiaqing Zhao const std::string& service, 4247a3a8f7aSJiaqing Zhao const sdbusplus::message::object_path& objectPath) 4257a3a8f7aSJiaqing Zhao { 4267a3a8f7aSJiaqing Zhao crow::connections::systemBus->async_method_call( 4277a3a8f7aSJiaqing Zhao [asyncResp, 4285e7e2dc5SEd Tanous id{objectPath.filename()}](const boost::system::error_code& ec) { 4297a3a8f7aSJiaqing Zhao if (ec) 4307a3a8f7aSJiaqing Zhao { 4317a3a8f7aSJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 4327a3a8f7aSJiaqing Zhao return; 4337a3a8f7aSJiaqing Zhao } 43462598e31SEd Tanous BMCWEB_LOG_INFO("Certificate deleted"); 4357a3a8f7aSJiaqing Zhao asyncResp->res.result(boost::beast::http::status::no_content); 4367a3a8f7aSJiaqing Zhao }, 4377a3a8f7aSJiaqing Zhao service, objectPath, certs::objDeleteIntf, "Delete"); 4387a3a8f7aSJiaqing Zhao } 4397a3a8f7aSJiaqing Zhao 440828252d5SJiaqing Zhao inline void handleCertificateServiceGet( 441828252d5SJiaqing Zhao App& app, const crow::Request& req, 442828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 4435968caeeSMarri Devender Rao { 444828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 445828252d5SJiaqing Zhao { 446828252d5SJiaqing Zhao return; 447828252d5SJiaqing Zhao } 448828252d5SJiaqing Zhao 4493e72c202SNinad Palsule if (req.session == nullptr) 4503e72c202SNinad Palsule { 4513e72c202SNinad Palsule messages::internalError(asyncResp->res); 4523e72c202SNinad Palsule return; 4533e72c202SNinad Palsule } 4543e72c202SNinad Palsule 455828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 456828252d5SJiaqing Zhao "#CertificateService.v1_0_0.CertificateService"; 457828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService"; 458828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateService"; 459828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Service"; 460828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 461828252d5SJiaqing Zhao "Actions available to manage certificates"; 462828252d5SJiaqing Zhao // /redfish/v1/CertificateService/CertificateLocations is something 463828252d5SJiaqing Zhao // only ConfigureManager can access then only display when the user 464828252d5SJiaqing Zhao // has permissions ConfigureManager 465828252d5SJiaqing Zhao Privileges effectiveUserPrivileges = 4663e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 467828252d5SJiaqing Zhao if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 468828252d5SJiaqing Zhao effectiveUserPrivileges)) 469828252d5SJiaqing Zhao { 470828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = 471828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 472828252d5SJiaqing Zhao } 473828252d5SJiaqing Zhao nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; 474828252d5SJiaqing Zhao nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"]; 475828252d5SJiaqing Zhao replace["target"] = 476828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; 477828252d5SJiaqing Zhao nlohmann::json::array_t allowed; 478ad539545SPatrick Williams allowed.emplace_back("PEM"); 479828252d5SJiaqing Zhao replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); 480828252d5SJiaqing Zhao actions["#CertificateService.GenerateCSR"]["target"] = 481828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; 482828252d5SJiaqing Zhao } 483828252d5SJiaqing Zhao 484828252d5SJiaqing Zhao inline void handleCertificateLocationsGet( 485828252d5SJiaqing Zhao App& app, const crow::Request& req, 486828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 487828252d5SJiaqing Zhao { 488828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 489828252d5SJiaqing Zhao { 490828252d5SJiaqing Zhao return; 491828252d5SJiaqing Zhao } 492828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = 493828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 494828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 495828252d5SJiaqing Zhao "#CertificateLocations.v1_0_0.CertificateLocations"; 496828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Locations"; 497828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateLocations"; 498828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 499828252d5SJiaqing Zhao "Defines a resource that an administrator can use in order to " 500828252d5SJiaqing Zhao "locate all certificates installed on a given service"; 501828252d5SJiaqing Zhao 502828252d5SJiaqing Zhao getCertificateList(asyncResp, certs::baseObjectPath, 503828252d5SJiaqing Zhao "/Links/Certificates"_json_pointer, 504828252d5SJiaqing Zhao "/Links/Certificates@odata.count"_json_pointer); 505828252d5SJiaqing Zhao } 506828252d5SJiaqing Zhao 50726d3b0fbSChandra Harkude inline void handleError(const std::string_view dbusErrorName, 50826d3b0fbSChandra Harkude const std::string& id, const std::string& certificate, 50926d3b0fbSChandra Harkude const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 51026d3b0fbSChandra Harkude { 51126d3b0fbSChandra Harkude if (dbusErrorName == "org.freedesktop.DBus.Error.UnknownObject") 51226d3b0fbSChandra Harkude { 51326d3b0fbSChandra Harkude messages::resourceNotFound(asyncResp->res, "Certificate", id); 51426d3b0fbSChandra Harkude } 51526d3b0fbSChandra Harkude else if (dbusErrorName == 51626d3b0fbSChandra Harkude "xyz.openbmc_project.Certs.Error.InvalidCertificate") 51726d3b0fbSChandra Harkude { 51826d3b0fbSChandra Harkude messages::propertyValueIncorrect(asyncResp->res, "Certificate", 51926d3b0fbSChandra Harkude certificate); 52026d3b0fbSChandra Harkude } 52126d3b0fbSChandra Harkude else 52226d3b0fbSChandra Harkude { 52326d3b0fbSChandra Harkude messages::internalError(asyncResp->res); 52426d3b0fbSChandra Harkude } 52526d3b0fbSChandra Harkude } 52626d3b0fbSChandra Harkude 527828252d5SJiaqing Zhao inline void handleReplaceCertificateAction( 528828252d5SJiaqing Zhao App& app, const crow::Request& req, 529828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 530828252d5SJiaqing Zhao { 5313ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 53245ca1b86SEd Tanous { 53345ca1b86SEd Tanous return; 53445ca1b86SEd Tanous } 5355968caeeSMarri Devender Rao std::string certificate; 5367a31e336SEd Tanous std::string certURI; 5375968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 5388d1b46d7Szhanghch05 539afc474aeSMyung Bae if (!json_util::readJsonAction( // 540afc474aeSMyung Bae req, asyncResp->res, // 541afc474aeSMyung Bae "CertificateString", certificate, // 542afc474aeSMyung Bae "CertificateType", certificateType, // 543afc474aeSMyung Bae "CertificateUri/@odata.id", certURI // 544afc474aeSMyung Bae )) 5455968caeeSMarri Devender Rao { 54662598e31SEd Tanous BMCWEB_LOG_ERROR("Required parameters are missing"); 5475968caeeSMarri Devender Rao return; 5485968caeeSMarri Devender Rao } 5495968caeeSMarri Devender Rao 5505968caeeSMarri Devender Rao if (!certificateType) 5515968caeeSMarri Devender Rao { 5525968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 5535968caeeSMarri Devender Rao return; 5545968caeeSMarri Devender Rao } 5555968caeeSMarri Devender Rao if (certificateType != "PEM") 5565968caeeSMarri Devender Rao { 557828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateType", 558828252d5SJiaqing Zhao "ReplaceCertificate"); 5595968caeeSMarri Devender Rao return; 5605968caeeSMarri Devender Rao } 5615968caeeSMarri Devender Rao 56262598e31SEd Tanous BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI); 5635968caeeSMarri Devender Rao 5646fd29553SEd Tanous boost::system::result<boost::urls::url> parsedUrl = 56575b63a2cSJiaqing Zhao boost::urls::parse_relative_ref(certURI); 56675b63a2cSJiaqing Zhao if (!parsedUrl) 5675968caeeSMarri Devender Rao { 568828252d5SJiaqing Zhao messages::actionParameterValueFormatError( 569828252d5SJiaqing Zhao asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate"); 5705968caeeSMarri Devender Rao return; 5715968caeeSMarri Devender Rao } 57275b63a2cSJiaqing Zhao 57375b63a2cSJiaqing Zhao std::string id; 57475b63a2cSJiaqing Zhao sdbusplus::message::object_path objectPath; 5755968caeeSMarri Devender Rao std::string name; 57637cce918SMarri Devender Rao std::string service; 577828252d5SJiaqing Zhao if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers", 578828252d5SJiaqing Zhao "bmc", "NetworkProtocol", "HTTPS", 579828252d5SJiaqing Zhao "Certificates", std::ref(id))) 5805968caeeSMarri Devender Rao { 58189492a15SPatrick Williams objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) / 58289492a15SPatrick Williams id; 5835968caeeSMarri Devender Rao name = "HTTPS certificate"; 58437cce918SMarri Devender Rao service = certs::httpsServiceName; 58537cce918SMarri Devender Rao } 58675b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 58775b63a2cSJiaqing Zhao "AccountService", "LDAP", 58875b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 58937cce918SMarri Devender Rao { 59089492a15SPatrick Williams objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) / 59189492a15SPatrick Williams id; 59237cce918SMarri Devender Rao name = "LDAP certificate"; 59337cce918SMarri Devender Rao service = certs::ldapServiceName; 5945968caeeSMarri Devender Rao } 59575b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 59675b63a2cSJiaqing Zhao "Managers", "bmc", "Truststore", 59775b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 598cfcd5f6bSMarri Devender Rao { 59975b63a2cSJiaqing Zhao objectPath = 600828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 601cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 602cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 603cfcd5f6bSMarri Devender Rao } 6045968caeeSMarri Devender Rao else 6055968caeeSMarri Devender Rao { 606828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateUri", 607828252d5SJiaqing Zhao "ReplaceCertificate"); 6085968caeeSMarri Devender Rao return; 6095968caeeSMarri Devender Rao } 6105968caeeSMarri Devender Rao 6115968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 6125968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 6135968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 61426d3b0fbSChandra Harkude [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, name, 61526d3b0fbSChandra Harkude certificate](const boost::system::error_code& ec, 616d3e0859cSPatrick Williams sdbusplus::message_t& m) { 6175968caeeSMarri Devender Rao if (ec) 6185968caeeSMarri Devender Rao { 61962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 62026d3b0fbSChandra Harkude const sd_bus_error* dbusError = m.get_error(); 62126d3b0fbSChandra Harkude if ((dbusError != nullptr) && (dbusError->name != nullptr)) 62290d2d1e8SJiaqing Zhao { 62326d3b0fbSChandra Harkude handleError(dbusError->name, id, certificate, asyncResp); 6245968caeeSMarri Devender Rao } 62526d3b0fbSChandra Harkude else 62626d3b0fbSChandra Harkude { 62790d2d1e8SJiaqing Zhao messages::internalError(asyncResp->res); 62826d3b0fbSChandra Harkude } 62990d2d1e8SJiaqing Zhao return; 63090d2d1e8SJiaqing Zhao } 631bd79bce8SPatrick Williams getCertificateProperties(asyncResp, objectPath, service, id, url, 632bd79bce8SPatrick Williams name); 63362598e31SEd Tanous BMCWEB_LOG_DEBUG("HTTPS certificate install file={}", 63462598e31SEd Tanous certFile->getCertFilePath()); 6355968caeeSMarri Devender Rao }, 6365968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 6375968caeeSMarri Devender Rao certFile->getCertFilePath()); 638828252d5SJiaqing Zhao } 6395968caeeSMarri Devender Rao 640cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 641828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher; 6425968caeeSMarri Devender Rao /** 643828252d5SJiaqing Zhao * @brief Read data from CSR D-bus object and set to response 644828252d5SJiaqing Zhao * 645828252d5SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 6468ece0e45SEd Tanous * @param[in] certURI Link to certificate collection URI 647828252d5SJiaqing Zhao * @param[in] service D-Bus service name 648828252d5SJiaqing Zhao * @param[in] certObjPath certificate D-Bus object path 649828252d5SJiaqing Zhao * @param[in] csrObjPath CSR D-Bus object path 650828252d5SJiaqing Zhao * @return None 6515968caeeSMarri Devender Rao */ 6524ff0f1f4SEd Tanous inline void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 653828252d5SJiaqing Zhao const std::string& certURI, const std::string& service, 654828252d5SJiaqing Zhao const std::string& certObjPath, 655828252d5SJiaqing Zhao const std::string& csrObjPath) 6565968caeeSMarri Devender Rao { 65762598e31SEd Tanous BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}", 65862598e31SEd Tanous certObjPath, csrObjPath, service); 659828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 660bd79bce8SPatrick Williams [asyncResp, 661bd79bce8SPatrick Williams certURI](const boost::system::error_code& ec, const std::string& csr) { 662828252d5SJiaqing Zhao if (ec) 663828252d5SJiaqing Zhao { 66462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 665828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 666828252d5SJiaqing Zhao return; 667828252d5SJiaqing Zhao } 668828252d5SJiaqing Zhao if (csr.empty()) 669828252d5SJiaqing Zhao { 67062598e31SEd Tanous BMCWEB_LOG_ERROR("CSR read is empty"); 671828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 672828252d5SJiaqing Zhao return; 673828252d5SJiaqing Zhao } 674828252d5SJiaqing Zhao asyncResp->res.jsonValue["CSRString"] = csr; 675828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = 676828252d5SJiaqing Zhao certURI; 677828252d5SJiaqing Zhao }, 678828252d5SJiaqing Zhao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 679828252d5SJiaqing Zhao } 680828252d5SJiaqing Zhao 681828252d5SJiaqing Zhao inline void 682828252d5SJiaqing Zhao handleGenerateCSRAction(App& app, const crow::Request& req, 683828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 684828252d5SJiaqing Zhao { 6853ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 68645ca1b86SEd Tanous { 68745ca1b86SEd Tanous return; 68845ca1b86SEd Tanous } 689828252d5SJiaqing Zhao static const int rsaKeyBitLength = 2048; 6905968caeeSMarri Devender Rao 691828252d5SJiaqing Zhao // Required parameters 692828252d5SJiaqing Zhao std::string city; 693828252d5SJiaqing Zhao std::string commonName; 694828252d5SJiaqing Zhao std::string country; 695828252d5SJiaqing Zhao std::string organization; 696828252d5SJiaqing Zhao std::string organizationalUnit; 697828252d5SJiaqing Zhao std::string state; 6987a31e336SEd Tanous std::string certURI; 699828252d5SJiaqing Zhao 700828252d5SJiaqing Zhao // Optional parameters 701828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optAlternativeNames = 702828252d5SJiaqing Zhao std::vector<std::string>(); 703828252d5SJiaqing Zhao std::optional<std::string> optContactPerson = ""; 704828252d5SJiaqing Zhao std::optional<std::string> optChallengePassword = ""; 705828252d5SJiaqing Zhao std::optional<std::string> optEmail = ""; 706828252d5SJiaqing Zhao std::optional<std::string> optGivenName = ""; 707828252d5SJiaqing Zhao std::optional<std::string> optInitials = ""; 708828252d5SJiaqing Zhao std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 709828252d5SJiaqing Zhao std::optional<std::string> optKeyCurveId = "secp384r1"; 710828252d5SJiaqing Zhao std::optional<std::string> optKeyPairAlgorithm = "EC"; 711828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optKeyUsage = 712828252d5SJiaqing Zhao std::vector<std::string>(); 713828252d5SJiaqing Zhao std::optional<std::string> optSurname = ""; 714828252d5SJiaqing Zhao std::optional<std::string> optUnstructuredName = ""; 715afc474aeSMyung Bae if (!json_util::readJsonAction( // 716afc474aeSMyung Bae req, asyncResp->res, // 717afc474aeSMyung Bae "AlternativeNames", optAlternativeNames, // 718afc474aeSMyung Bae "CertificateCollection/@odata.id", certURI, // 719afc474aeSMyung Bae "ChallengePassword", optChallengePassword, // 720afc474aeSMyung Bae "City", city, // 721afc474aeSMyung Bae "CommonName", commonName, // 722afc474aeSMyung Bae "ContactPerson", optContactPerson, // 723afc474aeSMyung Bae "Country", country, // 724afc474aeSMyung Bae "Email", optEmail, // 725afc474aeSMyung Bae "GivenName", optGivenName, // 726afc474aeSMyung Bae "Initials", optInitials, // 727afc474aeSMyung Bae "KeyBitLength", optKeyBitLength, // 728afc474aeSMyung Bae "KeyCurveId", optKeyCurveId, // 729afc474aeSMyung Bae "KeyPairAlgorithm", optKeyPairAlgorithm, // 730afc474aeSMyung Bae "KeyUsage", optKeyUsage, // 731afc474aeSMyung Bae "Organization", organization, // 732afc474aeSMyung Bae "OrganizationalUnit", organizationalUnit, // 733afc474aeSMyung Bae "State", state, // 734afc474aeSMyung Bae "Surname", optSurname, // 735afc474aeSMyung Bae "UnstructuredName", optUnstructuredName // 736afc474aeSMyung Bae )) 737828252d5SJiaqing Zhao { 738828252d5SJiaqing Zhao return; 7395968caeeSMarri Devender Rao } 7405968caeeSMarri Devender Rao 741828252d5SJiaqing Zhao // bmcweb has no way to store or decode a private key challenge 742828252d5SJiaqing Zhao // password, which will likely cause bmcweb to crash on startup 743828252d5SJiaqing Zhao // if this is not set on a post so not allowing the user to set 744828252d5SJiaqing Zhao // value 745828252d5SJiaqing Zhao if (!optChallengePassword->empty()) 7465968caeeSMarri Devender Rao { 747828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 748828252d5SJiaqing Zhao "ChallengePassword"); 749828252d5SJiaqing Zhao return; 750828252d5SJiaqing Zhao } 751828252d5SJiaqing Zhao 752828252d5SJiaqing Zhao std::string objectPath; 753828252d5SJiaqing Zhao std::string service; 754253f11b8SEd Tanous if (certURI.starts_with(std::format( 755253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 756253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME))) 757828252d5SJiaqing Zhao { 758828252d5SJiaqing Zhao objectPath = certs::httpsObjectPath; 759828252d5SJiaqing Zhao service = certs::httpsServiceName; 760828252d5SJiaqing Zhao } 761828252d5SJiaqing Zhao else if (certURI.starts_with( 762828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 763828252d5SJiaqing Zhao { 764828252d5SJiaqing Zhao objectPath = certs::ldapObjectPath; 765828252d5SJiaqing Zhao service = certs::ldapServiceName; 766828252d5SJiaqing Zhao } 767828252d5SJiaqing Zhao else 768828252d5SJiaqing Zhao { 769828252d5SJiaqing Zhao messages::actionParameterNotSupported( 770828252d5SJiaqing Zhao asyncResp->res, "CertificateCollection", "GenerateCSR"); 771828252d5SJiaqing Zhao return; 772828252d5SJiaqing Zhao } 773828252d5SJiaqing Zhao 774828252d5SJiaqing Zhao // supporting only EC and RSA algorithm 775828252d5SJiaqing Zhao if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 776828252d5SJiaqing Zhao { 777828252d5SJiaqing Zhao messages::actionParameterNotSupported( 778828252d5SJiaqing Zhao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 779828252d5SJiaqing Zhao return; 780828252d5SJiaqing Zhao } 781828252d5SJiaqing Zhao 782828252d5SJiaqing Zhao // supporting only 2048 key bit length for RSA algorithm due to 783828252d5SJiaqing Zhao // time consumed in generating private key 784828252d5SJiaqing Zhao if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength) 785828252d5SJiaqing Zhao { 786e2616cc5SEd Tanous messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength, 787e2616cc5SEd Tanous "KeyBitLength"); 788828252d5SJiaqing Zhao return; 789828252d5SJiaqing Zhao } 790828252d5SJiaqing Zhao 791828252d5SJiaqing Zhao // validate KeyUsage supporting only 1 type based on URL 792253f11b8SEd Tanous if (certURI.starts_with(std::format( 793253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 794253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME))) 795828252d5SJiaqing Zhao { 796828252d5SJiaqing Zhao if (optKeyUsage->empty()) 797828252d5SJiaqing Zhao { 798b2ba3072SPatrick Williams optKeyUsage->emplace_back("ServerAuthentication"); 799828252d5SJiaqing Zhao } 800828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 801828252d5SJiaqing Zhao { 802828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ServerAuthentication") 803828252d5SJiaqing Zhao { 804828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 805828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 806828252d5SJiaqing Zhao return; 807828252d5SJiaqing Zhao } 808828252d5SJiaqing Zhao } 809828252d5SJiaqing Zhao else 810828252d5SJiaqing Zhao { 811828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 812828252d5SJiaqing Zhao "GenerateCSR"); 813828252d5SJiaqing Zhao return; 814828252d5SJiaqing Zhao } 815828252d5SJiaqing Zhao } 816828252d5SJiaqing Zhao else if (certURI.starts_with( 817828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 818828252d5SJiaqing Zhao { 819828252d5SJiaqing Zhao if (optKeyUsage->empty()) 820828252d5SJiaqing Zhao { 821b2ba3072SPatrick Williams optKeyUsage->emplace_back("ClientAuthentication"); 822828252d5SJiaqing Zhao } 823828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 824828252d5SJiaqing Zhao { 825828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ClientAuthentication") 826828252d5SJiaqing Zhao { 827828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 828828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 829828252d5SJiaqing Zhao return; 830828252d5SJiaqing Zhao } 831828252d5SJiaqing Zhao } 832828252d5SJiaqing Zhao else 833828252d5SJiaqing Zhao { 834828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 835828252d5SJiaqing Zhao "GenerateCSR"); 836828252d5SJiaqing Zhao return; 837828252d5SJiaqing Zhao } 838828252d5SJiaqing Zhao } 839828252d5SJiaqing Zhao 840828252d5SJiaqing Zhao // Only allow one CSR matcher at a time so setting retry 841828252d5SJiaqing Zhao // time-out and timer expiry to 10 seconds for now. 842828252d5SJiaqing Zhao static const int timeOut = 10; 843828252d5SJiaqing Zhao if (csrMatcher) 844828252d5SJiaqing Zhao { 845828252d5SJiaqing Zhao messages::serviceTemporarilyUnavailable(asyncResp->res, 846828252d5SJiaqing Zhao std::to_string(timeOut)); 847828252d5SJiaqing Zhao return; 848828252d5SJiaqing Zhao } 849828252d5SJiaqing Zhao 8508e8245dbSEd Tanous if (req.ioService == nullptr) 8518e8245dbSEd Tanous { 8528e8245dbSEd Tanous messages::internalError(asyncResp->res); 8538e8245dbSEd Tanous return; 8548e8245dbSEd Tanous } 8558e8245dbSEd Tanous 856828252d5SJiaqing Zhao // Make this static so it survives outside this method 857828252d5SJiaqing Zhao static boost::asio::steady_timer timeout(*req.ioService); 858828252d5SJiaqing Zhao timeout.expires_after(std::chrono::seconds(timeOut)); 859828252d5SJiaqing Zhao timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 860828252d5SJiaqing Zhao csrMatcher = nullptr; 861828252d5SJiaqing Zhao if (ec) 862828252d5SJiaqing Zhao { 863828252d5SJiaqing Zhao // operation_aborted is expected if timer is canceled 864828252d5SJiaqing Zhao // before completion. 865828252d5SJiaqing Zhao if (ec != boost::asio::error::operation_aborted) 866828252d5SJiaqing Zhao { 86762598e31SEd Tanous BMCWEB_LOG_ERROR("Async_wait failed {}", ec); 868828252d5SJiaqing Zhao } 869828252d5SJiaqing Zhao return; 870828252d5SJiaqing Zhao } 87162598e31SEd Tanous BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR"); 872828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 873828252d5SJiaqing Zhao }); 874828252d5SJiaqing Zhao 875828252d5SJiaqing Zhao // create a matcher to wait on CSR object 87662598e31SEd Tanous BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath); 877828252d5SJiaqing Zhao std::string match("type='signal'," 878828252d5SJiaqing Zhao "interface='org.freedesktop.DBus.ObjectManager'," 879828252d5SJiaqing Zhao "path='" + 880828252d5SJiaqing Zhao objectPath + 881828252d5SJiaqing Zhao "'," 882828252d5SJiaqing Zhao "member='InterfacesAdded'"); 883828252d5SJiaqing Zhao csrMatcher = std::make_unique<sdbusplus::bus::match_t>( 884828252d5SJiaqing Zhao *crow::connections::systemBus, match, 885828252d5SJiaqing Zhao [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { 886828252d5SJiaqing Zhao timeout.cancel(); 887828252d5SJiaqing Zhao if (m.is_method_error()) 888828252d5SJiaqing Zhao { 88962598e31SEd Tanous BMCWEB_LOG_ERROR("Dbus method error!!!"); 890828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 891828252d5SJiaqing Zhao return; 892828252d5SJiaqing Zhao } 893828252d5SJiaqing Zhao 89480f79a40SMichael Shen dbus::utility::DBusInterfacesMap interfacesProperties; 895828252d5SJiaqing Zhao 896828252d5SJiaqing Zhao sdbusplus::message::object_path csrObjectPath; 897828252d5SJiaqing Zhao m.read(csrObjectPath, interfacesProperties); 89862598e31SEd Tanous BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str); 899828252d5SJiaqing Zhao for (const auto& interface : interfacesProperties) 900828252d5SJiaqing Zhao { 901828252d5SJiaqing Zhao if (interface.first == "xyz.openbmc_project.Certs.CSR") 902828252d5SJiaqing Zhao { 903828252d5SJiaqing Zhao getCSR(asyncResp, certURI, service, objectPath, 904828252d5SJiaqing Zhao csrObjectPath.str); 905828252d5SJiaqing Zhao break; 906828252d5SJiaqing Zhao } 907828252d5SJiaqing Zhao } 908828252d5SJiaqing Zhao }); 909828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 9105e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, const std::string&) { 911828252d5SJiaqing Zhao if (ec) 912828252d5SJiaqing Zhao { 91362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message()); 914828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 915828252d5SJiaqing Zhao return; 916828252d5SJiaqing Zhao } 917828252d5SJiaqing Zhao }, 918828252d5SJiaqing Zhao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 919828252d5SJiaqing Zhao "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 920828252d5SJiaqing Zhao commonName, *optContactPerson, country, *optEmail, *optGivenName, 921828252d5SJiaqing Zhao *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm, 922828252d5SJiaqing Zhao *optKeyUsage, organization, organizationalUnit, state, *optSurname, 923828252d5SJiaqing Zhao *optUnstructuredName); 924828252d5SJiaqing Zhao } 925828252d5SJiaqing Zhao 926828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app) 927828252d5SJiaqing Zhao { 928828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") 929828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateService) 930002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 931828252d5SJiaqing Zhao std::bind_front(handleCertificateServiceGet, std::ref(app))); 932828252d5SJiaqing Zhao 933828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 934828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateLocations) 935828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 936828252d5SJiaqing Zhao std::bind_front(handleCertificateLocationsGet, std::ref(app))); 937828252d5SJiaqing Zhao 938828252d5SJiaqing Zhao BMCWEB_ROUTE( 939828252d5SJiaqing Zhao app, 940828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 941828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 942828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 943828252d5SJiaqing Zhao std::bind_front(handleReplaceCertificateAction, std::ref(app))); 944828252d5SJiaqing Zhao 945828252d5SJiaqing Zhao BMCWEB_ROUTE( 946828252d5SJiaqing Zhao app, 947828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 948828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 949828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 950828252d5SJiaqing Zhao std::bind_front(handleGenerateCSRAction, std::ref(app))); 951828252d5SJiaqing Zhao } // requestRoutesCertificateService 952828252d5SJiaqing Zhao 953828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet( 954828252d5SJiaqing Zhao App& app, const crow::Request& req, 955253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 956253f11b8SEd Tanous const std::string& managerId) 957828252d5SJiaqing Zhao { 9583ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 95945ca1b86SEd Tanous { 96045ca1b86SEd Tanous return; 96145ca1b86SEd Tanous } 9621476687dSEd Tanous 963253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 964253f11b8SEd Tanous { 965253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 966253f11b8SEd Tanous return; 967253f11b8SEd Tanous } 968253f11b8SEd Tanous 969253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 970253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 971253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 9721476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 9731476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 9741476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; 9751476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 9761476687dSEd Tanous "A Collection of HTTPS certificate instances"; 9778d1b46d7Szhanghch05 978d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::httpsObjectPath, 979d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 980d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 981828252d5SJiaqing Zhao } 9825968caeeSMarri Devender Rao 983828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost( 984828252d5SJiaqing Zhao App& app, const crow::Request& req, 985253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 986253f11b8SEd Tanous const std::string& managerId) 987828252d5SJiaqing Zhao { 9883ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 98945ca1b86SEd Tanous { 99045ca1b86SEd Tanous return; 99145ca1b86SEd Tanous } 992253f11b8SEd Tanous 993253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 994253f11b8SEd Tanous { 995253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 996253f11b8SEd Tanous return; 997253f11b8SEd Tanous } 998253f11b8SEd Tanous 99962598e31SEd Tanous BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost"); 10008d1b46d7Szhanghch05 10011476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; 10021476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; 10035968caeeSMarri Devender Rao 1004b2896149SEd Tanous std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 100558eb238fSKowalski, Kamil 1006b2896149SEd Tanous if (certHttpBody.empty()) 100758eb238fSKowalski, Kamil { 100862598e31SEd Tanous BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 1009a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 101058eb238fSKowalski, Kamil return; 101158eb238fSKowalski, Kamil } 101258eb238fSKowalski, Kamil 10135968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 1014b2896149SEd Tanous std::make_shared<CertificateFile>(certHttpBody); 10155968caeeSMarri Devender Rao 10165968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 10175e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 1018656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 10195968caeeSMarri Devender Rao if (ec) 10205968caeeSMarri Devender Rao { 102162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 10225968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 10235968caeeSMarri Devender Rao return; 10245968caeeSMarri Devender Rao } 1025717b9802SJiaqing Zhao 1026717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1027717b9802SJiaqing Zhao std::string certId = path.filename(); 1028ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1029253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 1030253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1031bd79bce8SPatrick Williams getCertificateProperties(asyncResp, objectPath, 1032bd79bce8SPatrick Williams certs::httpsServiceName, certId, certURL, 1033bd79bce8SPatrick Williams "HTTPS Certificate"); 103462598e31SEd Tanous BMCWEB_LOG_DEBUG("HTTPS certificate install file={}", 103562598e31SEd Tanous certFile->getCertFilePath()); 10365968caeeSMarri Devender Rao }, 1037828252d5SJiaqing Zhao certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf, 1038828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 1039828252d5SJiaqing Zhao } 10405968caeeSMarri Devender Rao 1041828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet( 1042828252d5SJiaqing Zhao App& app, const crow::Request& req, 1043253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1044253f11b8SEd Tanous const std::string& managerId, const std::string& certId) 10457e860f15SJohn Edward Broadbent { 10463ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 104745ca1b86SEd Tanous { 104845ca1b86SEd Tanous return; 104945ca1b86SEd Tanous } 10507e860f15SJohn Edward Broadbent 1051253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1052253f11b8SEd Tanous { 1053253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1054253f11b8SEd Tanous return; 1055253f11b8SEd Tanous } 1056253f11b8SEd Tanous 1057253f11b8SEd Tanous BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId); 1058ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1059253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 1060253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1061828252d5SJiaqing Zhao std::string objPath = 1062253f11b8SEd Tanous sdbusplus::message::object_path(certs::httpsObjectPath) / certId; 1063253f11b8SEd Tanous getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, 1064253f11b8SEd Tanous certId, certURL, "HTTPS Certificate"); 10657e860f15SJohn Edward Broadbent } 106637cce918SMarri Devender Rao 1067828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app) 106837cce918SMarri Devender Rao { 1069253f11b8SEd Tanous BMCWEB_ROUTE( 1070253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/") 1071ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 1072828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 1073828252d5SJiaqing Zhao handleHTTPSCertificateCollectionGet, std::ref(app))); 1074828252d5SJiaqing Zhao 1075253f11b8SEd Tanous BMCWEB_ROUTE( 1076253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/") 1077828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1078828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1079828252d5SJiaqing Zhao handleHTTPSCertificateCollectionPost, std::ref(app))); 1080828252d5SJiaqing Zhao 1081828252d5SJiaqing Zhao BMCWEB_ROUTE( 1082828252d5SJiaqing Zhao app, 1083253f11b8SEd Tanous "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/") 1084828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1085002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1086828252d5SJiaqing Zhao std::bind_front(handleHTTPSCertificateGet, std::ref(app))); 1087828252d5SJiaqing Zhao } 1088828252d5SJiaqing Zhao 1089828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet( 1090828252d5SJiaqing Zhao App& app, const crow::Request& req, 1091828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1092828252d5SJiaqing Zhao { 10933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 109445ca1b86SEd Tanous { 109545ca1b86SEd Tanous return; 109645ca1b86SEd Tanous } 10971476687dSEd Tanous 10981476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 10991476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 11001476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 11011476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 11021476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; 11031476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 11041476687dSEd Tanous "A Collection of LDAP certificate instances"; 11058d1b46d7Szhanghch05 1106d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::ldapObjectPath, 1107d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1108d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1109828252d5SJiaqing Zhao } 111037cce918SMarri Devender Rao 1111828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost( 1112828252d5SJiaqing Zhao App& app, const crow::Request& req, 1113828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1114828252d5SJiaqing Zhao { 11153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 111645ca1b86SEd Tanous { 111745ca1b86SEd Tanous return; 111845ca1b86SEd Tanous } 1119b2896149SEd Tanous std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 112058eb238fSKowalski, Kamil 1121b2896149SEd Tanous if (certHttpBody.empty()) 112258eb238fSKowalski, Kamil { 112362598e31SEd Tanous BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 1124a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 112558eb238fSKowalski, Kamil return; 112658eb238fSKowalski, Kamil } 112758eb238fSKowalski, Kamil 112858eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 1129b2896149SEd Tanous std::make_shared<CertificateFile>(certHttpBody); 113058eb238fSKowalski, Kamil 113137cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 11325e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 1133656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 113437cce918SMarri Devender Rao if (ec) 113537cce918SMarri Devender Rao { 113662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 113737cce918SMarri Devender Rao messages::internalError(asyncResp->res); 113837cce918SMarri Devender Rao return; 113937cce918SMarri Devender Rao } 1140717b9802SJiaqing Zhao 1141717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1142717b9802SJiaqing Zhao std::string certId = path.filename(); 1143ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1144ef4c65b7SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/{}", certId); 1145bd79bce8SPatrick Williams getCertificateProperties(asyncResp, objectPath, 1146bd79bce8SPatrick Williams certs::ldapServiceName, certId, certURL, 1147bd79bce8SPatrick Williams "LDAP Certificate"); 114862598e31SEd Tanous BMCWEB_LOG_DEBUG("LDAP certificate install file={}", 114962598e31SEd Tanous certFile->getCertFilePath()); 115037cce918SMarri Devender Rao }, 1151828252d5SJiaqing Zhao certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf, 1152828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 1153828252d5SJiaqing Zhao } 115437cce918SMarri Devender Rao 1155828252d5SJiaqing Zhao inline void handleLDAPCertificateGet( 1156828252d5SJiaqing Zhao App& app, const crow::Request& req, 1157828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 115837cce918SMarri Devender Rao { 11593ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 116045ca1b86SEd Tanous { 116145ca1b86SEd Tanous return; 116245ca1b86SEd Tanous } 1163717b9802SJiaqing Zhao 116462598e31SEd Tanous BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id); 1165ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1166ef4c65b7SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/{}", id); 1167717b9802SJiaqing Zhao std::string objPath = 1168717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 1169717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, 1170717b9802SJiaqing Zhao certURL, "LDAP Certificate"); 1171828252d5SJiaqing Zhao } 1172828252d5SJiaqing Zhao 117399612247SJiaqing Zhao inline void handleLDAPCertificateDelete( 117499612247SJiaqing Zhao App& app, const crow::Request& req, 117599612247SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 117699612247SJiaqing Zhao { 117799612247SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117899612247SJiaqing Zhao { 117999612247SJiaqing Zhao return; 118099612247SJiaqing Zhao } 118199612247SJiaqing Zhao 118262598e31SEd Tanous BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id); 118399612247SJiaqing Zhao std::string objPath = 118499612247SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 118599612247SJiaqing Zhao 118699612247SJiaqing Zhao deleteCertificate(asyncResp, certs::ldapServiceName, objPath); 118799612247SJiaqing Zhao } 118899612247SJiaqing Zhao 1189828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app) 1190cfcd5f6bSMarri Devender Rao { 1191828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1192828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateCollection) 1193828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1194828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app))); 1195828252d5SJiaqing Zhao 1196828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1197828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1198828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1199828252d5SJiaqing Zhao handleLDAPCertificateCollectionPost, std::ref(app))); 1200828252d5SJiaqing Zhao 1201828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1202ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 1203002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1204828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateGet, std::ref(app))); 120599612247SJiaqing Zhao 120699612247SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 120799612247SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 120899612247SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 120999612247SJiaqing Zhao std::bind_front(handleLDAPCertificateDelete, std::ref(app))); 1210828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate 1211828252d5SJiaqing Zhao 1212828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet( 1213828252d5SJiaqing Zhao App& app, const crow::Request& req, 1214253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1215253f11b8SEd Tanous const std::string& managerId) 1216828252d5SJiaqing Zhao { 12173ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 121845ca1b86SEd Tanous { 121945ca1b86SEd Tanous return; 122045ca1b86SEd Tanous } 12211476687dSEd Tanous 1222253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1223253f11b8SEd Tanous { 1224253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1225253f11b8SEd Tanous return; 1226253f11b8SEd Tanous } 1227253f11b8SEd Tanous 12281476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 1229253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/", 1230253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 12311476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 12321476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 1233002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; 12341476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 12351476687dSEd Tanous "A Collection of TrustStore certificate instances"; 12368d1b46d7Szhanghch05 1237d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::authorityObjectPath, 1238d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1239d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1240828252d5SJiaqing Zhao } 1241cfcd5f6bSMarri Devender Rao 1242828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost( 1243828252d5SJiaqing Zhao App& app, const crow::Request& req, 1244253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1245253f11b8SEd Tanous const std::string& managerId) 1246828252d5SJiaqing Zhao { 12473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 124845ca1b86SEd Tanous { 124945ca1b86SEd Tanous return; 125045ca1b86SEd Tanous } 1251253f11b8SEd Tanous 1252253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1253253f11b8SEd Tanous { 1254253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1255253f11b8SEd Tanous return; 1256253f11b8SEd Tanous } 1257253f11b8SEd Tanous 1258b2896149SEd Tanous std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 1259a08752f5SZbigniew Kurzynski 1260b2896149SEd Tanous if (certHttpBody.empty()) 1261a08752f5SZbigniew Kurzynski { 126262598e31SEd Tanous BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 1263a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1264a08752f5SZbigniew Kurzynski return; 1265a08752f5SZbigniew Kurzynski } 1266a08752f5SZbigniew Kurzynski 1267a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1268b2896149SEd Tanous std::make_shared<CertificateFile>(certHttpBody); 1269cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 12705e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 1271656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1272cfcd5f6bSMarri Devender Rao if (ec) 1273cfcd5f6bSMarri Devender Rao { 127462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 1275cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1276cfcd5f6bSMarri Devender Rao return; 1277cfcd5f6bSMarri Devender Rao } 1278656ec7e3SZbigniew Kurzynski 1279717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1280717b9802SJiaqing Zhao std::string certId = path.filename(); 1281ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1282253f11b8SEd Tanous "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 1283253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1284717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, 1285bd79bce8SPatrick Williams certs::authorityServiceName, certId, 1286bd79bce8SPatrick Williams certURL, "TrustStore Certificate"); 128762598e31SEd Tanous BMCWEB_LOG_DEBUG("TrustStore certificate install file={}", 128862598e31SEd Tanous certFile->getCertFilePath()); 1289cfcd5f6bSMarri Devender Rao }, 1290cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 12910fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 1292828252d5SJiaqing Zhao } 1293cfcd5f6bSMarri Devender Rao 1294828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet( 1295828252d5SJiaqing Zhao App& app, const crow::Request& req, 1296253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1297253f11b8SEd Tanous const std::string& managerId, const std::string& certId) 1298cfcd5f6bSMarri Devender Rao { 12993ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 130045ca1b86SEd Tanous { 130145ca1b86SEd Tanous return; 130245ca1b86SEd Tanous } 1303717b9802SJiaqing Zhao 1304253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1305253f11b8SEd Tanous { 1306253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1307253f11b8SEd Tanous return; 1308253f11b8SEd Tanous } 1309253f11b8SEd Tanous 1310253f11b8SEd Tanous BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId); 1311ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1312253f11b8SEd Tanous "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 1313253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1314717b9802SJiaqing Zhao std::string objPath = 1315253f11b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / certId; 1316828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::authorityServiceName, 1317253f11b8SEd Tanous certId, certURL, "TrustStore Certificate"); 1318828252d5SJiaqing Zhao } 131907a60299SZbigniew Kurzynski 1320828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete( 1321828252d5SJiaqing Zhao App& app, const crow::Request& req, 1322253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1323253f11b8SEd Tanous const std::string& managerId, const std::string& certId) 1324828252d5SJiaqing Zhao { 13253ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 132645ca1b86SEd Tanous { 132745ca1b86SEd Tanous return; 132845ca1b86SEd Tanous } 132907a60299SZbigniew Kurzynski 1330253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1331253f11b8SEd Tanous { 1332253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1333253f11b8SEd Tanous return; 1334253f11b8SEd Tanous } 1335253f11b8SEd Tanous 1336253f11b8SEd Tanous BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId); 1337717b9802SJiaqing Zhao std::string objPath = 1338253f11b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / certId; 133907a60299SZbigniew Kurzynski 13407a3a8f7aSJiaqing Zhao deleteCertificate(asyncResp, certs::authorityServiceName, objPath); 1341828252d5SJiaqing Zhao } 1342828252d5SJiaqing Zhao 1343828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app) 1344828252d5SJiaqing Zhao { 1345253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/") 1346828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1347828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 1348828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionGet, std::ref(app))); 1349828252d5SJiaqing Zhao 1350253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/") 1351828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1352828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1353828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionPost, std::ref(app))); 1354828252d5SJiaqing Zhao 1355253f11b8SEd Tanous BMCWEB_ROUTE(app, 1356253f11b8SEd Tanous "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/") 1357828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1358828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1359828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateGet, std::ref(app))); 1360828252d5SJiaqing Zhao 1361253f11b8SEd Tanous BMCWEB_ROUTE(app, 1362253f11b8SEd Tanous "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/") 1363828252d5SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 1364828252d5SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 1365828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateDelete, std::ref(app))); 13667e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate 13675968caeeSMarri Devender Rao } // namespace redfish 1368