15968caeeSMarri Devender Rao #pragma once 25968caeeSMarri Devender Rao 37e860f15SJohn Edward Broadbent #include <app.hpp> 4e6604b11SIwona Klimaszewska #include <boost/convert.hpp> 5e6604b11SIwona Klimaszewska #include <boost/convert/strtol.hpp> 690d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp> 7168e20c1SEd Tanous #include <dbus_utility.hpp> 845ca1b86SEd Tanous #include <query.hpp> 9ed398213SEd Tanous #include <registries/privilege_registry.hpp> 101214b7e7SGunnar Mills 115968caeeSMarri Devender Rao namespace redfish 125968caeeSMarri Devender Rao { 135968caeeSMarri Devender Rao namespace certs 145968caeeSMarri Devender Rao { 155968caeeSMarri Devender Rao constexpr char const* httpsObjectPath = 165968caeeSMarri Devender Rao "/xyz/openbmc_project/certs/server/https"; 175968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 185968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 1907a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 205968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 215968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties"; 225968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 2337cce918SMarri Devender Rao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 2437cce918SMarri Devender Rao constexpr char const* httpsServiceName = 2537cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Server.Https"; 2637cce918SMarri Devender Rao constexpr char const* ldapServiceName = 2737cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 28cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName = 29cfcd5f6bSMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Authority.Ldap"; 30cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath = 31cfcd5f6bSMarri Devender Rao "/xyz/openbmc_project/certs/authority/ldap"; 325968caeeSMarri Devender Rao } // namespace certs 335968caeeSMarri Devender Rao 345968caeeSMarri Devender Rao /** 355968caeeSMarri Devender Rao * The Certificate schema defines a Certificate Service which represents the 365968caeeSMarri Devender Rao * actions available to manage certificates and links to where certificates 375968caeeSMarri Devender Rao * are installed. 385968caeeSMarri Devender Rao */ 397e860f15SJohn Edward Broadbent 405968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate 414e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish 425968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF 435968caeeSMarri Devender Rao // publish Privilege details for certificate service 445968caeeSMarri Devender Rao 457e860f15SJohn Edward Broadbent inline void requestRoutesCertificateService(App& app) 465968caeeSMarri Devender Rao { 477e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") 48ed398213SEd Tanous .privileges(redfish::privileges::getCertificateService) 49*002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 50*002d39b4SEd Tanous [&app](const crow::Request& req, 51*002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 5245ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 5345ca1b86SEd Tanous { 5445ca1b86SEd Tanous return; 5545ca1b86SEd Tanous } 561476687dSEd Tanous 571476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 581476687dSEd Tanous "#CertificateService.v1_0_0.CertificateService"; 591476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 601476687dSEd Tanous "/redfish/v1/CertificateService"; 611476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "CertificateService"; 621476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Certificate Service"; 631476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 641476687dSEd Tanous "Actions available to manage certificates"; 6572048780SAbhishek Patel // /redfish/v1/CertificateService/CertificateLocations is something 6672048780SAbhishek Patel // only ConfigureManager can access then only display when the user 6772048780SAbhishek Patel // has permissions ConfigureManager 6872048780SAbhishek Patel Privileges effectiveUserPrivileges = 6972048780SAbhishek Patel redfish::getUserPrivileges(req.userRole); 7072048780SAbhishek Patel if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 7172048780SAbhishek Patel effectiveUserPrivileges)) 7272048780SAbhishek Patel { 731476687dSEd Tanous asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = 741476687dSEd Tanous "/redfish/v1/CertificateService/CertificateLocations"; 7572048780SAbhishek Patel } 760fda0f12SGeorge Liu asyncResp->res 77*002d39b4SEd Tanous .jsonValue["Actions"]["#CertificateService.ReplaceCertificate"] = { 780fda0f12SGeorge Liu {"target", 790fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"}, 805968caeeSMarri Devender Rao {"CertificateType@Redfish.AllowableValues", {"PEM"}}}; 817e860f15SJohn Edward Broadbent asyncResp->res 827e860f15SJohn Edward Broadbent .jsonValue["Actions"]["#CertificateService.GenerateCSR"] = { 830fda0f12SGeorge Liu {"target", 840fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"}}; 857e860f15SJohn Edward Broadbent }); 867e860f15SJohn Edward Broadbent } // requestRoutesCertificateService 8737cce918SMarri Devender Rao 885968caeeSMarri Devender Rao /** 895968caeeSMarri Devender Rao * @brief Find the ID specified in the URL 905968caeeSMarri Devender Rao * Finds the numbers specified after the last "/" in the URL and returns. 915968caeeSMarri Devender Rao * @param[in] path URL 925968caeeSMarri Devender Rao * @return -1 on failure and number on success 935968caeeSMarri Devender Rao */ 9423a21a1cSEd Tanous inline long getIDFromURL(const std::string_view url) 955968caeeSMarri Devender Rao { 96f23b7296SEd Tanous std::size_t found = url.rfind('/'); 975968caeeSMarri Devender Rao if (found == std::string::npos) 985968caeeSMarri Devender Rao { 995968caeeSMarri Devender Rao return -1; 1005968caeeSMarri Devender Rao } 101e6604b11SIwona Klimaszewska 1025968caeeSMarri Devender Rao if ((found + 1) < url.length()) 1035968caeeSMarri Devender Rao { 1045968caeeSMarri Devender Rao std::string_view str = url.substr(found + 1); 105e6604b11SIwona Klimaszewska 106e6604b11SIwona Klimaszewska return boost::convert<long>(str, boost::cnv::strtol()).value_or(-1); 1075968caeeSMarri Devender Rao } 108e6604b11SIwona Klimaszewska 1095968caeeSMarri Devender Rao return -1; 1105968caeeSMarri Devender Rao } 1115968caeeSMarri Devender Rao 1128d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody( 1138d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 11458eb238fSKowalski, Kamil const crow::Request& req) 11558eb238fSKowalski, Kamil { 11658eb238fSKowalski, Kamil nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false); 11758eb238fSKowalski, Kamil 11858eb238fSKowalski, Kamil if (reqJson.is_discarded()) 11958eb238fSKowalski, Kamil { 12058eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 12158eb238fSKowalski, Kamil return req.body; 12258eb238fSKowalski, Kamil } 12358eb238fSKowalski, Kamil 12458eb238fSKowalski, Kamil std::string certificate; 12558eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 12658eb238fSKowalski, Kamil 12715ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString", 12815ed6780SWilly Tu certificate, "CertificateType", 12915ed6780SWilly Tu certificateType)) 13058eb238fSKowalski, Kamil { 13158eb238fSKowalski, Kamil BMCWEB_LOG_ERROR << "Required parameters are missing"; 13258eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 133abb93cddSEd Tanous return {}; 13458eb238fSKowalski, Kamil } 13558eb238fSKowalski, Kamil 13658eb238fSKowalski, Kamil if (*certificateType != "PEM") 13758eb238fSKowalski, Kamil { 13858eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 13958eb238fSKowalski, Kamil "CertificateType"); 140abb93cddSEd Tanous return {}; 14158eb238fSKowalski, Kamil } 14258eb238fSKowalski, Kamil 14358eb238fSKowalski, Kamil return certificate; 14458eb238fSKowalski, Kamil } 14558eb238fSKowalski, Kamil 1465968caeeSMarri Devender Rao /** 1475968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 1485968caeeSMarri Devender Rao */ 1495968caeeSMarri Devender Rao class CertificateFile 1505968caeeSMarri Devender Rao { 1515968caeeSMarri Devender Rao public: 1525968caeeSMarri Devender Rao CertificateFile() = delete; 1535968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 1545968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 1555968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 1565968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 1575968caeeSMarri Devender Rao CertificateFile(const std::string& certString) 1585968caeeSMarri Devender Rao { 15972d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 1605207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 1615207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 1625207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 163e662eae8SEd Tanous if (tempDirectory != nullptr) 1645968caeeSMarri Devender Rao { 1655968caeeSMarri Devender Rao certDirectory = tempDirectory; 1665968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 1675968caeeSMarri Devender Rao std::ofstream out(certificateFile, std::ofstream::out | 1685968caeeSMarri Devender Rao std::ofstream::binary | 1695968caeeSMarri Devender Rao std::ofstream::trunc); 1705968caeeSMarri Devender Rao out << certString; 1715968caeeSMarri Devender Rao out.close(); 1728cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Creating certificate file" 1738cc8edecSEd Tanous << certificateFile.string(); 1745968caeeSMarri Devender Rao } 1755968caeeSMarri Devender Rao } 1765968caeeSMarri Devender Rao ~CertificateFile() 1775968caeeSMarri Devender Rao { 1785968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1795968caeeSMarri Devender Rao { 1808cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Removing certificate file" 1818cc8edecSEd Tanous << certificateFile.string(); 18223a21a1cSEd Tanous std::error_code ec; 18323a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 18423a21a1cSEd Tanous if (ec) 1855968caeeSMarri Devender Rao { 1865968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Failed to remove temp directory" 1878cc8edecSEd Tanous << certDirectory.string(); 1885968caeeSMarri Devender Rao } 1895968caeeSMarri Devender Rao } 1905968caeeSMarri Devender Rao } 1915968caeeSMarri Devender Rao std::string getCertFilePath() 1925968caeeSMarri Devender Rao { 1935968caeeSMarri Devender Rao return certificateFile; 1945968caeeSMarri Devender Rao } 1955968caeeSMarri Devender Rao 1965968caeeSMarri Devender Rao private: 1975968caeeSMarri Devender Rao std::filesystem::path certificateFile; 1985968caeeSMarri Devender Rao std::filesystem::path certDirectory; 1995968caeeSMarri Devender Rao }; 2005968caeeSMarri Devender Rao 20130215816SMarri Devender Rao static std::unique_ptr<sdbusplus::bus::match::match> csrMatcher; 20230215816SMarri Devender Rao /** 20330215816SMarri Devender Rao * @brief Read data from CSR D-bus object and set to response 20430215816SMarri Devender Rao * 20530215816SMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 20630215816SMarri Devender Rao * @param[in] certURI Link to certifiate collection URI 20730215816SMarri Devender Rao * @param[in] service D-Bus service name 20830215816SMarri Devender Rao * @param[in] certObjPath certificate D-Bus object path 20930215816SMarri Devender Rao * @param[in] csrObjPath CSR D-Bus object path 21030215816SMarri Devender Rao * @return None 21130215816SMarri Devender Rao */ 2128d1b46d7Szhanghch05 static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21330215816SMarri Devender Rao const std::string& certURI, const std::string& service, 21430215816SMarri Devender Rao const std::string& certObjPath, 21530215816SMarri Devender Rao const std::string& csrObjPath) 21630215816SMarri Devender Rao { 21730215816SMarri Devender Rao BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath 21830215816SMarri Devender Rao << " CSRObjectPath=" << csrObjPath 21930215816SMarri Devender Rao << " service=" << service; 22030215816SMarri Devender Rao crow::connections::systemBus->async_method_call( 22130215816SMarri Devender Rao [asyncResp, certURI](const boost::system::error_code ec, 22230215816SMarri Devender Rao const std::string& csr) { 22330215816SMarri Devender Rao if (ec) 22430215816SMarri Devender Rao { 22530215816SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 22630215816SMarri Devender Rao messages::internalError(asyncResp->res); 22730215816SMarri Devender Rao return; 22830215816SMarri Devender Rao } 22930215816SMarri Devender Rao if (csr.empty()) 23030215816SMarri Devender Rao { 23130215816SMarri Devender Rao BMCWEB_LOG_ERROR << "CSR read is empty"; 23230215816SMarri Devender Rao messages::internalError(asyncResp->res); 23330215816SMarri Devender Rao return; 23430215816SMarri Devender Rao } 23530215816SMarri Devender Rao asyncResp->res.jsonValue["CSRString"] = csr; 2361476687dSEd Tanous asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = 2371476687dSEd Tanous certURI; 23830215816SMarri Devender Rao }, 23930215816SMarri Devender Rao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 24030215816SMarri Devender Rao } 24130215816SMarri Devender Rao 24230215816SMarri Devender Rao /** 24330215816SMarri Devender Rao * Action to Generate CSR 24430215816SMarri Devender Rao */ 2457e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionGenerateCSR(App& app) 24630215816SMarri Devender Rao { 2470fda0f12SGeorge Liu BMCWEB_ROUTE( 2480fda0f12SGeorge Liu app, 2490fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 2505344ab8eSAbhishek Patel .privileges(redfish::privileges::postCertificateService) 251*002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 252*002d39b4SEd Tanous [&app](const crow::Request& req, 2537e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 25445ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 25545ca1b86SEd Tanous { 25645ca1b86SEd Tanous return; 25745ca1b86SEd Tanous } 2582c70f800SEd Tanous static const int rsaKeyBitLength = 2048; 2598d1b46d7Szhanghch05 26030215816SMarri Devender Rao // Required parameters 26130215816SMarri Devender Rao std::string city; 26230215816SMarri Devender Rao std::string commonName; 26330215816SMarri Devender Rao std::string country; 26430215816SMarri Devender Rao std::string organization; 26530215816SMarri Devender Rao std::string organizationalUnit; 26630215816SMarri Devender Rao std::string state; 26730215816SMarri Devender Rao nlohmann::json certificateCollection; 26830215816SMarri Devender Rao 26930215816SMarri Devender Rao // Optional parameters 27030215816SMarri Devender Rao std::optional<std::vector<std::string>> optAlternativeNames = 27130215816SMarri Devender Rao std::vector<std::string>(); 27230215816SMarri Devender Rao std::optional<std::string> optContactPerson = ""; 27330215816SMarri Devender Rao std::optional<std::string> optChallengePassword = ""; 27430215816SMarri Devender Rao std::optional<std::string> optEmail = ""; 27530215816SMarri Devender Rao std::optional<std::string> optGivenName = ""; 27630215816SMarri Devender Rao std::optional<std::string> optInitials = ""; 2772c70f800SEd Tanous std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 278aaf3206fSVernon Mauery std::optional<std::string> optKeyCurveId = "secp384r1"; 27930215816SMarri Devender Rao std::optional<std::string> optKeyPairAlgorithm = "EC"; 28030215816SMarri Devender Rao std::optional<std::vector<std::string>> optKeyUsage = 28130215816SMarri Devender Rao std::vector<std::string>(); 28230215816SMarri Devender Rao std::optional<std::string> optSurname = ""; 28330215816SMarri Devender Rao std::optional<std::string> optUnstructuredName = ""; 28415ed6780SWilly Tu if (!json_util::readJsonAction( 2850fda0f12SGeorge Liu req, asyncResp->res, "City", city, "CommonName", commonName, 2860fda0f12SGeorge Liu "ContactPerson", optContactPerson, "Country", country, 2870fda0f12SGeorge Liu "Organization", organization, "OrganizationalUnit", 2880fda0f12SGeorge Liu organizationalUnit, "State", state, "CertificateCollection", 289*002d39b4SEd Tanous certificateCollection, "AlternativeNames", optAlternativeNames, 290*002d39b4SEd Tanous "ChallengePassword", optChallengePassword, "Email", optEmail, 291*002d39b4SEd Tanous "GivenName", optGivenName, "Initials", optInitials, 292*002d39b4SEd Tanous "KeyBitLength", optKeyBitLength, "KeyCurveId", optKeyCurveId, 2930fda0f12SGeorge Liu "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage", 2940fda0f12SGeorge Liu optKeyUsage, "Surname", optSurname, "UnstructuredName", 2950fda0f12SGeorge Liu optUnstructuredName)) 29630215816SMarri Devender Rao { 29730215816SMarri Devender Rao return; 29830215816SMarri Devender Rao } 29930215816SMarri Devender Rao 30030215816SMarri Devender Rao // bmcweb has no way to store or decode a private key challenge 3017e860f15SJohn Edward Broadbent // password, which will likely cause bmcweb to crash on startup 3027e860f15SJohn Edward Broadbent // if this is not set on a post so not allowing the user to set 3037e860f15SJohn Edward Broadbent // value 30426f6976fSEd Tanous if (!optChallengePassword->empty()) 30530215816SMarri Devender Rao { 306*002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 307*002d39b4SEd Tanous "ChallengePassword"); 30830215816SMarri Devender Rao return; 30930215816SMarri Devender Rao } 31030215816SMarri Devender Rao 31130215816SMarri Devender Rao std::string certURI; 312*002d39b4SEd Tanous if (!redfish::json_util::readJson(certificateCollection, asyncResp->res, 313*002d39b4SEd Tanous "@odata.id", certURI)) 31430215816SMarri Devender Rao { 31530215816SMarri Devender Rao return; 31630215816SMarri Devender Rao } 31730215816SMarri Devender Rao 31830215816SMarri Devender Rao std::string objectPath; 31930215816SMarri Devender Rao std::string service; 3200fda0f12SGeorge Liu if (boost::starts_with( 3210fda0f12SGeorge Liu certURI, 3220fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 32330215816SMarri Devender Rao { 32430215816SMarri Devender Rao objectPath = certs::httpsObjectPath; 32530215816SMarri Devender Rao service = certs::httpsServiceName; 32630215816SMarri Devender Rao } 3273b7f0149SMarri Devender Rao else if (boost::starts_with( 328*002d39b4SEd Tanous certURI, "/redfish/v1/AccountService/LDAP/Certificates")) 3293b7f0149SMarri Devender Rao { 3303b7f0149SMarri Devender Rao objectPath = certs::ldapObjectPath; 3313b7f0149SMarri Devender Rao service = certs::ldapServiceName; 3323b7f0149SMarri Devender Rao } 33330215816SMarri Devender Rao else 33430215816SMarri Devender Rao { 33530215816SMarri Devender Rao messages::actionParameterNotSupported( 33630215816SMarri Devender Rao asyncResp->res, "CertificateCollection", "GenerateCSR"); 33730215816SMarri Devender Rao return; 33830215816SMarri Devender Rao } 33930215816SMarri Devender Rao 34030215816SMarri Devender Rao // supporting only EC and RSA algorithm 3410fda0f12SGeorge Liu if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 34230215816SMarri Devender Rao { 34330215816SMarri Devender Rao messages::actionParameterNotSupported( 34430215816SMarri Devender Rao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 34530215816SMarri Devender Rao return; 34630215816SMarri Devender Rao } 34730215816SMarri Devender Rao 3487e860f15SJohn Edward Broadbent // supporting only 2048 key bit length for RSA algorithm due to 3497e860f15SJohn Edward Broadbent // time consumed in generating private key 35030215816SMarri Devender Rao if (*optKeyPairAlgorithm == "RSA" && 3512c70f800SEd Tanous *optKeyBitLength != rsaKeyBitLength) 35230215816SMarri Devender Rao { 353*002d39b4SEd Tanous messages::propertyValueNotInList(asyncResp->res, 354*002d39b4SEd Tanous std::to_string(*optKeyBitLength), 35530215816SMarri Devender Rao "KeyBitLength"); 35630215816SMarri Devender Rao return; 35730215816SMarri Devender Rao } 35830215816SMarri Devender Rao 35930215816SMarri Devender Rao // validate KeyUsage supporting only 1 type based on URL 3600fda0f12SGeorge Liu if (boost::starts_with( 3610fda0f12SGeorge Liu certURI, 3620fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 36330215816SMarri Devender Rao { 36426f6976fSEd Tanous if (optKeyUsage->empty()) 36530215816SMarri Devender Rao { 36630215816SMarri Devender Rao optKeyUsage->push_back("ServerAuthentication"); 36730215816SMarri Devender Rao } 36830215816SMarri Devender Rao else if (optKeyUsage->size() == 1) 36930215816SMarri Devender Rao { 37030215816SMarri Devender Rao if ((*optKeyUsage)[0] != "ServerAuthentication") 37130215816SMarri Devender Rao { 37230215816SMarri Devender Rao messages::propertyValueNotInList( 37330215816SMarri Devender Rao asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); 37430215816SMarri Devender Rao return; 37530215816SMarri Devender Rao } 37630215816SMarri Devender Rao } 37730215816SMarri Devender Rao else 37830215816SMarri Devender Rao { 37930215816SMarri Devender Rao messages::actionParameterNotSupported( 38030215816SMarri Devender Rao asyncResp->res, "KeyUsage", "GenerateCSR"); 38130215816SMarri Devender Rao return; 38230215816SMarri Devender Rao } 38330215816SMarri Devender Rao } 3843b7f0149SMarri Devender Rao else if (boost::starts_with( 385*002d39b4SEd Tanous certURI, "/redfish/v1/AccountService/LDAP/Certificates")) 3863b7f0149SMarri Devender Rao { 38726f6976fSEd Tanous if (optKeyUsage->empty()) 3883b7f0149SMarri Devender Rao { 3893b7f0149SMarri Devender Rao optKeyUsage->push_back("ClientAuthentication"); 3903b7f0149SMarri Devender Rao } 3913b7f0149SMarri Devender Rao else if (optKeyUsage->size() == 1) 3923b7f0149SMarri Devender Rao { 3933b7f0149SMarri Devender Rao if ((*optKeyUsage)[0] != "ClientAuthentication") 3943b7f0149SMarri Devender Rao { 3953b7f0149SMarri Devender Rao messages::propertyValueNotInList( 3963b7f0149SMarri Devender Rao asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); 3973b7f0149SMarri Devender Rao return; 3983b7f0149SMarri Devender Rao } 3993b7f0149SMarri Devender Rao } 4003b7f0149SMarri Devender Rao else 4013b7f0149SMarri Devender Rao { 4023b7f0149SMarri Devender Rao messages::actionParameterNotSupported( 4033b7f0149SMarri Devender Rao asyncResp->res, "KeyUsage", "GenerateCSR"); 4043b7f0149SMarri Devender Rao return; 4053b7f0149SMarri Devender Rao } 4063b7f0149SMarri Devender Rao } 40730215816SMarri Devender Rao 4087e860f15SJohn Edward Broadbent // Only allow one CSR matcher at a time so setting retry 4097e860f15SJohn Edward Broadbent // time-out and timer expiry to 10 seconds for now. 4102c70f800SEd Tanous static const int timeOut = 10; 41130215816SMarri Devender Rao if (csrMatcher) 41230215816SMarri Devender Rao { 413*002d39b4SEd Tanous messages::serviceTemporarilyUnavailable(asyncResp->res, 414*002d39b4SEd Tanous std::to_string(timeOut)); 41530215816SMarri Devender Rao return; 41630215816SMarri Devender Rao } 41730215816SMarri Devender Rao 41830215816SMarri Devender Rao // Make this static so it survives outside this method 41930215816SMarri Devender Rao static boost::asio::steady_timer timeout(*req.ioService); 4202c70f800SEd Tanous timeout.expires_after(std::chrono::seconds(timeOut)); 421*002d39b4SEd Tanous timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 42230215816SMarri Devender Rao csrMatcher = nullptr; 42330215816SMarri Devender Rao if (ec) 42430215816SMarri Devender Rao { 4257e860f15SJohn Edward Broadbent // operation_aborted is expected if timer is canceled 4267e860f15SJohn Edward Broadbent // before completion. 42730215816SMarri Devender Rao if (ec != boost::asio::error::operation_aborted) 42830215816SMarri Devender Rao { 42930215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Async_wait failed " << ec; 43030215816SMarri Devender Rao } 43130215816SMarri Devender Rao return; 43230215816SMarri Devender Rao } 43330215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; 43430215816SMarri Devender Rao messages::internalError(asyncResp->res); 43530215816SMarri Devender Rao }); 43630215816SMarri Devender Rao 43730215816SMarri Devender Rao // create a matcher to wait on CSR object 43830215816SMarri Devender Rao BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; 4390fda0f12SGeorge Liu std::string match("type='signal'," 44030215816SMarri Devender Rao "interface='org.freedesktop.DBus.ObjectManager'," 44130215816SMarri Devender Rao "path='" + 44230215816SMarri Devender Rao objectPath + 44330215816SMarri Devender Rao "'," 44430215816SMarri Devender Rao "member='InterfacesAdded'"); 44530215816SMarri Devender Rao csrMatcher = std::make_unique<sdbusplus::bus::match::match>( 44630215816SMarri Devender Rao *crow::connections::systemBus, match, 44730215816SMarri Devender Rao [asyncResp, service, objectPath, 44830215816SMarri Devender Rao certURI](sdbusplus::message::message& m) { 449271584abSEd Tanous timeout.cancel(); 45030215816SMarri Devender Rao if (m.is_method_error()) 45130215816SMarri Devender Rao { 45230215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Dbus method error!!!"; 45330215816SMarri Devender Rao messages::internalError(asyncResp->res); 45430215816SMarri Devender Rao return; 45530215816SMarri Devender Rao } 456b9d36b47SEd Tanous 457b9d36b47SEd Tanous dbus::utility::DBusInteracesMap interfacesProperties; 458b9d36b47SEd Tanous 45930215816SMarri Devender Rao sdbusplus::message::object_path csrObjectPath; 46030215816SMarri Devender Rao m.read(csrObjectPath, interfacesProperties); 4610fda0f12SGeorge Liu BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; 46230215816SMarri Devender Rao for (auto& interface : interfacesProperties) 46330215816SMarri Devender Rao { 4640fda0f12SGeorge Liu if (interface.first == "xyz.openbmc_project.Certs.CSR") 46530215816SMarri Devender Rao { 46630215816SMarri Devender Rao getCSR(asyncResp, certURI, service, objectPath, 46730215816SMarri Devender Rao csrObjectPath.str); 46830215816SMarri Devender Rao break; 46930215816SMarri Devender Rao } 47030215816SMarri Devender Rao } 47130215816SMarri Devender Rao }); 47230215816SMarri Devender Rao crow::connections::systemBus->async_method_call( 473914e2d5dSEd Tanous [asyncResp](const boost::system::error_code ec, 474cb13a392SEd Tanous const std::string&) { 47530215816SMarri Devender Rao if (ec) 47630215816SMarri Devender Rao { 477*002d39b4SEd Tanous BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message(); 47830215816SMarri Devender Rao messages::internalError(asyncResp->res); 47930215816SMarri Devender Rao return; 48030215816SMarri Devender Rao } 48130215816SMarri Devender Rao }, 48230215816SMarri Devender Rao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 483*002d39b4SEd Tanous "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 484*002d39b4SEd Tanous commonName, *optContactPerson, country, *optEmail, *optGivenName, 485*002d39b4SEd Tanous *optInitials, *optKeyBitLength, *optKeyCurveId, 4860fda0f12SGeorge Liu *optKeyPairAlgorithm, *optKeyUsage, organization, 4870fda0f12SGeorge Liu organizationalUnit, state, *optSurname, *optUnstructuredName); 4887e860f15SJohn Edward Broadbent }); 4897e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionGenerateCSR 49030215816SMarri Devender Rao 4915968caeeSMarri Devender Rao /** 4924e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 4935968caeeSMarri Devender Rao * 4945968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 4955968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 4965968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 4975968caeeSMarri Devender Rao * @return None 4985968caeeSMarri Devender Rao */ 4995968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out, 5005968caeeSMarri Devender Rao const std::string_view value) 5015968caeeSMarri Devender Rao { 5025968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 5035968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 5045968caeeSMarri Devender Rao while (i != value.end()) 5055968caeeSMarri Devender Rao { 5065968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 5075968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 5085968caeeSMarri Devender Rao { 50917a897dfSManojkiran Eda ++i; 5105968caeeSMarri Devender Rao } 5115968caeeSMarri Devender Rao if (i == value.end()) 5125968caeeSMarri Devender Rao { 5135968caeeSMarri Devender Rao break; 5145968caeeSMarri Devender Rao } 515271584abSEd Tanous const std::string_view key(tokenBegin, 516271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 51717a897dfSManojkiran Eda ++i; 5185968caeeSMarri Devender Rao tokenBegin = i; 5195968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 5205968caeeSMarri Devender Rao { 52117a897dfSManojkiran Eda ++i; 5225968caeeSMarri Devender Rao } 523271584abSEd Tanous const std::string_view val(tokenBegin, 524271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 5255968caeeSMarri Devender Rao if (key == "L") 5265968caeeSMarri Devender Rao { 5275968caeeSMarri Devender Rao out["City"] = val; 5285968caeeSMarri Devender Rao } 5295968caeeSMarri Devender Rao else if (key == "CN") 5305968caeeSMarri Devender Rao { 5315968caeeSMarri Devender Rao out["CommonName"] = val; 5325968caeeSMarri Devender Rao } 5335968caeeSMarri Devender Rao else if (key == "C") 5345968caeeSMarri Devender Rao { 5355968caeeSMarri Devender Rao out["Country"] = val; 5365968caeeSMarri Devender Rao } 5375968caeeSMarri Devender Rao else if (key == "O") 5385968caeeSMarri Devender Rao { 5395968caeeSMarri Devender Rao out["Organization"] = val; 5405968caeeSMarri Devender Rao } 5415968caeeSMarri Devender Rao else if (key == "OU") 5425968caeeSMarri Devender Rao { 5435968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 5445968caeeSMarri Devender Rao } 5455968caeeSMarri Devender Rao else if (key == "ST") 5465968caeeSMarri Devender Rao { 5475968caeeSMarri Devender Rao out["State"] = val; 5485968caeeSMarri Devender Rao } 5495968caeeSMarri Devender Rao // skip comma character 5505968caeeSMarri Devender Rao if (i != value.end()) 5515968caeeSMarri Devender Rao { 55217a897dfSManojkiran Eda ++i; 5535968caeeSMarri Devender Rao } 5545968caeeSMarri Devender Rao } 5555968caeeSMarri Devender Rao } 5565968caeeSMarri Devender Rao 5575968caeeSMarri Devender Rao /** 5585968caeeSMarri Devender Rao * @brief Retrieve the certificates properties and append to the response 5595968caeeSMarri Devender Rao * message 5605968caeeSMarri Devender Rao * 5615968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 5625968caeeSMarri Devender Rao * @param[in] objectPath Path of the D-Bus service object 5635968caeeSMarri Devender Rao * @param[in] certId Id of the certificate 5645968caeeSMarri Devender Rao * @param[in] certURL URL of the certificate object 5655968caeeSMarri Devender Rao * @param[in] name name of the certificate 5665968caeeSMarri Devender Rao * @return None 5675968caeeSMarri Devender Rao */ 5685968caeeSMarri Devender Rao static void getCertificateProperties( 5698d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5708d1b46d7Szhanghch05 const std::string& objectPath, const std::string& service, long certId, 5718d1b46d7Szhanghch05 const std::string& certURL, const std::string& name) 5725968caeeSMarri Devender Rao { 5735968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath 5745968caeeSMarri Devender Rao << " certId=" << certId << " certURl=" << certURL; 5755968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 576b9d36b47SEd Tanous [asyncResp, certURL, certId, 577b9d36b47SEd Tanous name](const boost::system::error_code ec, 578b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& properties) { 5795968caeeSMarri Devender Rao if (ec) 5805968caeeSMarri Devender Rao { 5815968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 5828aae75adSMarri Devender Rao messages::resourceNotFound(asyncResp->res, name, 5838aae75adSMarri Devender Rao std::to_string(certId)); 5845968caeeSMarri Devender Rao return; 5855968caeeSMarri Devender Rao } 5861476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = certURL; 5871476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 5881476687dSEd Tanous "#Certificate.v1_0_0.Certificate"; 5891476687dSEd Tanous asyncResp->res.jsonValue["Id"] = std::to_string(certId); 5901476687dSEd Tanous asyncResp->res.jsonValue["Name"] = name; 5911476687dSEd Tanous asyncResp->res.jsonValue["Description"] = name; 5925968caeeSMarri Devender Rao for (const auto& property : properties) 5935968caeeSMarri Devender Rao { 5945968caeeSMarri Devender Rao if (property.first == "CertificateString") 5955968caeeSMarri Devender Rao { 5965968caeeSMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = ""; 5975968caeeSMarri Devender Rao const std::string* value = 5985968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 599e662eae8SEd Tanous if (value != nullptr) 6005968caeeSMarri Devender Rao { 60137cce918SMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = *value; 6025968caeeSMarri Devender Rao } 6035968caeeSMarri Devender Rao } 6045968caeeSMarri Devender Rao else if (property.first == "KeyUsage") 6055968caeeSMarri Devender Rao { 606*002d39b4SEd Tanous nlohmann::json& keyUsage = asyncResp->res.jsonValue["KeyUsage"]; 6075968caeeSMarri Devender Rao keyUsage = nlohmann::json::array(); 6085968caeeSMarri Devender Rao const std::vector<std::string>* value = 60937cce918SMarri Devender Rao std::get_if<std::vector<std::string>>(&property.second); 610e662eae8SEd Tanous if (value != nullptr) 6115968caeeSMarri Devender Rao { 6125968caeeSMarri Devender Rao for (const std::string& usage : *value) 6135968caeeSMarri Devender Rao { 6145968caeeSMarri Devender Rao keyUsage.push_back(usage); 6155968caeeSMarri Devender Rao } 6165968caeeSMarri Devender Rao } 6175968caeeSMarri Devender Rao } 6185968caeeSMarri Devender Rao else if (property.first == "Issuer") 6195968caeeSMarri Devender Rao { 6205968caeeSMarri Devender Rao const std::string* value = 6215968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 622e662eae8SEd Tanous if (value != nullptr) 6235968caeeSMarri Devender Rao { 6245968caeeSMarri Devender Rao updateCertIssuerOrSubject( 6255968caeeSMarri Devender Rao asyncResp->res.jsonValue["Issuer"], *value); 6265968caeeSMarri Devender Rao } 6275968caeeSMarri Devender Rao } 6285968caeeSMarri Devender Rao else if (property.first == "Subject") 6295968caeeSMarri Devender Rao { 6305968caeeSMarri Devender Rao const std::string* value = 6315968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 632e662eae8SEd Tanous if (value != nullptr) 6335968caeeSMarri Devender Rao { 6345968caeeSMarri Devender Rao updateCertIssuerOrSubject( 63537cce918SMarri Devender Rao asyncResp->res.jsonValue["Subject"], *value); 6365968caeeSMarri Devender Rao } 6375968caeeSMarri Devender Rao } 6385968caeeSMarri Devender Rao else if (property.first == "ValidNotAfter") 6395968caeeSMarri Devender Rao { 640*002d39b4SEd Tanous const uint64_t* value = std::get_if<uint64_t>(&property.second); 641e662eae8SEd Tanous if (value != nullptr) 6425968caeeSMarri Devender Rao { 6435968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotAfter"] = 6441d8782e7SNan Zhou crow::utility::getDateTimeUint(*value); 6455968caeeSMarri Devender Rao } 6465968caeeSMarri Devender Rao } 6475968caeeSMarri Devender Rao else if (property.first == "ValidNotBefore") 6485968caeeSMarri Devender Rao { 649*002d39b4SEd Tanous const uint64_t* value = std::get_if<uint64_t>(&property.second); 650e662eae8SEd Tanous if (value != nullptr) 6515968caeeSMarri Devender Rao { 6525968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotBefore"] = 6531d8782e7SNan Zhou crow::utility::getDateTimeUint(*value); 6545968caeeSMarri Devender Rao } 6555968caeeSMarri Devender Rao } 6565968caeeSMarri Devender Rao } 6575968caeeSMarri Devender Rao asyncResp->res.addHeader("Location", certURL); 6585968caeeSMarri Devender Rao }, 6595968caeeSMarri Devender Rao service, objectPath, certs::dbusPropIntf, "GetAll", 6605968caeeSMarri Devender Rao certs::certPropIntf); 6615968caeeSMarri Devender Rao } 6625968caeeSMarri Devender Rao 6635968caeeSMarri Devender Rao /** 6645968caeeSMarri Devender Rao * Action to replace an existing certificate 6655968caeeSMarri Devender Rao */ 6667e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionsReplaceCertificate(App& app) 6675968caeeSMarri Devender Rao { 6680fda0f12SGeorge Liu BMCWEB_ROUTE( 6690fda0f12SGeorge Liu app, 6700fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 671ed398213SEd Tanous .privileges(redfish::privileges::postCertificateService) 672*002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 673*002d39b4SEd Tanous [&app](const crow::Request& req, 6747e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 67545ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 67645ca1b86SEd Tanous { 67745ca1b86SEd Tanous return; 67845ca1b86SEd Tanous } 6795968caeeSMarri Devender Rao std::string certificate; 6805968caeeSMarri Devender Rao nlohmann::json certificateUri; 6815968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 6828d1b46d7Szhanghch05 683*002d39b4SEd Tanous if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString", 684*002d39b4SEd Tanous certificate, "CertificateUri", 685*002d39b4SEd Tanous certificateUri, "CertificateType", 686*002d39b4SEd Tanous certificateType)) 6875968caeeSMarri Devender Rao { 6885968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Required parameters are missing"; 6895968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 6905968caeeSMarri Devender Rao return; 6915968caeeSMarri Devender Rao } 6925968caeeSMarri Devender Rao 6935968caeeSMarri Devender Rao if (!certificateType) 6945968caeeSMarri Devender Rao { 6955968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 6965968caeeSMarri Devender Rao return; 6975968caeeSMarri Devender Rao } 6985968caeeSMarri Devender Rao if (certificateType != "PEM") 6995968caeeSMarri Devender Rao { 7005968caeeSMarri Devender Rao messages::actionParameterNotSupported( 7015968caeeSMarri Devender Rao asyncResp->res, "CertificateType", "ReplaceCertificate"); 7025968caeeSMarri Devender Rao return; 7035968caeeSMarri Devender Rao } 7045968caeeSMarri Devender Rao 7055968caeeSMarri Devender Rao std::string certURI; 7065968caeeSMarri Devender Rao if (!redfish::json_util::readJson(certificateUri, asyncResp->res, 7075968caeeSMarri Devender Rao "@odata.id", certURI)) 7085968caeeSMarri Devender Rao { 7095968caeeSMarri Devender Rao messages::actionParameterMissing( 7105968caeeSMarri Devender Rao asyncResp->res, "ReplaceCertificate", "CertificateUri"); 7115968caeeSMarri Devender Rao return; 7125968caeeSMarri Devender Rao } 7135968caeeSMarri Devender Rao 7145968caeeSMarri Devender Rao BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI; 7155968caeeSMarri Devender Rao long id = getIDFromURL(certURI); 7165968caeeSMarri Devender Rao if (id < 0) 7175968caeeSMarri Devender Rao { 718*002d39b4SEd Tanous messages::actionParameterValueFormatError(asyncResp->res, certURI, 719*002d39b4SEd Tanous "CertificateUri", 7205968caeeSMarri Devender Rao "ReplaceCertificate"); 7215968caeeSMarri Devender Rao return; 7225968caeeSMarri Devender Rao } 7235968caeeSMarri Devender Rao std::string objectPath; 7245968caeeSMarri Devender Rao std::string name; 72537cce918SMarri Devender Rao std::string service; 7260fda0f12SGeorge Liu if (boost::starts_with( 7270fda0f12SGeorge Liu certURI, 7280fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")) 7295968caeeSMarri Devender Rao { 730*002d39b4SEd Tanous objectPath = 731*002d39b4SEd Tanous std::string(certs::httpsObjectPath) + "/" + std::to_string(id); 7325968caeeSMarri Devender Rao name = "HTTPS certificate"; 73337cce918SMarri Devender Rao service = certs::httpsServiceName; 73437cce918SMarri Devender Rao } 73537cce918SMarri Devender Rao else if (boost::starts_with( 736*002d39b4SEd Tanous certURI, "/redfish/v1/AccountService/LDAP/Certificates/")) 73737cce918SMarri Devender Rao { 738*002d39b4SEd Tanous objectPath = 739*002d39b4SEd Tanous std::string(certs::ldapObjectPath) + "/" + std::to_string(id); 74037cce918SMarri Devender Rao name = "LDAP certificate"; 74137cce918SMarri Devender Rao service = certs::ldapServiceName; 7425968caeeSMarri Devender Rao } 743cfcd5f6bSMarri Devender Rao else if (boost::starts_with( 744cfcd5f6bSMarri Devender Rao certURI, 745cfcd5f6bSMarri Devender Rao "/redfish/v1/Managers/bmc/Truststore/Certificates/")) 746cfcd5f6bSMarri Devender Rao { 747cfcd5f6bSMarri Devender Rao objectPath = std::string(certs::authorityObjectPath) + "/" + 748cfcd5f6bSMarri Devender Rao std::to_string(id); 749cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 750cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 751cfcd5f6bSMarri Devender Rao } 7525968caeeSMarri Devender Rao else 7535968caeeSMarri Devender Rao { 7545968caeeSMarri Devender Rao messages::actionParameterNotSupported( 7555968caeeSMarri Devender Rao asyncResp->res, "CertificateUri", "ReplaceCertificate"); 7565968caeeSMarri Devender Rao return; 7575968caeeSMarri Devender Rao } 7585968caeeSMarri Devender Rao 7595968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 7605968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 7615968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 76237cce918SMarri Devender Rao [asyncResp, certFile, objectPath, service, certURI, id, 7635968caeeSMarri Devender Rao name](const boost::system::error_code ec) { 7645968caeeSMarri Devender Rao if (ec) 7655968caeeSMarri Devender Rao { 7665968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 76790d2d1e8SJiaqing Zhao if (ec.value() == 76890d2d1e8SJiaqing Zhao boost::system::linux_error::bad_request_descriptor) 76990d2d1e8SJiaqing Zhao { 7708aae75adSMarri Devender Rao messages::resourceNotFound(asyncResp->res, name, 7718aae75adSMarri Devender Rao std::to_string(id)); 7725968caeeSMarri Devender Rao return; 7735968caeeSMarri Devender Rao } 77490d2d1e8SJiaqing Zhao messages::internalError(asyncResp->res); 77590d2d1e8SJiaqing Zhao return; 77690d2d1e8SJiaqing Zhao } 77737cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, service, id, 7785968caeeSMarri Devender Rao certURI, name); 7795968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 7805968caeeSMarri Devender Rao << certFile->getCertFilePath(); 7815968caeeSMarri Devender Rao }, 7825968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 7835968caeeSMarri Devender Rao certFile->getCertFilePath()); 7847e860f15SJohn Edward Broadbent }); 7857e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionsReplaceCertificate 7865968caeeSMarri Devender Rao 7875968caeeSMarri Devender Rao /** 7885968caeeSMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 7895968caeeSMarri Devender Rao * of a component, account or service. 7905968caeeSMarri Devender Rao */ 7915968caeeSMarri Devender Rao 7927e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificate(App& app) 7935968caeeSMarri Devender Rao { 7947e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 7957e860f15SJohn Edward Broadbent app, 7967e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/") 797ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 7987e860f15SJohn Edward Broadbent .methods( 7997e860f15SJohn Edward Broadbent boost::beast::http::verb:: 80045ca1b86SEd Tanous get)([&app](const crow::Request& req, 8017e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8027e860f15SJohn Edward Broadbent const std::string& param) -> void { 80345ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 80445ca1b86SEd Tanous { 80545ca1b86SEd Tanous return; 80645ca1b86SEd Tanous } 8077e860f15SJohn Edward Broadbent if (param.empty()) 8085968caeeSMarri Devender Rao { 8095968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 8105968caeeSMarri Devender Rao return; 8115968caeeSMarri Devender Rao } 8125968caeeSMarri Devender Rao long id = getIDFromURL(req.url); 8135968caeeSMarri Devender Rao 8147e860f15SJohn Edward Broadbent BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID=" 8157e860f15SJohn Edward Broadbent << std::to_string(id); 8165968caeeSMarri Devender Rao std::string certURL = 8175968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" + 8185968caeeSMarri Devender Rao std::to_string(id); 8195968caeeSMarri Devender Rao std::string objectPath = certs::httpsObjectPath; 8205968caeeSMarri Devender Rao objectPath += "/"; 8215968caeeSMarri Devender Rao objectPath += std::to_string(id); 8227e860f15SJohn Edward Broadbent getCertificateProperties(asyncResp, objectPath, 8237e860f15SJohn Edward Broadbent certs::httpsServiceName, id, certURL, 8247e860f15SJohn Edward Broadbent "HTTPS Certificate"); 8257e860f15SJohn Edward Broadbent }); 8265968caeeSMarri Devender Rao } 8275968caeeSMarri Devender Rao 8285968caeeSMarri Devender Rao /** 8295968caeeSMarri Devender Rao * Collection of HTTPS certificates 8305968caeeSMarri Devender Rao */ 8317e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificateCollection(App& app) 8325968caeeSMarri Devender Rao { 8337e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 8345968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 835ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 836*002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 837*002d39b4SEd Tanous [&app](const crow::Request& req, 838*002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 83945ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 84045ca1b86SEd Tanous { 84145ca1b86SEd Tanous return; 84245ca1b86SEd Tanous } 8431476687dSEd Tanous 8441476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 8451476687dSEd Tanous "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"; 8461476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 8471476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 8481476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; 8491476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 8501476687dSEd Tanous "A Collection of HTTPS certificate instances"; 8518d1b46d7Szhanghch05 8525968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 8535968caeeSMarri Devender Rao [asyncResp](const boost::system::error_code ec, 854711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 8555968caeeSMarri Devender Rao if (ec) 8565968caeeSMarri Devender Rao { 8575968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 8585968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 8595968caeeSMarri Devender Rao return; 8605968caeeSMarri Devender Rao } 861*002d39b4SEd Tanous nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 8625968caeeSMarri Devender Rao members = nlohmann::json::array(); 8635968caeeSMarri Devender Rao for (const auto& cert : certs) 8645968caeeSMarri Devender Rao { 8655968caeeSMarri Devender Rao long id = getIDFromURL(cert.first.str); 86637cce918SMarri Devender Rao if (id >= 0) 8675968caeeSMarri Devender Rao { 8681476687dSEd Tanous nlohmann::json::object_t member; 8691476687dSEd Tanous member["@odata.id"] = 8700fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" + 8711476687dSEd Tanous std::to_string(id); 8721476687dSEd Tanous members.push_back(std::move(member)); 8735968caeeSMarri Devender Rao } 8745968caeeSMarri Devender Rao } 875*002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 8765968caeeSMarri Devender Rao }, 87737cce918SMarri Devender Rao certs::httpsServiceName, certs::httpsObjectPath, 87837cce918SMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 8797e860f15SJohn Edward Broadbent }); 8805968caeeSMarri Devender Rao 8817e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 8827e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 883ed398213SEd Tanous .privileges(redfish::privileges::postCertificateCollection) 884*002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 885*002d39b4SEd Tanous [&app](const crow::Request& req, 8867e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 88745ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 88845ca1b86SEd Tanous { 88945ca1b86SEd Tanous return; 89045ca1b86SEd Tanous } 8915968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; 8928d1b46d7Szhanghch05 8931476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; 8941476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; 8955968caeeSMarri Devender Rao 896*002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 89758eb238fSKowalski, Kamil 89858eb238fSKowalski, Kamil if (certFileBody.empty()) 89958eb238fSKowalski, Kamil { 9000fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 901a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 90258eb238fSKowalski, Kamil return; 90358eb238fSKowalski, Kamil } 90458eb238fSKowalski, Kamil 9055968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 90658eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 9075968caeeSMarri Devender Rao 9085968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 909656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 910656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 9115968caeeSMarri Devender Rao if (ec) 9125968caeeSMarri Devender Rao { 9135968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 9145968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 9155968caeeSMarri Devender Rao return; 9165968caeeSMarri Devender Rao } 917656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 918656ec7e3SZbigniew Kurzynski if (certId < 0) 919656ec7e3SZbigniew Kurzynski { 920*002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath; 921656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 922656ec7e3SZbigniew Kurzynski return; 923656ec7e3SZbigniew Kurzynski } 9245968caeeSMarri Devender Rao std::string certURL = 9250fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" + 9265968caeeSMarri Devender Rao std::to_string(certId); 9270fda0f12SGeorge Liu getCertificateProperties(asyncResp, objectPath, 928*002d39b4SEd Tanous certs::httpsServiceName, certId, certURL, 929*002d39b4SEd Tanous "HTTPS Certificate"); 9305968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 9315968caeeSMarri Devender Rao << certFile->getCertFilePath(); 9325968caeeSMarri Devender Rao }, 93337cce918SMarri Devender Rao certs::httpsServiceName, certs::httpsObjectPath, 9340fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 9357e860f15SJohn Edward Broadbent }); 9367e860f15SJohn Edward Broadbent } // requestRoutesHTTPSCertificateCollection 9375968caeeSMarri Devender Rao 9385968caeeSMarri Devender Rao /** 93937cce918SMarri Devender Rao * @brief Retrieve the certificates installed list and append to the 94037cce918SMarri Devender Rao * response 94137cce918SMarri Devender Rao * 94237cce918SMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 94337cce918SMarri Devender Rao * @param[in] certURL Path of the certificate object 94437cce918SMarri Devender Rao * @param[in] path Path of the D-Bus service object 94537cce918SMarri Devender Rao * @return None 94637cce918SMarri Devender Rao */ 9474f48d5f6SEd Tanous inline void 9484f48d5f6SEd Tanous getCertificateLocations(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9498d1b46d7Szhanghch05 const std::string& certURL, const std::string& path, 95037cce918SMarri Devender Rao const std::string& service) 95137cce918SMarri Devender Rao { 95237cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL 95337cce918SMarri Devender Rao << " Path=" << path << " service= " << service; 95437cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 95537cce918SMarri Devender Rao [asyncResp, certURL](const boost::system::error_code ec, 956711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 95737cce918SMarri Devender Rao if (ec) 95837cce918SMarri Devender Rao { 959*002d39b4SEd Tanous BMCWEB_LOG_WARNING << "Certificate collection query failed: " << ec 9609c8e039eSJonathan Doman << ", skipping " << certURL; 96137cce918SMarri Devender Rao return; 96237cce918SMarri Devender Rao } 96337cce918SMarri Devender Rao nlohmann::json& links = 96437cce918SMarri Devender Rao asyncResp->res.jsonValue["Links"]["Certificates"]; 9659eb808c1SEd Tanous for (const auto& cert : certs) 96637cce918SMarri Devender Rao { 96737cce918SMarri Devender Rao long id = getIDFromURL(cert.first.str); 96837cce918SMarri Devender Rao if (id >= 0) 96937cce918SMarri Devender Rao { 9701476687dSEd Tanous nlohmann::json::object_t link; 9711476687dSEd Tanous link["@odata.id"] = certURL + std::to_string(id); 9721476687dSEd Tanous links.push_back(std::move(link)); 97337cce918SMarri Devender Rao } 97437cce918SMarri Devender Rao } 97537cce918SMarri Devender Rao asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] = 97637cce918SMarri Devender Rao links.size(); 97737cce918SMarri Devender Rao }, 97837cce918SMarri Devender Rao service, path, certs::dbusObjManagerIntf, "GetManagedObjects"); 9795968caeeSMarri Devender Rao } 9807e860f15SJohn Edward Broadbent 9817e860f15SJohn Edward Broadbent /** 9827e860f15SJohn Edward Broadbent * The certificate location schema defines a resource that an administrator 9837e860f15SJohn Edward Broadbent * can use in order to locate all certificates installed on a given service. 9847e860f15SJohn Edward Broadbent */ 9857e860f15SJohn Edward Broadbent inline void requestRoutesCertificateLocations(App& app) 9867e860f15SJohn Edward Broadbent { 9877e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 988ed398213SEd Tanous .privileges(redfish::privileges::getCertificateLocations) 989*002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 990*002d39b4SEd Tanous [&app](const crow::Request& req, 991*002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 99245ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 99345ca1b86SEd Tanous { 99445ca1b86SEd Tanous return; 99545ca1b86SEd Tanous } 9961476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 9971476687dSEd Tanous "/redfish/v1/CertificateService/CertificateLocations"; 9981476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 9991476687dSEd Tanous "#CertificateLocations.v1_0_0.CertificateLocations"; 10001476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Certificate Locations"; 10011476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "CertificateLocations"; 10021476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 10037e860f15SJohn Edward Broadbent "Defines a resource that an administrator can use in order to " 10041476687dSEd Tanous "locate all certificates installed on a given service"; 10057e860f15SJohn Edward Broadbent 10067e860f15SJohn Edward Broadbent nlohmann::json& links = 10077e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Links"]["Certificates"]; 10087e860f15SJohn Edward Broadbent links = nlohmann::json::array(); 10097e860f15SJohn Edward Broadbent getCertificateLocations( 10107e860f15SJohn Edward Broadbent asyncResp, 10117e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/", 10127e860f15SJohn Edward Broadbent certs::httpsObjectPath, certs::httpsServiceName); 1013*002d39b4SEd Tanous getCertificateLocations(asyncResp, 1014*002d39b4SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/", 10157e860f15SJohn Edward Broadbent certs::ldapObjectPath, certs::ldapServiceName); 10167e860f15SJohn Edward Broadbent getCertificateLocations( 10177e860f15SJohn Edward Broadbent asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/", 10187e860f15SJohn Edward Broadbent certs::authorityObjectPath, certs::authorityServiceName); 10197e860f15SJohn Edward Broadbent }); 10207e860f15SJohn Edward Broadbent } 10217e860f15SJohn Edward Broadbent // requestRoutesCertificateLocations 102237cce918SMarri Devender Rao 102337cce918SMarri Devender Rao /** 102437cce918SMarri Devender Rao * Collection of LDAP certificates 102537cce918SMarri Devender Rao */ 10267e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificateCollection(App& app) 102737cce918SMarri Devender Rao { 10287e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1029ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 1030*002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1031*002d39b4SEd Tanous [&app](const crow::Request& req, 1032*002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 103345ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 103445ca1b86SEd Tanous { 103545ca1b86SEd Tanous return; 103645ca1b86SEd Tanous } 10371476687dSEd Tanous 10381476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 10391476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 10401476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 10411476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 10421476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; 10431476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 10441476687dSEd Tanous "A Collection of LDAP certificate instances"; 10458d1b46d7Szhanghch05 104637cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 104737cce918SMarri Devender Rao [asyncResp](const boost::system::error_code ec, 1048711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 1049*002d39b4SEd Tanous nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 10509c8e039eSJonathan Doman nlohmann::json& count = 10519c8e039eSJonathan Doman asyncResp->res.jsonValue["Members@odata.count"]; 10529c8e039eSJonathan Doman members = nlohmann::json::array(); 10539c8e039eSJonathan Doman count = 0; 105437cce918SMarri Devender Rao if (ec) 105537cce918SMarri Devender Rao { 1056*002d39b4SEd Tanous BMCWEB_LOG_WARNING << "LDAP certificate query failed: " << ec; 105737cce918SMarri Devender Rao return; 105837cce918SMarri Devender Rao } 105937cce918SMarri Devender Rao for (const auto& cert : certs) 106037cce918SMarri Devender Rao { 106137cce918SMarri Devender Rao long id = getIDFromURL(cert.first.str); 106237cce918SMarri Devender Rao if (id >= 0) 106337cce918SMarri Devender Rao { 10641476687dSEd Tanous nlohmann::json::object_t member; 10651476687dSEd Tanous member["@odata.id"] = 10660fda0f12SGeorge Liu "/redfish/v1/AccountService/LDAP/Certificates/" + 10671476687dSEd Tanous std::to_string(id); 10681476687dSEd Tanous members.push_back(std::move(member)); 106937cce918SMarri Devender Rao } 107037cce918SMarri Devender Rao } 10719c8e039eSJonathan Doman count = members.size(); 107237cce918SMarri Devender Rao }, 107337cce918SMarri Devender Rao certs::ldapServiceName, certs::ldapObjectPath, 107437cce918SMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 10757e860f15SJohn Edward Broadbent }); 107637cce918SMarri Devender Rao 10777e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1078ed398213SEd Tanous .privileges(redfish::privileges::postCertificateCollection) 10797e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 108045ca1b86SEd Tanous [&app](const crow::Request& req, 10817e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 108245ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 108345ca1b86SEd Tanous { 108445ca1b86SEd Tanous return; 108545ca1b86SEd Tanous } 1086*002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 108758eb238fSKowalski, Kamil 108858eb238fSKowalski, Kamil if (certFileBody.empty()) 108958eb238fSKowalski, Kamil { 1090*002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1091a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 109258eb238fSKowalski, Kamil return; 109358eb238fSKowalski, Kamil } 109458eb238fSKowalski, Kamil 109558eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 109658eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 109758eb238fSKowalski, Kamil 109837cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 1099656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1100656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 110137cce918SMarri Devender Rao if (ec) 110237cce918SMarri Devender Rao { 110337cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 110437cce918SMarri Devender Rao messages::internalError(asyncResp->res); 110537cce918SMarri Devender Rao return; 110637cce918SMarri Devender Rao } 1107656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 1108656ec7e3SZbigniew Kurzynski if (certId < 0) 1109656ec7e3SZbigniew Kurzynski { 1110*002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath; 1111656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 1112656ec7e3SZbigniew Kurzynski return; 1113656ec7e3SZbigniew Kurzynski } 111437cce918SMarri Devender Rao std::string certURL = 111537cce918SMarri Devender Rao "/redfish/v1/AccountService/LDAP/Certificates/" + 111637cce918SMarri Devender Rao std::to_string(certId); 111737cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 1118*002d39b4SEd Tanous certs::ldapServiceName, certId, certURL, 1119*002d39b4SEd Tanous "LDAP Certificate"); 112037cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "LDAP certificate install file=" 112137cce918SMarri Devender Rao << certFile->getCertFilePath(); 112237cce918SMarri Devender Rao }, 112337cce918SMarri Devender Rao certs::ldapServiceName, certs::ldapObjectPath, 1124*002d39b4SEd Tanous certs::certInstallIntf, "Install", certFile->getCertFilePath()); 11257e860f15SJohn Edward Broadbent }); 11267e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificateCollection 112737cce918SMarri Devender Rao 112837cce918SMarri Devender Rao /** 112937cce918SMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 113037cce918SMarri Devender Rao * of a component, account or service. 113137cce918SMarri Devender Rao */ 11327e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificate(App& app) 113337cce918SMarri Devender Rao { 11347e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1135ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 11367e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 113745ca1b86SEd Tanous [&app](const crow::Request& req, 11387e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 11397e860f15SJohn Edward Broadbent const std::string&) { 114045ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 114145ca1b86SEd Tanous { 114245ca1b86SEd Tanous return; 114345ca1b86SEd Tanous } 114437cce918SMarri Devender Rao long id = getIDFromURL(req.url); 114537cce918SMarri Devender Rao if (id < 0) 114637cce918SMarri Devender Rao { 114737cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "Invalid url value" << req.url; 114837cce918SMarri Devender Rao messages::internalError(asyncResp->res); 114937cce918SMarri Devender Rao return; 115037cce918SMarri Devender Rao } 1151*002d39b4SEd Tanous BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << std::to_string(id); 1152*002d39b4SEd Tanous std::string certURL = "/redfish/v1/AccountService/LDAP/Certificates/" + 115337cce918SMarri Devender Rao std::to_string(id); 115437cce918SMarri Devender Rao std::string objectPath = certs::ldapObjectPath; 115537cce918SMarri Devender Rao objectPath += "/"; 115637cce918SMarri Devender Rao objectPath += std::to_string(id); 1157*002d39b4SEd Tanous getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName, 1158*002d39b4SEd Tanous id, certURL, "LDAP Certificate"); 11597e860f15SJohn Edward Broadbent }); 11607e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificate 1161cfcd5f6bSMarri Devender Rao /** 1162cfcd5f6bSMarri Devender Rao * Collection of TrustStoreCertificate certificates 1163cfcd5f6bSMarri Devender Rao */ 11647e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificateCollection(App& app) 1165cfcd5f6bSMarri Devender Rao { 11667e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1167ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 1168*002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1169*002d39b4SEd Tanous [&app](const crow::Request& req, 1170*002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 117145ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 117245ca1b86SEd Tanous { 117345ca1b86SEd Tanous return; 117445ca1b86SEd Tanous } 11751476687dSEd Tanous 11761476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 11771476687dSEd Tanous "/redfish/v1/Managers/bmc/Truststore/Certificates/"; 11781476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 11791476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 1180*002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; 11811476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 11821476687dSEd Tanous "A Collection of TrustStore certificate instances"; 11838d1b46d7Szhanghch05 1184cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1185cfcd5f6bSMarri Devender Rao [asyncResp](const boost::system::error_code ec, 1186711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 1187cfcd5f6bSMarri Devender Rao if (ec) 1188cfcd5f6bSMarri Devender Rao { 1189cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1190cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1191cfcd5f6bSMarri Devender Rao return; 1192cfcd5f6bSMarri Devender Rao } 1193*002d39b4SEd Tanous nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 1194cfcd5f6bSMarri Devender Rao members = nlohmann::json::array(); 1195cfcd5f6bSMarri Devender Rao for (const auto& cert : certs) 1196cfcd5f6bSMarri Devender Rao { 1197cfcd5f6bSMarri Devender Rao long id = getIDFromURL(cert.first.str); 1198cfcd5f6bSMarri Devender Rao if (id >= 0) 1199cfcd5f6bSMarri Devender Rao { 12001476687dSEd Tanous nlohmann::json::object_t member; 12011476687dSEd Tanous member["@odata.id"] = 12020fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/Truststore/Certificates/" + 12031476687dSEd Tanous std::to_string(id); 12041476687dSEd Tanous members.push_back(std::move(member)); 1205cfcd5f6bSMarri Devender Rao } 1206cfcd5f6bSMarri Devender Rao } 1207*002d39b4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 1208cfcd5f6bSMarri Devender Rao }, 1209cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 1210cfcd5f6bSMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 12117e860f15SJohn Edward Broadbent }); 1212cfcd5f6bSMarri Devender Rao 12137e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1214ed398213SEd Tanous .privileges(redfish::privileges::postCertificateCollection) 1215*002d39b4SEd Tanous .methods(boost::beast::http::verb::post)( 1216*002d39b4SEd Tanous [&app](const crow::Request& req, 12177e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 121845ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 121945ca1b86SEd Tanous { 122045ca1b86SEd Tanous return; 122145ca1b86SEd Tanous } 1222*002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 1223a08752f5SZbigniew Kurzynski 1224a08752f5SZbigniew Kurzynski if (certFileBody.empty()) 1225a08752f5SZbigniew Kurzynski { 12260fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1227a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1228a08752f5SZbigniew Kurzynski return; 1229a08752f5SZbigniew Kurzynski } 1230a08752f5SZbigniew Kurzynski 1231a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1232a08752f5SZbigniew Kurzynski std::make_shared<CertificateFile>(certFileBody); 1233cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1234656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1235656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1236cfcd5f6bSMarri Devender Rao if (ec) 1237cfcd5f6bSMarri Devender Rao { 1238cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1239cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1240cfcd5f6bSMarri Devender Rao return; 1241cfcd5f6bSMarri Devender Rao } 1242656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 1243656ec7e3SZbigniew Kurzynski if (certId < 0) 1244656ec7e3SZbigniew Kurzynski { 1245*002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Invalid objectPath value" << objectPath; 1246656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 1247656ec7e3SZbigniew Kurzynski return; 1248656ec7e3SZbigniew Kurzynski } 12490fda0f12SGeorge Liu std::string certURL = 12500fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/Truststore/Certificates/" + 1251cfcd5f6bSMarri Devender Rao std::to_string(certId); 1252656ec7e3SZbigniew Kurzynski 1253*002d39b4SEd Tanous getCertificateProperties(asyncResp, objectPath, 1254*002d39b4SEd Tanous certs::authorityServiceName, certId, 1255*002d39b4SEd Tanous certURL, "TrustStore Certificate"); 12560fda0f12SGeorge Liu BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" 1257cfcd5f6bSMarri Devender Rao << certFile->getCertFilePath(); 1258cfcd5f6bSMarri Devender Rao }, 1259cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 12600fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 12617e860f15SJohn Edward Broadbent }); 12627e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificateCollection 1263cfcd5f6bSMarri Devender Rao 1264cfcd5f6bSMarri Devender Rao /** 1265cfcd5f6bSMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 1266cfcd5f6bSMarri Devender Rao * of a component, account or service. 1267cfcd5f6bSMarri Devender Rao */ 12687e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificate(App& app) 1269cfcd5f6bSMarri Devender Rao { 12707e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1271ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 12727e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 127345ca1b86SEd Tanous [&app](const crow::Request& req, 12747e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12757e860f15SJohn Edward Broadbent const std::string&) { 127645ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 127745ca1b86SEd Tanous { 127845ca1b86SEd Tanous return; 127945ca1b86SEd Tanous } 1280cfcd5f6bSMarri Devender Rao long id = getIDFromURL(req.url); 1281cfcd5f6bSMarri Devender Rao if (id < 0) 1282cfcd5f6bSMarri Devender Rao { 1283cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "Invalid url value" << req.url; 1284cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1285cfcd5f6bSMarri Devender Rao return; 1286cfcd5f6bSMarri Devender Rao } 1287cfcd5f6bSMarri Devender Rao BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID=" 1288cfcd5f6bSMarri Devender Rao << std::to_string(id); 1289cfcd5f6bSMarri Devender Rao std::string certURL = 1290cfcd5f6bSMarri Devender Rao "/redfish/v1/Managers/bmc/Truststore/Certificates/" + 1291cfcd5f6bSMarri Devender Rao std::to_string(id); 1292cfcd5f6bSMarri Devender Rao std::string objectPath = certs::authorityObjectPath; 1293cfcd5f6bSMarri Devender Rao objectPath += "/"; 1294cfcd5f6bSMarri Devender Rao objectPath += std::to_string(id); 1295cfcd5f6bSMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 1296*002d39b4SEd Tanous certs::authorityServiceName, id, certURL, 1297*002d39b4SEd Tanous "TrustStore Certificate"); 12987e860f15SJohn Edward Broadbent }); 129907a60299SZbigniew Kurzynski 13007e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1301ed398213SEd Tanous .privileges(redfish::privileges::deleteCertificate) 13027e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 130345ca1b86SEd Tanous [&app](const crow::Request& req, 13047e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 13057e860f15SJohn Edward Broadbent const std::string& param) { 130645ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 130745ca1b86SEd Tanous { 130845ca1b86SEd Tanous return; 130945ca1b86SEd Tanous } 13107e860f15SJohn Edward Broadbent if (param.empty()) 131107a60299SZbigniew Kurzynski { 131207a60299SZbigniew Kurzynski messages::internalError(asyncResp->res); 131307a60299SZbigniew Kurzynski return; 131407a60299SZbigniew Kurzynski } 131507a60299SZbigniew Kurzynski 131607a60299SZbigniew Kurzynski long id = getIDFromURL(req.url); 131707a60299SZbigniew Kurzynski if (id < 0) 131807a60299SZbigniew Kurzynski { 131907a60299SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid url value: " << req.url; 1320*002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "TrustStore Certificate", 132107a60299SZbigniew Kurzynski std::string(req.url)); 132207a60299SZbigniew Kurzynski return; 132307a60299SZbigniew Kurzynski } 132407a60299SZbigniew Kurzynski BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID=" 132507a60299SZbigniew Kurzynski << std::to_string(id); 132607a60299SZbigniew Kurzynski std::string certPath = certs::authorityObjectPath; 132707a60299SZbigniew Kurzynski certPath += "/"; 132807a60299SZbigniew Kurzynski certPath += std::to_string(id); 132907a60299SZbigniew Kurzynski 133007a60299SZbigniew Kurzynski crow::connections::systemBus->async_method_call( 133107a60299SZbigniew Kurzynski [asyncResp, id](const boost::system::error_code ec) { 133207a60299SZbigniew Kurzynski if (ec) 133307a60299SZbigniew Kurzynski { 133407a60299SZbigniew Kurzynski messages::resourceNotFound(asyncResp->res, 133507a60299SZbigniew Kurzynski "TrustStore Certificate", 133607a60299SZbigniew Kurzynski std::to_string(id)); 133707a60299SZbigniew Kurzynski return; 133807a60299SZbigniew Kurzynski } 133907a60299SZbigniew Kurzynski BMCWEB_LOG_INFO << "Certificate deleted"; 1340*002d39b4SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 134107a60299SZbigniew Kurzynski }, 134207a60299SZbigniew Kurzynski certs::authorityServiceName, certPath, certs::objDeleteIntf, 134307a60299SZbigniew Kurzynski "Delete"); 13447e860f15SJohn Edward Broadbent }); 13457e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate 13465968caeeSMarri Devender Rao } // namespace redfish 1347