1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 35968caeeSMarri Devender Rao #pragma once 45968caeeSMarri Devender Rao 53ccb3adbSEd Tanous #include "app.hpp" 63ccb3adbSEd Tanous #include "async_resp.hpp" 77a1dbc48SGeorge Liu #include "dbus_utility.hpp" 81aa0c2b8SEd Tanous #include "http/parsing.hpp" 93ccb3adbSEd Tanous #include "http_response.hpp" 103ccb3adbSEd Tanous #include "query.hpp" 113ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 129b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp" 133ccb3adbSEd Tanous #include "utils/json_utils.hpp" 143ccb3adbSEd Tanous #include "utils/time_utils.hpp" 159b12d1f9SKrzysztof Grobelny 1690d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp> 17ef4c65b7SEd Tanous #include <boost/url/format.hpp> 189b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 193ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp> 209b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 211214b7e7SGunnar Mills 227a1dbc48SGeorge Liu #include <array> 233ccb3adbSEd Tanous #include <memory> 247a1dbc48SGeorge Liu #include <string_view> 257a1dbc48SGeorge Liu 265968caeeSMarri Devender Rao namespace redfish 275968caeeSMarri Devender Rao { 285968caeeSMarri Devender Rao namespace certs 295968caeeSMarri Devender Rao { 3089492a15SPatrick Williams constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 3189492a15SPatrick Williams constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 3289492a15SPatrick Williams constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 3389492a15SPatrick Williams constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 3489492a15SPatrick Williams constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties"; 3589492a15SPatrick Williams constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 3689492a15SPatrick Williams constexpr const char* httpsServiceName = 3737cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Server.Https"; 3889492a15SPatrick Williams constexpr const char* ldapServiceName = 3937cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 4089492a15SPatrick Williams constexpr const char* authorityServiceName = 41b2254ccdSMichal Orzel "xyz.openbmc_project.Certs.Manager.Authority.Truststore"; 4289492a15SPatrick Williams constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs"; 4389492a15SPatrick Williams constexpr const char* httpsObjectPath = 44c6a8dfb1SJiaqing Zhao "/xyz/openbmc_project/certs/server/https"; 4589492a15SPatrick Williams constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 4689492a15SPatrick Williams constexpr const char* authorityObjectPath = 47b2254ccdSMichal Orzel "/xyz/openbmc_project/certs/authority/truststore"; 485968caeeSMarri Devender Rao } // namespace certs 495968caeeSMarri Devender Rao 505968caeeSMarri Devender Rao /** 515968caeeSMarri Devender Rao * The Certificate schema defines a Certificate Service which represents the 525968caeeSMarri Devender Rao * actions available to manage certificates and links to where certificates 535968caeeSMarri Devender Rao * are installed. 545968caeeSMarri Devender Rao */ 557e860f15SJohn Edward Broadbent 568d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody( 578d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5858eb238fSKowalski, Kamil const crow::Request& req) 5958eb238fSKowalski, Kamil { 601aa0c2b8SEd Tanous nlohmann::json reqJson; 611aa0c2b8SEd Tanous JsonParseResult ret = parseRequestAsJson(req, reqJson); 621aa0c2b8SEd Tanous if (ret != JsonParseResult::Success) 6358eb238fSKowalski, Kamil { 6458eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 6533c6b580SEd Tanous return req.body(); 6658eb238fSKowalski, Kamil } 6758eb238fSKowalski, Kamil 6858eb238fSKowalski, Kamil std::string certificate; 6958eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 7058eb238fSKowalski, Kamil 71afc474aeSMyung Bae if (!json_util::readJsonPatch( // 72afc474aeSMyung Bae req, asyncResp->res, // 73afc474aeSMyung Bae "CertificateString", certificate, // 74afc474aeSMyung Bae "CertificateType", certificateType // 75afc474aeSMyung Bae )) 7658eb238fSKowalski, Kamil { 7762598e31SEd Tanous BMCWEB_LOG_ERROR("Required parameters are missing"); 7858eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 79abb93cddSEd Tanous return {}; 8058eb238fSKowalski, Kamil } 8158eb238fSKowalski, Kamil 8258eb238fSKowalski, Kamil if (*certificateType != "PEM") 8358eb238fSKowalski, Kamil { 8458eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 8558eb238fSKowalski, Kamil "CertificateType"); 86abb93cddSEd Tanous return {}; 8758eb238fSKowalski, Kamil } 8858eb238fSKowalski, Kamil 8958eb238fSKowalski, Kamil return certificate; 9058eb238fSKowalski, Kamil } 9158eb238fSKowalski, Kamil 925968caeeSMarri Devender Rao /** 935968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 945968caeeSMarri Devender Rao */ 955968caeeSMarri Devender Rao class CertificateFile 965968caeeSMarri Devender Rao { 975968caeeSMarri Devender Rao public: 985968caeeSMarri Devender Rao CertificateFile() = delete; 995968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 1005968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 1015968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 1025968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 1034e23a444SEd Tanous explicit CertificateFile(const std::string& certString) 1045968caeeSMarri Devender Rao { 10572d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 1065207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 1075207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 1085207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 109e662eae8SEd Tanous if (tempDirectory != nullptr) 1105968caeeSMarri Devender Rao { 1115968caeeSMarri Devender Rao certDirectory = tempDirectory; 1125968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 113bd79bce8SPatrick Williams std::ofstream out(certificateFile, 114bd79bce8SPatrick Williams std::ofstream::out | std::ofstream::binary | 1155968caeeSMarri Devender Rao std::ofstream::trunc); 1165968caeeSMarri Devender Rao out << certString; 1175968caeeSMarri Devender Rao out.close(); 11862598e31SEd Tanous BMCWEB_LOG_DEBUG("Creating certificate file{}", 11962598e31SEd Tanous certificateFile.string()); 1205968caeeSMarri Devender Rao } 1215968caeeSMarri Devender Rao } 1225968caeeSMarri Devender Rao ~CertificateFile() 1235968caeeSMarri Devender Rao { 1245968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1255968caeeSMarri Devender Rao { 12662598e31SEd Tanous BMCWEB_LOG_DEBUG("Removing certificate file{}", 12762598e31SEd Tanous certificateFile.string()); 12823a21a1cSEd Tanous std::error_code ec; 12923a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 13023a21a1cSEd Tanous if (ec) 1315968caeeSMarri Devender Rao { 13262598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to remove temp directory{}", 13362598e31SEd Tanous certDirectory.string()); 1345968caeeSMarri Devender Rao } 1355968caeeSMarri Devender Rao } 1365968caeeSMarri Devender Rao } 1375968caeeSMarri Devender Rao std::string getCertFilePath() 1385968caeeSMarri Devender Rao { 1395968caeeSMarri Devender Rao return certificateFile; 1405968caeeSMarri Devender Rao } 1415968caeeSMarri Devender Rao 1425968caeeSMarri Devender Rao private: 1435968caeeSMarri Devender Rao std::filesystem::path certificateFile; 1445968caeeSMarri Devender Rao std::filesystem::path certDirectory; 1455968caeeSMarri Devender Rao }; 1465968caeeSMarri Devender Rao 1475968caeeSMarri Devender Rao /** 1484e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 1495968caeeSMarri Devender Rao * 1505968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 1515968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 1525968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 1535968caeeSMarri Devender Rao * @return None 1545968caeeSMarri Devender Rao */ 1554ff0f1f4SEd Tanous inline void updateCertIssuerOrSubject(nlohmann::json& out, 15626ccae32SEd Tanous std::string_view value) 1575968caeeSMarri Devender Rao { 1585968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 1595968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 1605968caeeSMarri Devender Rao while (i != value.end()) 1615968caeeSMarri Devender Rao { 1625968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 1635968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 1645968caeeSMarri Devender Rao { 1656da47babSPatrick Williams std::advance(i, 1); 1665968caeeSMarri Devender Rao } 1675968caeeSMarri Devender Rao if (i == value.end()) 1685968caeeSMarri Devender Rao { 1695968caeeSMarri Devender Rao break; 1705968caeeSMarri Devender Rao } 17126ccae32SEd Tanous std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin)); 1726da47babSPatrick Williams std::advance(i, 1); 1735968caeeSMarri Devender Rao tokenBegin = i; 1745968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 1755968caeeSMarri Devender Rao { 1766da47babSPatrick Williams std::advance(i, 1); 1775968caeeSMarri Devender Rao } 17826ccae32SEd Tanous std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin)); 1795968caeeSMarri Devender Rao if (key == "L") 1805968caeeSMarri Devender Rao { 1815968caeeSMarri Devender Rao out["City"] = val; 1825968caeeSMarri Devender Rao } 1835968caeeSMarri Devender Rao else if (key == "CN") 1845968caeeSMarri Devender Rao { 1855968caeeSMarri Devender Rao out["CommonName"] = val; 1865968caeeSMarri Devender Rao } 1875968caeeSMarri Devender Rao else if (key == "C") 1885968caeeSMarri Devender Rao { 1895968caeeSMarri Devender Rao out["Country"] = val; 1905968caeeSMarri Devender Rao } 1915968caeeSMarri Devender Rao else if (key == "O") 1925968caeeSMarri Devender Rao { 1935968caeeSMarri Devender Rao out["Organization"] = val; 1945968caeeSMarri Devender Rao } 1955968caeeSMarri Devender Rao else if (key == "OU") 1965968caeeSMarri Devender Rao { 1975968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 1985968caeeSMarri Devender Rao } 1995968caeeSMarri Devender Rao else if (key == "ST") 2005968caeeSMarri Devender Rao { 2015968caeeSMarri Devender Rao out["State"] = val; 2025968caeeSMarri Devender Rao } 2035968caeeSMarri Devender Rao // skip comma character 2045968caeeSMarri Devender Rao if (i != value.end()) 2055968caeeSMarri Devender Rao { 2066da47babSPatrick Williams std::advance(i, 1); 2075968caeeSMarri Devender Rao } 2085968caeeSMarri Devender Rao } 2095968caeeSMarri Devender Rao } 2105968caeeSMarri Devender Rao 2115968caeeSMarri Devender Rao /** 212d3f92ce7SJiaqing Zhao * @brief Retrieve the installed certificate list 213d3f92ce7SJiaqing Zhao * 214d3f92ce7SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 215d3f92ce7SJiaqing Zhao * @param[in] basePath DBus object path to search 216d3f92ce7SJiaqing Zhao * @param[in] listPtr Json pointer to the list in asyncResp 217d3f92ce7SJiaqing Zhao * @param[in] countPtr Json pointer to the count in asyncResp 218d3f92ce7SJiaqing Zhao * @return None 219d3f92ce7SJiaqing Zhao */ 2204ff0f1f4SEd Tanous inline void getCertificateList( 221bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 222bd79bce8SPatrick Williams const std::string& basePath, const nlohmann::json::json_pointer& listPtr, 223d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& countPtr) 224d3f92ce7SJiaqing Zhao { 2257a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 2267a1dbc48SGeorge Liu certs::certPropIntf}; 2277a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 2287a1dbc48SGeorge Liu basePath, 0, interfaces, 229d3f92ce7SJiaqing Zhao [asyncResp, listPtr, countPtr]( 2307a1dbc48SGeorge Liu const boost::system::error_code& ec, 231d3f92ce7SJiaqing Zhao const dbus::utility::MapperGetSubTreePathsResponse& certPaths) { 232d3f92ce7SJiaqing Zhao if (ec) 233d3f92ce7SJiaqing Zhao { 23462598e31SEd Tanous BMCWEB_LOG_ERROR("Certificate collection query failed: {}", ec); 235d3f92ce7SJiaqing Zhao messages::internalError(asyncResp->res); 236d3f92ce7SJiaqing Zhao return; 237d3f92ce7SJiaqing Zhao } 238d3f92ce7SJiaqing Zhao 239d3f92ce7SJiaqing Zhao nlohmann::json& links = asyncResp->res.jsonValue[listPtr]; 240d3f92ce7SJiaqing Zhao links = nlohmann::json::array(); 241d3f92ce7SJiaqing Zhao for (const auto& certPath : certPaths) 242d3f92ce7SJiaqing Zhao { 243d3f92ce7SJiaqing Zhao sdbusplus::message::object_path objPath(certPath); 244d3f92ce7SJiaqing Zhao std::string certId = objPath.filename(); 245d3f92ce7SJiaqing Zhao if (certId.empty()) 246d3f92ce7SJiaqing Zhao { 247bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("Invalid certificate objPath {}", 248bd79bce8SPatrick Williams certPath); 249d3f92ce7SJiaqing Zhao continue; 250d3f92ce7SJiaqing Zhao } 251d3f92ce7SJiaqing Zhao 252d3f92ce7SJiaqing Zhao boost::urls::url certURL; 253d3f92ce7SJiaqing Zhao if (objPath.parent_path() == certs::httpsObjectPath) 254d3f92ce7SJiaqing Zhao { 255ef4c65b7SEd Tanous certURL = boost::urls::format( 256253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 257253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 258d3f92ce7SJiaqing Zhao } 259d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::ldapObjectPath) 260d3f92ce7SJiaqing Zhao { 261ef4c65b7SEd Tanous certURL = boost::urls::format( 262bd79bce8SPatrick Williams "/redfish/v1/AccountService/LDAP/Certificates/{}", 263bd79bce8SPatrick Williams certId); 264d3f92ce7SJiaqing Zhao } 265d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::authorityObjectPath) 266d3f92ce7SJiaqing Zhao { 267ef4c65b7SEd Tanous certURL = boost::urls::format( 268253f11b8SEd Tanous "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 269253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 270d3f92ce7SJiaqing Zhao } 271d3f92ce7SJiaqing Zhao else 272d3f92ce7SJiaqing Zhao { 273d3f92ce7SJiaqing Zhao continue; 274d3f92ce7SJiaqing Zhao } 275d3f92ce7SJiaqing Zhao 276d3f92ce7SJiaqing Zhao nlohmann::json::object_t link; 277d3f92ce7SJiaqing Zhao link["@odata.id"] = certURL; 278d3f92ce7SJiaqing Zhao links.emplace_back(std::move(link)); 279d3f92ce7SJiaqing Zhao } 280d3f92ce7SJiaqing Zhao 281d3f92ce7SJiaqing Zhao asyncResp->res.jsonValue[countPtr] = links.size(); 2827a1dbc48SGeorge Liu }); 283d3f92ce7SJiaqing Zhao } 284d3f92ce7SJiaqing Zhao 285d3f92ce7SJiaqing Zhao /** 2865968caeeSMarri Devender Rao * @brief Retrieve the certificates properties and append to the response 2875968caeeSMarri Devender Rao * message 2885968caeeSMarri Devender Rao * 2895968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 2905968caeeSMarri Devender Rao * @param[in] objectPath Path of the D-Bus service object 2915968caeeSMarri Devender Rao * @param[in] certId Id of the certificate 2925968caeeSMarri Devender Rao * @param[in] certURL URL of the certificate object 2935968caeeSMarri Devender Rao * @param[in] name name of the certificate 2945968caeeSMarri Devender Rao * @return None 2955968caeeSMarri Devender Rao */ 2964ff0f1f4SEd Tanous inline void getCertificateProperties( 2978d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 298e19e97e2SJiaqing Zhao const std::string& objectPath, const std::string& service, 2991e312598SJiaqing Zhao const std::string& certId, const boost::urls::url& certURL, 300e19e97e2SJiaqing Zhao const std::string& name) 3015968caeeSMarri Devender Rao { 30262598e31SEd Tanous BMCWEB_LOG_DEBUG("getCertificateProperties Path={} certId={} certURl={}", 30362598e31SEd Tanous objectPath, certId, certURL); 304deae6a78SEd Tanous dbus::utility::getAllProperties( 305deae6a78SEd Tanous service, objectPath, certs::certPropIntf, 306b9d36b47SEd Tanous [asyncResp, certURL, certId, 3075e7e2dc5SEd Tanous name](const boost::system::error_code& ec, 308b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& properties) { 3095968caeeSMarri Devender Rao if (ec) 3105968caeeSMarri Devender Rao { 31162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 312bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Certificate", 313bd79bce8SPatrick Williams certId); 3145968caeeSMarri Devender Rao return; 3155968caeeSMarri Devender Rao } 3169b12d1f9SKrzysztof Grobelny 3179b12d1f9SKrzysztof Grobelny const std::string* certificateString = nullptr; 3189b12d1f9SKrzysztof Grobelny const std::vector<std::string>* keyUsage = nullptr; 3199b12d1f9SKrzysztof Grobelny const std::string* issuer = nullptr; 3209b12d1f9SKrzysztof Grobelny const std::string* subject = nullptr; 3219b12d1f9SKrzysztof Grobelny const uint64_t* validNotAfter = nullptr; 3229b12d1f9SKrzysztof Grobelny const uint64_t* validNotBefore = nullptr; 3239b12d1f9SKrzysztof Grobelny 3249b12d1f9SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 325bd79bce8SPatrick Williams dbus_utils::UnpackErrorPrinter(), properties, 326bd79bce8SPatrick Williams "CertificateString", certificateString, "KeyUsage", keyUsage, 327bd79bce8SPatrick Williams "Issuer", issuer, "Subject", subject, "ValidNotAfter", 328bd79bce8SPatrick Williams validNotAfter, "ValidNotBefore", validNotBefore); 3299b12d1f9SKrzysztof Grobelny 3309b12d1f9SKrzysztof Grobelny if (!success) 3319b12d1f9SKrzysztof Grobelny { 3329b12d1f9SKrzysztof Grobelny messages::internalError(asyncResp->res); 3339b12d1f9SKrzysztof Grobelny return; 3349b12d1f9SKrzysztof Grobelny } 3359b12d1f9SKrzysztof Grobelny 3361476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = certURL; 3371476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3381476687dSEd Tanous "#Certificate.v1_0_0.Certificate"; 339e19e97e2SJiaqing Zhao asyncResp->res.jsonValue["Id"] = certId; 3401476687dSEd Tanous asyncResp->res.jsonValue["Name"] = name; 3411476687dSEd Tanous asyncResp->res.jsonValue["Description"] = name; 3425968caeeSMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = ""; 3439b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array(); 3449b12d1f9SKrzysztof Grobelny 3459b12d1f9SKrzysztof Grobelny if (certificateString != nullptr) 3465968caeeSMarri Devender Rao { 347bd79bce8SPatrick Williams asyncResp->res.jsonValue["CertificateString"] = 348bd79bce8SPatrick Williams *certificateString; 3495968caeeSMarri Devender Rao } 3509b12d1f9SKrzysztof Grobelny 3519b12d1f9SKrzysztof Grobelny if (keyUsage != nullptr) 3525968caeeSMarri Devender Rao { 3539b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = *keyUsage; 3545968caeeSMarri Devender Rao } 3559b12d1f9SKrzysztof Grobelny 3569b12d1f9SKrzysztof Grobelny if (issuer != nullptr) 3575968caeeSMarri Devender Rao { 3589b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"], 3599b12d1f9SKrzysztof Grobelny *issuer); 3605968caeeSMarri Devender Rao } 3619b12d1f9SKrzysztof Grobelny 3629b12d1f9SKrzysztof Grobelny if (subject != nullptr) 3635968caeeSMarri Devender Rao { 3649b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"], 3659b12d1f9SKrzysztof Grobelny *subject); 3665968caeeSMarri Devender Rao } 3679b12d1f9SKrzysztof Grobelny 3689b12d1f9SKrzysztof Grobelny if (validNotAfter != nullptr) 3695968caeeSMarri Devender Rao { 3705968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotAfter"] = 3719b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotAfter); 3725968caeeSMarri Devender Rao } 3739b12d1f9SKrzysztof Grobelny 3749b12d1f9SKrzysztof Grobelny if (validNotBefore != nullptr) 3755968caeeSMarri Devender Rao { 3765968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotBefore"] = 3779b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotBefore); 3785968caeeSMarri Devender Rao } 3799b12d1f9SKrzysztof Grobelny 3801e312598SJiaqing Zhao asyncResp->res.addHeader( 381d9f6c621SEd Tanous boost::beast::http::field::location, 382d9f6c621SEd Tanous std::string_view(certURL.data(), certURL.size())); 3839b12d1f9SKrzysztof Grobelny }); 3845968caeeSMarri Devender Rao } 3855968caeeSMarri Devender Rao 3864ff0f1f4SEd Tanous inline void 3877a3a8f7aSJiaqing Zhao deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3887a3a8f7aSJiaqing Zhao const std::string& service, 3897a3a8f7aSJiaqing Zhao const sdbusplus::message::object_path& objectPath) 3907a3a8f7aSJiaqing Zhao { 3917a3a8f7aSJiaqing Zhao crow::connections::systemBus->async_method_call( 3927a3a8f7aSJiaqing Zhao [asyncResp, 3935e7e2dc5SEd Tanous id{objectPath.filename()}](const boost::system::error_code& ec) { 3947a3a8f7aSJiaqing Zhao if (ec) 3957a3a8f7aSJiaqing Zhao { 3967a3a8f7aSJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 3977a3a8f7aSJiaqing Zhao return; 3987a3a8f7aSJiaqing Zhao } 39962598e31SEd Tanous BMCWEB_LOG_INFO("Certificate deleted"); 4007a3a8f7aSJiaqing Zhao asyncResp->res.result(boost::beast::http::status::no_content); 4017a3a8f7aSJiaqing Zhao }, 4027a3a8f7aSJiaqing Zhao service, objectPath, certs::objDeleteIntf, "Delete"); 4037a3a8f7aSJiaqing Zhao } 4047a3a8f7aSJiaqing Zhao 405828252d5SJiaqing Zhao inline void handleCertificateServiceGet( 406828252d5SJiaqing Zhao App& app, const crow::Request& req, 407828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 4085968caeeSMarri Devender Rao { 409828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 410828252d5SJiaqing Zhao { 411828252d5SJiaqing Zhao return; 412828252d5SJiaqing Zhao } 413828252d5SJiaqing Zhao 4143e72c202SNinad Palsule if (req.session == nullptr) 4153e72c202SNinad Palsule { 4163e72c202SNinad Palsule messages::internalError(asyncResp->res); 4173e72c202SNinad Palsule return; 4183e72c202SNinad Palsule } 4193e72c202SNinad Palsule 420828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 421828252d5SJiaqing Zhao "#CertificateService.v1_0_0.CertificateService"; 422828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService"; 423828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateService"; 424828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Service"; 425828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 426828252d5SJiaqing Zhao "Actions available to manage certificates"; 427828252d5SJiaqing Zhao // /redfish/v1/CertificateService/CertificateLocations is something 428828252d5SJiaqing Zhao // only ConfigureManager can access then only display when the user 429828252d5SJiaqing Zhao // has permissions ConfigureManager 430828252d5SJiaqing Zhao Privileges effectiveUserPrivileges = 4313e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 432828252d5SJiaqing Zhao if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 433828252d5SJiaqing Zhao effectiveUserPrivileges)) 434828252d5SJiaqing Zhao { 435828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = 436828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 437828252d5SJiaqing Zhao } 438828252d5SJiaqing Zhao nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; 439828252d5SJiaqing Zhao nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"]; 440828252d5SJiaqing Zhao replace["target"] = 441828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; 442828252d5SJiaqing Zhao nlohmann::json::array_t allowed; 443ad539545SPatrick Williams allowed.emplace_back("PEM"); 444828252d5SJiaqing Zhao replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); 445828252d5SJiaqing Zhao actions["#CertificateService.GenerateCSR"]["target"] = 446828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; 447828252d5SJiaqing Zhao } 448828252d5SJiaqing Zhao 449828252d5SJiaqing Zhao inline void handleCertificateLocationsGet( 450828252d5SJiaqing Zhao App& app, const crow::Request& req, 451828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 452828252d5SJiaqing Zhao { 453828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 454828252d5SJiaqing Zhao { 455828252d5SJiaqing Zhao return; 456828252d5SJiaqing Zhao } 457828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = 458828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 459828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 460828252d5SJiaqing Zhao "#CertificateLocations.v1_0_0.CertificateLocations"; 461828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Locations"; 462828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateLocations"; 463828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 464828252d5SJiaqing Zhao "Defines a resource that an administrator can use in order to " 465828252d5SJiaqing Zhao "locate all certificates installed on a given service"; 466828252d5SJiaqing Zhao 467828252d5SJiaqing Zhao getCertificateList(asyncResp, certs::baseObjectPath, 468828252d5SJiaqing Zhao "/Links/Certificates"_json_pointer, 469828252d5SJiaqing Zhao "/Links/Certificates@odata.count"_json_pointer); 470828252d5SJiaqing Zhao } 471828252d5SJiaqing Zhao 47226d3b0fbSChandra Harkude inline void handleError(const std::string_view dbusErrorName, 47326d3b0fbSChandra Harkude const std::string& id, const std::string& certificate, 47426d3b0fbSChandra Harkude const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 47526d3b0fbSChandra Harkude { 47626d3b0fbSChandra Harkude if (dbusErrorName == "org.freedesktop.DBus.Error.UnknownObject") 47726d3b0fbSChandra Harkude { 47826d3b0fbSChandra Harkude messages::resourceNotFound(asyncResp->res, "Certificate", id); 47926d3b0fbSChandra Harkude } 48026d3b0fbSChandra Harkude else if (dbusErrorName == 48126d3b0fbSChandra Harkude "xyz.openbmc_project.Certs.Error.InvalidCertificate") 48226d3b0fbSChandra Harkude { 48326d3b0fbSChandra Harkude messages::propertyValueIncorrect(asyncResp->res, "Certificate", 48426d3b0fbSChandra Harkude certificate); 48526d3b0fbSChandra Harkude } 48626d3b0fbSChandra Harkude else 48726d3b0fbSChandra Harkude { 48826d3b0fbSChandra Harkude messages::internalError(asyncResp->res); 48926d3b0fbSChandra Harkude } 49026d3b0fbSChandra Harkude } 49126d3b0fbSChandra Harkude 492828252d5SJiaqing Zhao inline void handleReplaceCertificateAction( 493828252d5SJiaqing Zhao App& app, const crow::Request& req, 494828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 495828252d5SJiaqing Zhao { 4963ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 49745ca1b86SEd Tanous { 49845ca1b86SEd Tanous return; 49945ca1b86SEd Tanous } 5005968caeeSMarri Devender Rao std::string certificate; 5017a31e336SEd Tanous std::string certURI; 5025968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 5038d1b46d7Szhanghch05 504afc474aeSMyung Bae if (!json_util::readJsonAction( // 505afc474aeSMyung Bae req, asyncResp->res, // 506afc474aeSMyung Bae "CertificateString", certificate, // 507afc474aeSMyung Bae "CertificateType", certificateType, // 508afc474aeSMyung Bae "CertificateUri/@odata.id", certURI // 509afc474aeSMyung Bae )) 5105968caeeSMarri Devender Rao { 51162598e31SEd Tanous BMCWEB_LOG_ERROR("Required parameters are missing"); 5125968caeeSMarri Devender Rao return; 5135968caeeSMarri Devender Rao } 5145968caeeSMarri Devender Rao 5155968caeeSMarri Devender Rao if (!certificateType) 5165968caeeSMarri Devender Rao { 5175968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 5185968caeeSMarri Devender Rao return; 5195968caeeSMarri Devender Rao } 5205968caeeSMarri Devender Rao if (certificateType != "PEM") 5215968caeeSMarri Devender Rao { 522828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateType", 523828252d5SJiaqing Zhao "ReplaceCertificate"); 5245968caeeSMarri Devender Rao return; 5255968caeeSMarri Devender Rao } 5265968caeeSMarri Devender Rao 52762598e31SEd Tanous BMCWEB_LOG_INFO("Certificate URI to replace: {}", certURI); 5285968caeeSMarri Devender Rao 5296fd29553SEd Tanous boost::system::result<boost::urls::url> parsedUrl = 53075b63a2cSJiaqing Zhao boost::urls::parse_relative_ref(certURI); 53175b63a2cSJiaqing Zhao if (!parsedUrl) 5325968caeeSMarri Devender Rao { 533828252d5SJiaqing Zhao messages::actionParameterValueFormatError( 534828252d5SJiaqing Zhao asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate"); 5355968caeeSMarri Devender Rao return; 5365968caeeSMarri Devender Rao } 53775b63a2cSJiaqing Zhao 53875b63a2cSJiaqing Zhao std::string id; 53975b63a2cSJiaqing Zhao sdbusplus::message::object_path objectPath; 5405968caeeSMarri Devender Rao std::string name; 54137cce918SMarri Devender Rao std::string service; 542828252d5SJiaqing Zhao if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers", 543828252d5SJiaqing Zhao "bmc", "NetworkProtocol", "HTTPS", 544828252d5SJiaqing Zhao "Certificates", std::ref(id))) 5455968caeeSMarri Devender Rao { 54689492a15SPatrick Williams objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) / 54789492a15SPatrick Williams id; 5485968caeeSMarri Devender Rao name = "HTTPS certificate"; 54937cce918SMarri Devender Rao service = certs::httpsServiceName; 55037cce918SMarri Devender Rao } 55175b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 55275b63a2cSJiaqing Zhao "AccountService", "LDAP", 55375b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 55437cce918SMarri Devender Rao { 55589492a15SPatrick Williams objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) / 55689492a15SPatrick Williams id; 55737cce918SMarri Devender Rao name = "LDAP certificate"; 55837cce918SMarri Devender Rao service = certs::ldapServiceName; 5595968caeeSMarri Devender Rao } 56075b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 56175b63a2cSJiaqing Zhao "Managers", "bmc", "Truststore", 56275b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 563cfcd5f6bSMarri Devender Rao { 56475b63a2cSJiaqing Zhao objectPath = 565828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 566cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 567cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 568cfcd5f6bSMarri Devender Rao } 5695968caeeSMarri Devender Rao else 5705968caeeSMarri Devender Rao { 571828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateUri", 572828252d5SJiaqing Zhao "ReplaceCertificate"); 5735968caeeSMarri Devender Rao return; 5745968caeeSMarri Devender Rao } 5755968caeeSMarri Devender Rao 5765968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 5775968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 5785968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 57926d3b0fbSChandra Harkude [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, name, 58026d3b0fbSChandra Harkude certificate](const boost::system::error_code& ec, 581d3e0859cSPatrick Williams sdbusplus::message_t& m) { 5825968caeeSMarri Devender Rao if (ec) 5835968caeeSMarri Devender Rao { 58462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 58526d3b0fbSChandra Harkude const sd_bus_error* dbusError = m.get_error(); 58626d3b0fbSChandra Harkude if ((dbusError != nullptr) && (dbusError->name != nullptr)) 58790d2d1e8SJiaqing Zhao { 58826d3b0fbSChandra Harkude handleError(dbusError->name, id, certificate, asyncResp); 5895968caeeSMarri Devender Rao } 59026d3b0fbSChandra Harkude else 59126d3b0fbSChandra Harkude { 59290d2d1e8SJiaqing Zhao messages::internalError(asyncResp->res); 59326d3b0fbSChandra Harkude } 59490d2d1e8SJiaqing Zhao return; 59590d2d1e8SJiaqing Zhao } 596bd79bce8SPatrick Williams getCertificateProperties(asyncResp, objectPath, service, id, url, 597bd79bce8SPatrick Williams name); 59862598e31SEd Tanous BMCWEB_LOG_DEBUG("HTTPS certificate install file={}", 59962598e31SEd Tanous certFile->getCertFilePath()); 6005968caeeSMarri Devender Rao }, 6015968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 6025968caeeSMarri Devender Rao certFile->getCertFilePath()); 603828252d5SJiaqing Zhao } 6045968caeeSMarri Devender Rao 605cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 606828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher; 6075968caeeSMarri Devender Rao /** 608828252d5SJiaqing Zhao * @brief Read data from CSR D-bus object and set to response 609828252d5SJiaqing Zhao * 610828252d5SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 6118ece0e45SEd Tanous * @param[in] certURI Link to certificate collection URI 612828252d5SJiaqing Zhao * @param[in] service D-Bus service name 613828252d5SJiaqing Zhao * @param[in] certObjPath certificate D-Bus object path 614828252d5SJiaqing Zhao * @param[in] csrObjPath CSR D-Bus object path 615828252d5SJiaqing Zhao * @return None 6165968caeeSMarri Devender Rao */ 6174ff0f1f4SEd Tanous inline void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 618828252d5SJiaqing Zhao const std::string& certURI, const std::string& service, 619828252d5SJiaqing Zhao const std::string& certObjPath, 620828252d5SJiaqing Zhao const std::string& csrObjPath) 6215968caeeSMarri Devender Rao { 62262598e31SEd Tanous BMCWEB_LOG_DEBUG("getCSR CertObjectPath{} CSRObjectPath={} service={}", 62362598e31SEd Tanous certObjPath, csrObjPath, service); 624828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 625bd79bce8SPatrick Williams [asyncResp, 626bd79bce8SPatrick Williams certURI](const boost::system::error_code& ec, const std::string& csr) { 627828252d5SJiaqing Zhao if (ec) 628828252d5SJiaqing Zhao { 62962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 630828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 631828252d5SJiaqing Zhao return; 632828252d5SJiaqing Zhao } 633828252d5SJiaqing Zhao if (csr.empty()) 634828252d5SJiaqing Zhao { 63562598e31SEd Tanous BMCWEB_LOG_ERROR("CSR read is empty"); 636828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 637828252d5SJiaqing Zhao return; 638828252d5SJiaqing Zhao } 639828252d5SJiaqing Zhao asyncResp->res.jsonValue["CSRString"] = csr; 640828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = 641828252d5SJiaqing Zhao certURI; 642828252d5SJiaqing Zhao }, 643828252d5SJiaqing Zhao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 644828252d5SJiaqing Zhao } 645828252d5SJiaqing Zhao 646828252d5SJiaqing Zhao inline void 647828252d5SJiaqing Zhao handleGenerateCSRAction(App& app, const crow::Request& req, 648828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 649828252d5SJiaqing Zhao { 6503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 65145ca1b86SEd Tanous { 65245ca1b86SEd Tanous return; 65345ca1b86SEd Tanous } 654828252d5SJiaqing Zhao static const int rsaKeyBitLength = 2048; 6555968caeeSMarri Devender Rao 656828252d5SJiaqing Zhao // Required parameters 657828252d5SJiaqing Zhao std::string city; 658828252d5SJiaqing Zhao std::string commonName; 659828252d5SJiaqing Zhao std::string country; 660828252d5SJiaqing Zhao std::string organization; 661828252d5SJiaqing Zhao std::string organizationalUnit; 662828252d5SJiaqing Zhao std::string state; 6637a31e336SEd Tanous std::string certURI; 664828252d5SJiaqing Zhao 665828252d5SJiaqing Zhao // Optional parameters 666828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optAlternativeNames = 667828252d5SJiaqing Zhao std::vector<std::string>(); 668828252d5SJiaqing Zhao std::optional<std::string> optContactPerson = ""; 669828252d5SJiaqing Zhao std::optional<std::string> optChallengePassword = ""; 670828252d5SJiaqing Zhao std::optional<std::string> optEmail = ""; 671828252d5SJiaqing Zhao std::optional<std::string> optGivenName = ""; 672828252d5SJiaqing Zhao std::optional<std::string> optInitials = ""; 673828252d5SJiaqing Zhao std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 674828252d5SJiaqing Zhao std::optional<std::string> optKeyCurveId = "secp384r1"; 675828252d5SJiaqing Zhao std::optional<std::string> optKeyPairAlgorithm = "EC"; 676828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optKeyUsage = 677828252d5SJiaqing Zhao std::vector<std::string>(); 678828252d5SJiaqing Zhao std::optional<std::string> optSurname = ""; 679828252d5SJiaqing Zhao std::optional<std::string> optUnstructuredName = ""; 680afc474aeSMyung Bae if (!json_util::readJsonAction( // 681afc474aeSMyung Bae req, asyncResp->res, // 682afc474aeSMyung Bae "AlternativeNames", optAlternativeNames, // 683afc474aeSMyung Bae "CertificateCollection/@odata.id", certURI, // 684afc474aeSMyung Bae "ChallengePassword", optChallengePassword, // 685afc474aeSMyung Bae "City", city, // 686afc474aeSMyung Bae "CommonName", commonName, // 687afc474aeSMyung Bae "ContactPerson", optContactPerson, // 688afc474aeSMyung Bae "Country", country, // 689afc474aeSMyung Bae "Email", optEmail, // 690afc474aeSMyung Bae "GivenName", optGivenName, // 691afc474aeSMyung Bae "Initials", optInitials, // 692afc474aeSMyung Bae "KeyBitLength", optKeyBitLength, // 693afc474aeSMyung Bae "KeyCurveId", optKeyCurveId, // 694afc474aeSMyung Bae "KeyPairAlgorithm", optKeyPairAlgorithm, // 695afc474aeSMyung Bae "KeyUsage", optKeyUsage, // 696afc474aeSMyung Bae "Organization", organization, // 697afc474aeSMyung Bae "OrganizationalUnit", organizationalUnit, // 698afc474aeSMyung Bae "State", state, // 699afc474aeSMyung Bae "Surname", optSurname, // 700afc474aeSMyung Bae "UnstructuredName", optUnstructuredName // 701afc474aeSMyung Bae )) 702828252d5SJiaqing Zhao { 703828252d5SJiaqing Zhao return; 7045968caeeSMarri Devender Rao } 7055968caeeSMarri Devender Rao 706828252d5SJiaqing Zhao // bmcweb has no way to store or decode a private key challenge 707828252d5SJiaqing Zhao // password, which will likely cause bmcweb to crash on startup 708828252d5SJiaqing Zhao // if this is not set on a post so not allowing the user to set 709828252d5SJiaqing Zhao // value 710828252d5SJiaqing Zhao if (!optChallengePassword->empty()) 7115968caeeSMarri Devender Rao { 712828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 713828252d5SJiaqing Zhao "ChallengePassword"); 714828252d5SJiaqing Zhao return; 715828252d5SJiaqing Zhao } 716828252d5SJiaqing Zhao 717828252d5SJiaqing Zhao std::string objectPath; 718828252d5SJiaqing Zhao std::string service; 719253f11b8SEd Tanous if (certURI.starts_with(std::format( 720253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 721253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME))) 722828252d5SJiaqing Zhao { 723828252d5SJiaqing Zhao objectPath = certs::httpsObjectPath; 724828252d5SJiaqing Zhao service = certs::httpsServiceName; 725828252d5SJiaqing Zhao } 726828252d5SJiaqing Zhao else if (certURI.starts_with( 727828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 728828252d5SJiaqing Zhao { 729828252d5SJiaqing Zhao objectPath = certs::ldapObjectPath; 730828252d5SJiaqing Zhao service = certs::ldapServiceName; 731828252d5SJiaqing Zhao } 732828252d5SJiaqing Zhao else 733828252d5SJiaqing Zhao { 734828252d5SJiaqing Zhao messages::actionParameterNotSupported( 735828252d5SJiaqing Zhao asyncResp->res, "CertificateCollection", "GenerateCSR"); 736828252d5SJiaqing Zhao return; 737828252d5SJiaqing Zhao } 738828252d5SJiaqing Zhao 739828252d5SJiaqing Zhao // supporting only EC and RSA algorithm 740828252d5SJiaqing Zhao if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 741828252d5SJiaqing Zhao { 742828252d5SJiaqing Zhao messages::actionParameterNotSupported( 743828252d5SJiaqing Zhao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 744828252d5SJiaqing Zhao return; 745828252d5SJiaqing Zhao } 746828252d5SJiaqing Zhao 747828252d5SJiaqing Zhao // supporting only 2048 key bit length for RSA algorithm due to 748828252d5SJiaqing Zhao // time consumed in generating private key 749828252d5SJiaqing Zhao if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength) 750828252d5SJiaqing Zhao { 751e2616cc5SEd Tanous messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength, 752e2616cc5SEd Tanous "KeyBitLength"); 753828252d5SJiaqing Zhao return; 754828252d5SJiaqing Zhao } 755828252d5SJiaqing Zhao 756828252d5SJiaqing Zhao // validate KeyUsage supporting only 1 type based on URL 757253f11b8SEd Tanous if (certURI.starts_with(std::format( 758253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 759253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME))) 760828252d5SJiaqing Zhao { 761828252d5SJiaqing Zhao if (optKeyUsage->empty()) 762828252d5SJiaqing Zhao { 763b2ba3072SPatrick Williams optKeyUsage->emplace_back("ServerAuthentication"); 764828252d5SJiaqing Zhao } 765828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 766828252d5SJiaqing Zhao { 767828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ServerAuthentication") 768828252d5SJiaqing Zhao { 769828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 770828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 771828252d5SJiaqing Zhao return; 772828252d5SJiaqing Zhao } 773828252d5SJiaqing Zhao } 774828252d5SJiaqing Zhao else 775828252d5SJiaqing Zhao { 776828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 777828252d5SJiaqing Zhao "GenerateCSR"); 778828252d5SJiaqing Zhao return; 779828252d5SJiaqing Zhao } 780828252d5SJiaqing Zhao } 781828252d5SJiaqing Zhao else if (certURI.starts_with( 782828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 783828252d5SJiaqing Zhao { 784828252d5SJiaqing Zhao if (optKeyUsage->empty()) 785828252d5SJiaqing Zhao { 786b2ba3072SPatrick Williams optKeyUsage->emplace_back("ClientAuthentication"); 787828252d5SJiaqing Zhao } 788828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 789828252d5SJiaqing Zhao { 790828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ClientAuthentication") 791828252d5SJiaqing Zhao { 792828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 793828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 794828252d5SJiaqing Zhao return; 795828252d5SJiaqing Zhao } 796828252d5SJiaqing Zhao } 797828252d5SJiaqing Zhao else 798828252d5SJiaqing Zhao { 799828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 800828252d5SJiaqing Zhao "GenerateCSR"); 801828252d5SJiaqing Zhao return; 802828252d5SJiaqing Zhao } 803828252d5SJiaqing Zhao } 804828252d5SJiaqing Zhao 805828252d5SJiaqing Zhao // Only allow one CSR matcher at a time so setting retry 806828252d5SJiaqing Zhao // time-out and timer expiry to 10 seconds for now. 807828252d5SJiaqing Zhao static const int timeOut = 10; 808828252d5SJiaqing Zhao if (csrMatcher) 809828252d5SJiaqing Zhao { 810828252d5SJiaqing Zhao messages::serviceTemporarilyUnavailable(asyncResp->res, 811828252d5SJiaqing Zhao std::to_string(timeOut)); 812828252d5SJiaqing Zhao return; 813828252d5SJiaqing Zhao } 814828252d5SJiaqing Zhao 8158e8245dbSEd Tanous if (req.ioService == nullptr) 8168e8245dbSEd Tanous { 8178e8245dbSEd Tanous messages::internalError(asyncResp->res); 8188e8245dbSEd Tanous return; 8198e8245dbSEd Tanous } 8208e8245dbSEd Tanous 821828252d5SJiaqing Zhao // Make this static so it survives outside this method 822828252d5SJiaqing Zhao static boost::asio::steady_timer timeout(*req.ioService); 823828252d5SJiaqing Zhao timeout.expires_after(std::chrono::seconds(timeOut)); 824828252d5SJiaqing Zhao timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 825828252d5SJiaqing Zhao csrMatcher = nullptr; 826828252d5SJiaqing Zhao if (ec) 827828252d5SJiaqing Zhao { 828828252d5SJiaqing Zhao // operation_aborted is expected if timer is canceled 829828252d5SJiaqing Zhao // before completion. 830828252d5SJiaqing Zhao if (ec != boost::asio::error::operation_aborted) 831828252d5SJiaqing Zhao { 83262598e31SEd Tanous BMCWEB_LOG_ERROR("Async_wait failed {}", ec); 833828252d5SJiaqing Zhao } 834828252d5SJiaqing Zhao return; 835828252d5SJiaqing Zhao } 83662598e31SEd Tanous BMCWEB_LOG_ERROR("Timed out waiting for Generating CSR"); 837828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 838828252d5SJiaqing Zhao }); 839828252d5SJiaqing Zhao 840828252d5SJiaqing Zhao // create a matcher to wait on CSR object 84162598e31SEd Tanous BMCWEB_LOG_DEBUG("create matcher with path {}", objectPath); 842828252d5SJiaqing Zhao std::string match("type='signal'," 843828252d5SJiaqing Zhao "interface='org.freedesktop.DBus.ObjectManager'," 844828252d5SJiaqing Zhao "path='" + 845828252d5SJiaqing Zhao objectPath + 846828252d5SJiaqing Zhao "'," 847828252d5SJiaqing Zhao "member='InterfacesAdded'"); 848828252d5SJiaqing Zhao csrMatcher = std::make_unique<sdbusplus::bus::match_t>( 849828252d5SJiaqing Zhao *crow::connections::systemBus, match, 850828252d5SJiaqing Zhao [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { 851828252d5SJiaqing Zhao timeout.cancel(); 852828252d5SJiaqing Zhao if (m.is_method_error()) 853828252d5SJiaqing Zhao { 85462598e31SEd Tanous BMCWEB_LOG_ERROR("Dbus method error!!!"); 855828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 856828252d5SJiaqing Zhao return; 857828252d5SJiaqing Zhao } 858828252d5SJiaqing Zhao 85980f79a40SMichael Shen dbus::utility::DBusInterfacesMap interfacesProperties; 860828252d5SJiaqing Zhao 861828252d5SJiaqing Zhao sdbusplus::message::object_path csrObjectPath; 862828252d5SJiaqing Zhao m.read(csrObjectPath, interfacesProperties); 86362598e31SEd Tanous BMCWEB_LOG_DEBUG("CSR object added{}", csrObjectPath.str); 864828252d5SJiaqing Zhao for (const auto& interface : interfacesProperties) 865828252d5SJiaqing Zhao { 866828252d5SJiaqing Zhao if (interface.first == "xyz.openbmc_project.Certs.CSR") 867828252d5SJiaqing Zhao { 868828252d5SJiaqing Zhao getCSR(asyncResp, certURI, service, objectPath, 869828252d5SJiaqing Zhao csrObjectPath.str); 870828252d5SJiaqing Zhao break; 871828252d5SJiaqing Zhao } 872828252d5SJiaqing Zhao } 873828252d5SJiaqing Zhao }); 874828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 8755e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, const std::string&) { 876828252d5SJiaqing Zhao if (ec) 877828252d5SJiaqing Zhao { 87862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec.message()); 879828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 880828252d5SJiaqing Zhao return; 881828252d5SJiaqing Zhao } 882828252d5SJiaqing Zhao }, 883828252d5SJiaqing Zhao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 884828252d5SJiaqing Zhao "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 885828252d5SJiaqing Zhao commonName, *optContactPerson, country, *optEmail, *optGivenName, 886828252d5SJiaqing Zhao *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm, 887828252d5SJiaqing Zhao *optKeyUsage, organization, organizationalUnit, state, *optSurname, 888828252d5SJiaqing Zhao *optUnstructuredName); 889828252d5SJiaqing Zhao } 890828252d5SJiaqing Zhao 891828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app) 892828252d5SJiaqing Zhao { 893828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") 894828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateService) 895002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 896828252d5SJiaqing Zhao std::bind_front(handleCertificateServiceGet, std::ref(app))); 897828252d5SJiaqing Zhao 898828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 899828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateLocations) 900828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 901828252d5SJiaqing Zhao std::bind_front(handleCertificateLocationsGet, std::ref(app))); 902828252d5SJiaqing Zhao 903828252d5SJiaqing Zhao BMCWEB_ROUTE( 904828252d5SJiaqing Zhao app, 905828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 906828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 907828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 908828252d5SJiaqing Zhao std::bind_front(handleReplaceCertificateAction, std::ref(app))); 909828252d5SJiaqing Zhao 910828252d5SJiaqing Zhao BMCWEB_ROUTE( 911828252d5SJiaqing Zhao app, 912828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 913828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 914828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 915828252d5SJiaqing Zhao std::bind_front(handleGenerateCSRAction, std::ref(app))); 916828252d5SJiaqing Zhao } // requestRoutesCertificateService 917828252d5SJiaqing Zhao 918828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet( 919828252d5SJiaqing Zhao App& app, const crow::Request& req, 920253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 921253f11b8SEd Tanous const std::string& managerId) 922828252d5SJiaqing Zhao { 9233ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 92445ca1b86SEd Tanous { 92545ca1b86SEd Tanous return; 92645ca1b86SEd Tanous } 9271476687dSEd Tanous 928253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 929253f11b8SEd Tanous { 930253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 931253f11b8SEd Tanous return; 932253f11b8SEd Tanous } 933253f11b8SEd Tanous 934253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 935253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates", 936253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 9371476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 9381476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 9391476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; 9401476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 9411476687dSEd Tanous "A Collection of HTTPS certificate instances"; 9428d1b46d7Szhanghch05 943d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::httpsObjectPath, 944d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 945d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 946828252d5SJiaqing Zhao } 9475968caeeSMarri Devender Rao 948828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost( 949828252d5SJiaqing Zhao App& app, const crow::Request& req, 950253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 951253f11b8SEd Tanous const std::string& managerId) 952828252d5SJiaqing Zhao { 9533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 95445ca1b86SEd Tanous { 95545ca1b86SEd Tanous return; 95645ca1b86SEd Tanous } 957253f11b8SEd Tanous 958253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 959253f11b8SEd Tanous { 960253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 961253f11b8SEd Tanous return; 962253f11b8SEd Tanous } 963253f11b8SEd Tanous 96462598e31SEd Tanous BMCWEB_LOG_DEBUG("HTTPSCertificateCollection::doPost"); 9658d1b46d7Szhanghch05 9661476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; 9671476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; 9685968caeeSMarri Devender Rao 969b2896149SEd Tanous std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 97058eb238fSKowalski, Kamil 971b2896149SEd Tanous if (certHttpBody.empty()) 97258eb238fSKowalski, Kamil { 97362598e31SEd Tanous BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 974a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 97558eb238fSKowalski, Kamil return; 97658eb238fSKowalski, Kamil } 97758eb238fSKowalski, Kamil 9785968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 979b2896149SEd Tanous std::make_shared<CertificateFile>(certHttpBody); 9805968caeeSMarri Devender Rao 9815968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 9825e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 983656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 9845968caeeSMarri Devender Rao if (ec) 9855968caeeSMarri Devender Rao { 98662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 9875968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 9885968caeeSMarri Devender Rao return; 9895968caeeSMarri Devender Rao } 990717b9802SJiaqing Zhao 991717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 992717b9802SJiaqing Zhao std::string certId = path.filename(); 993ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 994253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 995253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 996bd79bce8SPatrick Williams getCertificateProperties(asyncResp, objectPath, 997bd79bce8SPatrick Williams certs::httpsServiceName, certId, certURL, 998bd79bce8SPatrick Williams "HTTPS Certificate"); 99962598e31SEd Tanous BMCWEB_LOG_DEBUG("HTTPS certificate install file={}", 100062598e31SEd Tanous certFile->getCertFilePath()); 10015968caeeSMarri Devender Rao }, 1002828252d5SJiaqing Zhao certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf, 1003828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 1004828252d5SJiaqing Zhao } 10055968caeeSMarri Devender Rao 1006828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet( 1007828252d5SJiaqing Zhao App& app, const crow::Request& req, 1008253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1009253f11b8SEd Tanous const std::string& managerId, const std::string& certId) 10107e860f15SJohn Edward Broadbent { 10113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 101245ca1b86SEd Tanous { 101345ca1b86SEd Tanous return; 101445ca1b86SEd Tanous } 10157e860f15SJohn Edward Broadbent 1016253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1017253f11b8SEd Tanous { 1018253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1019253f11b8SEd Tanous return; 1020253f11b8SEd Tanous } 1021253f11b8SEd Tanous 1022253f11b8SEd Tanous BMCWEB_LOG_DEBUG("HTTPS Certificate ID={}", certId); 1023ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1024253f11b8SEd Tanous "/redfish/v1/Managers/{}/NetworkProtocol/HTTPS/Certificates/{}", 1025253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1026828252d5SJiaqing Zhao std::string objPath = 1027253f11b8SEd Tanous sdbusplus::message::object_path(certs::httpsObjectPath) / certId; 1028253f11b8SEd Tanous getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, 1029253f11b8SEd Tanous certId, certURL, "HTTPS Certificate"); 10307e860f15SJohn Edward Broadbent } 103137cce918SMarri Devender Rao 1032828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app) 103337cce918SMarri Devender Rao { 1034253f11b8SEd Tanous BMCWEB_ROUTE( 1035253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/") 1036ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 1037828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 1038828252d5SJiaqing Zhao handleHTTPSCertificateCollectionGet, std::ref(app))); 1039828252d5SJiaqing Zhao 1040253f11b8SEd Tanous BMCWEB_ROUTE( 1041253f11b8SEd Tanous app, "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/") 1042828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1043828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1044828252d5SJiaqing Zhao handleHTTPSCertificateCollectionPost, std::ref(app))); 1045828252d5SJiaqing Zhao 1046828252d5SJiaqing Zhao BMCWEB_ROUTE( 1047828252d5SJiaqing Zhao app, 1048253f11b8SEd Tanous "/redfish/v1/Managers/<str>/NetworkProtocol/HTTPS/Certificates/<str>/") 1049828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1050002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1051828252d5SJiaqing Zhao std::bind_front(handleHTTPSCertificateGet, std::ref(app))); 1052828252d5SJiaqing Zhao } 1053828252d5SJiaqing Zhao 1054828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet( 1055828252d5SJiaqing Zhao App& app, const crow::Request& req, 1056828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1057828252d5SJiaqing Zhao { 10583ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 105945ca1b86SEd Tanous { 106045ca1b86SEd Tanous return; 106145ca1b86SEd Tanous } 10621476687dSEd Tanous 10631476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 10641476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 10651476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 10661476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 10671476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; 10681476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 10691476687dSEd Tanous "A Collection of LDAP certificate instances"; 10708d1b46d7Szhanghch05 1071d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::ldapObjectPath, 1072d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1073d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1074828252d5SJiaqing Zhao } 107537cce918SMarri Devender Rao 1076828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost( 1077828252d5SJiaqing Zhao App& app, const crow::Request& req, 1078828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1079828252d5SJiaqing Zhao { 10803ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 108145ca1b86SEd Tanous { 108245ca1b86SEd Tanous return; 108345ca1b86SEd Tanous } 1084b2896149SEd Tanous std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 108558eb238fSKowalski, Kamil 1086b2896149SEd Tanous if (certHttpBody.empty()) 108758eb238fSKowalski, Kamil { 108862598e31SEd Tanous BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 1089a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 109058eb238fSKowalski, Kamil return; 109158eb238fSKowalski, Kamil } 109258eb238fSKowalski, Kamil 109358eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 1094b2896149SEd Tanous std::make_shared<CertificateFile>(certHttpBody); 109558eb238fSKowalski, Kamil 109637cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 10975e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 1098656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 109937cce918SMarri Devender Rao if (ec) 110037cce918SMarri Devender Rao { 110162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 110237cce918SMarri Devender Rao messages::internalError(asyncResp->res); 110337cce918SMarri Devender Rao return; 110437cce918SMarri Devender Rao } 1105717b9802SJiaqing Zhao 1106717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1107717b9802SJiaqing Zhao std::string certId = path.filename(); 1108ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1109ef4c65b7SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/{}", certId); 1110bd79bce8SPatrick Williams getCertificateProperties(asyncResp, objectPath, 1111bd79bce8SPatrick Williams certs::ldapServiceName, certId, certURL, 1112bd79bce8SPatrick Williams "LDAP Certificate"); 111362598e31SEd Tanous BMCWEB_LOG_DEBUG("LDAP certificate install file={}", 111462598e31SEd Tanous certFile->getCertFilePath()); 111537cce918SMarri Devender Rao }, 1116828252d5SJiaqing Zhao certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf, 1117828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 1118828252d5SJiaqing Zhao } 111937cce918SMarri Devender Rao 1120828252d5SJiaqing Zhao inline void handleLDAPCertificateGet( 1121828252d5SJiaqing Zhao App& app, const crow::Request& req, 1122828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 112337cce918SMarri Devender Rao { 11243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 112545ca1b86SEd Tanous { 112645ca1b86SEd Tanous return; 112745ca1b86SEd Tanous } 1128717b9802SJiaqing Zhao 112962598e31SEd Tanous BMCWEB_LOG_DEBUG("LDAP Certificate ID={}", id); 1130ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1131ef4c65b7SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/{}", id); 1132717b9802SJiaqing Zhao std::string objPath = 1133717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 1134717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, 1135717b9802SJiaqing Zhao certURL, "LDAP Certificate"); 1136828252d5SJiaqing Zhao } 1137828252d5SJiaqing Zhao 113899612247SJiaqing Zhao inline void handleLDAPCertificateDelete( 113999612247SJiaqing Zhao App& app, const crow::Request& req, 114099612247SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 114199612247SJiaqing Zhao { 114299612247SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 114399612247SJiaqing Zhao { 114499612247SJiaqing Zhao return; 114599612247SJiaqing Zhao } 114699612247SJiaqing Zhao 114762598e31SEd Tanous BMCWEB_LOG_DEBUG("Delete LDAP Certificate ID={}", id); 114899612247SJiaqing Zhao std::string objPath = 114999612247SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 115099612247SJiaqing Zhao 115199612247SJiaqing Zhao deleteCertificate(asyncResp, certs::ldapServiceName, objPath); 115299612247SJiaqing Zhao } 115399612247SJiaqing Zhao 1154828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app) 1155cfcd5f6bSMarri Devender Rao { 1156828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1157828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateCollection) 1158828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1159828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app))); 1160828252d5SJiaqing Zhao 1161828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1162828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1163828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1164828252d5SJiaqing Zhao handleLDAPCertificateCollectionPost, std::ref(app))); 1165828252d5SJiaqing Zhao 1166828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1167ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 1168002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1169828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateGet, std::ref(app))); 117099612247SJiaqing Zhao 117199612247SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 117299612247SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 117399612247SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 117499612247SJiaqing Zhao std::bind_front(handleLDAPCertificateDelete, std::ref(app))); 1175828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate 1176828252d5SJiaqing Zhao 1177828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet( 1178828252d5SJiaqing Zhao App& app, const crow::Request& req, 1179253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1180253f11b8SEd Tanous const std::string& managerId) 1181828252d5SJiaqing Zhao { 11823ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 118345ca1b86SEd Tanous { 118445ca1b86SEd Tanous return; 118545ca1b86SEd Tanous } 11861476687dSEd Tanous 1187253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1188253f11b8SEd Tanous { 1189253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1190253f11b8SEd Tanous return; 1191253f11b8SEd Tanous } 1192253f11b8SEd Tanous 11931476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 1194253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/Truststore/Certificates/", 1195253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 11961476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 11971476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 1198002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; 11991476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 12001476687dSEd Tanous "A Collection of TrustStore certificate instances"; 12018d1b46d7Szhanghch05 1202d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::authorityObjectPath, 1203d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1204d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1205828252d5SJiaqing Zhao } 1206cfcd5f6bSMarri Devender Rao 1207828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost( 1208828252d5SJiaqing Zhao App& app, const crow::Request& req, 1209253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1210253f11b8SEd Tanous const std::string& managerId) 1211828252d5SJiaqing Zhao { 12123ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 121345ca1b86SEd Tanous { 121445ca1b86SEd Tanous return; 121545ca1b86SEd Tanous } 1216253f11b8SEd Tanous 1217253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1218253f11b8SEd Tanous { 1219253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1220253f11b8SEd Tanous return; 1221253f11b8SEd Tanous } 1222253f11b8SEd Tanous 1223b2896149SEd Tanous std::string certHttpBody = getCertificateFromReqBody(asyncResp, req); 1224a08752f5SZbigniew Kurzynski 1225b2896149SEd Tanous if (certHttpBody.empty()) 1226a08752f5SZbigniew Kurzynski { 122762598e31SEd Tanous BMCWEB_LOG_ERROR("Cannot get certificate from request body."); 1228a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1229a08752f5SZbigniew Kurzynski return; 1230a08752f5SZbigniew Kurzynski } 1231a08752f5SZbigniew Kurzynski 1232a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1233b2896149SEd Tanous std::make_shared<CertificateFile>(certHttpBody); 1234cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 12355e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 1236656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1237cfcd5f6bSMarri Devender Rao if (ec) 1238cfcd5f6bSMarri Devender Rao { 123962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 1240cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1241cfcd5f6bSMarri Devender Rao return; 1242cfcd5f6bSMarri Devender Rao } 1243656ec7e3SZbigniew Kurzynski 1244717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1245717b9802SJiaqing Zhao std::string certId = path.filename(); 1246ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1247253f11b8SEd Tanous "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 1248253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1249717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, 1250bd79bce8SPatrick Williams certs::authorityServiceName, certId, 1251bd79bce8SPatrick Williams certURL, "TrustStore Certificate"); 125262598e31SEd Tanous BMCWEB_LOG_DEBUG("TrustStore certificate install file={}", 125362598e31SEd Tanous certFile->getCertFilePath()); 1254cfcd5f6bSMarri Devender Rao }, 1255cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 12560fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 1257828252d5SJiaqing Zhao } 1258cfcd5f6bSMarri Devender Rao 1259828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet( 1260828252d5SJiaqing Zhao App& app, const crow::Request& req, 1261253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1262253f11b8SEd Tanous const std::string& managerId, const std::string& certId) 1263cfcd5f6bSMarri Devender Rao { 12643ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 126545ca1b86SEd Tanous { 126645ca1b86SEd Tanous return; 126745ca1b86SEd Tanous } 1268717b9802SJiaqing Zhao 1269253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1270253f11b8SEd Tanous { 1271253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1272253f11b8SEd Tanous return; 1273253f11b8SEd Tanous } 1274253f11b8SEd Tanous 1275253f11b8SEd Tanous BMCWEB_LOG_DEBUG("Truststore Certificate ID={}", certId); 1276ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1277253f11b8SEd Tanous "/redfish/v1/Managers/{}/Truststore/Certificates/{}", 1278253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, certId); 1279717b9802SJiaqing Zhao std::string objPath = 1280253f11b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / certId; 1281828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::authorityServiceName, 1282253f11b8SEd Tanous certId, certURL, "TrustStore Certificate"); 1283828252d5SJiaqing Zhao } 128407a60299SZbigniew Kurzynski 1285828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete( 1286828252d5SJiaqing Zhao App& app, const crow::Request& req, 1287253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1288253f11b8SEd Tanous const std::string& managerId, const std::string& certId) 1289828252d5SJiaqing Zhao { 12903ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 129145ca1b86SEd Tanous { 129245ca1b86SEd Tanous return; 129345ca1b86SEd Tanous } 129407a60299SZbigniew Kurzynski 1295253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1296253f11b8SEd Tanous { 1297253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1298253f11b8SEd Tanous return; 1299253f11b8SEd Tanous } 1300253f11b8SEd Tanous 1301253f11b8SEd Tanous BMCWEB_LOG_DEBUG("Delete TrustStore Certificate ID={}", certId); 1302717b9802SJiaqing Zhao std::string objPath = 1303253f11b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / certId; 130407a60299SZbigniew Kurzynski 13057a3a8f7aSJiaqing Zhao deleteCertificate(asyncResp, certs::authorityServiceName, objPath); 1306828252d5SJiaqing Zhao } 1307828252d5SJiaqing Zhao 1308828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app) 1309828252d5SJiaqing Zhao { 1310253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/") 1311828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1312828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 1313828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionGet, std::ref(app))); 1314828252d5SJiaqing Zhao 1315253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Truststore/Certificates/") 1316828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1317828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1318828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionPost, std::ref(app))); 1319828252d5SJiaqing Zhao 1320253f11b8SEd Tanous BMCWEB_ROUTE(app, 1321253f11b8SEd Tanous "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/") 1322828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1323828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1324828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateGet, std::ref(app))); 1325828252d5SJiaqing Zhao 1326253f11b8SEd Tanous BMCWEB_ROUTE(app, 1327253f11b8SEd Tanous "/redfish/v1/Managers/<str>/Truststore/Certificates/<str>/") 1328828252d5SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 1329828252d5SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 1330828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateDelete, std::ref(app))); 13317e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate 13325968caeeSMarri Devender Rao } // namespace redfish 1333