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) 4945ca1b86SEd Tanous .methods(boost::beast::http::verb::get)([&app](const crow::Request& req, 5045ca1b86SEd Tanous const std::shared_ptr< 5145ca1b86SEd Tanous bmcweb::AsyncResp>& 5245ca1b86SEd Tanous asyncResp) { 5345ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 5445ca1b86SEd Tanous { 5545ca1b86SEd Tanous return; 5645ca1b86SEd Tanous } 578d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 587e860f15SJohn Edward Broadbent {"@odata.type", 597e860f15SJohn Edward Broadbent "#CertificateService.v1_0_0.CertificateService"}, 605968caeeSMarri Devender Rao {"@odata.id", "/redfish/v1/CertificateService"}, 615968caeeSMarri Devender Rao {"Id", "CertificateService"}, 625968caeeSMarri Devender Rao {"Name", "Certificate Service"}, 6372048780SAbhishek Patel {"Description", "Actions available to manage certificates"}}; 6472048780SAbhishek Patel // /redfish/v1/CertificateService/CertificateLocations is something 6572048780SAbhishek Patel // only ConfigureManager can access then only display when the user 6672048780SAbhishek Patel // has permissions ConfigureManager 6772048780SAbhishek Patel Privileges effectiveUserPrivileges = 6872048780SAbhishek Patel redfish::getUserPrivileges(req.userRole); 6972048780SAbhishek Patel if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 7072048780SAbhishek Patel effectiveUserPrivileges)) 7172048780SAbhishek Patel { 728d1b46d7Szhanghch05 asyncResp->res.jsonValue["CertificateLocations"] = { 735968caeeSMarri Devender Rao {"@odata.id", 745968caeeSMarri Devender Rao "/redfish/v1/CertificateService/CertificateLocations"}}; 7572048780SAbhishek Patel } 760fda0f12SGeorge Liu asyncResp->res 770fda0f12SGeorge Liu .jsonValue["Actions"] 780fda0f12SGeorge Liu ["#CertificateService.ReplaceCertificate"] = { 790fda0f12SGeorge Liu {"target", 800fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"}, 815968caeeSMarri Devender Rao {"CertificateType@Redfish.AllowableValues", {"PEM"}}}; 827e860f15SJohn Edward Broadbent asyncResp->res 837e860f15SJohn Edward Broadbent .jsonValue["Actions"]["#CertificateService.GenerateCSR"] = { 840fda0f12SGeorge Liu {"target", 850fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"}}; 867e860f15SJohn Edward Broadbent }); 877e860f15SJohn Edward Broadbent } // requestRoutesCertificateService 8837cce918SMarri Devender Rao 895968caeeSMarri Devender Rao /** 905968caeeSMarri Devender Rao * @brief Find the ID specified in the URL 915968caeeSMarri Devender Rao * Finds the numbers specified after the last "/" in the URL and returns. 925968caeeSMarri Devender Rao * @param[in] path URL 935968caeeSMarri Devender Rao * @return -1 on failure and number on success 945968caeeSMarri Devender Rao */ 9523a21a1cSEd Tanous inline long getIDFromURL(const std::string_view url) 965968caeeSMarri Devender Rao { 97f23b7296SEd Tanous std::size_t found = url.rfind('/'); 985968caeeSMarri Devender Rao if (found == std::string::npos) 995968caeeSMarri Devender Rao { 1005968caeeSMarri Devender Rao return -1; 1015968caeeSMarri Devender Rao } 102e6604b11SIwona Klimaszewska 1035968caeeSMarri Devender Rao if ((found + 1) < url.length()) 1045968caeeSMarri Devender Rao { 1055968caeeSMarri Devender Rao std::string_view str = url.substr(found + 1); 106e6604b11SIwona Klimaszewska 107e6604b11SIwona Klimaszewska return boost::convert<long>(str, boost::cnv::strtol()).value_or(-1); 1085968caeeSMarri Devender Rao } 109e6604b11SIwona Klimaszewska 1105968caeeSMarri Devender Rao return -1; 1115968caeeSMarri Devender Rao } 1125968caeeSMarri Devender Rao 1138d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody( 1148d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 11558eb238fSKowalski, Kamil const crow::Request& req) 11658eb238fSKowalski, Kamil { 11758eb238fSKowalski, Kamil nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false); 11858eb238fSKowalski, Kamil 11958eb238fSKowalski, Kamil if (reqJson.is_discarded()) 12058eb238fSKowalski, Kamil { 12158eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 12258eb238fSKowalski, Kamil return req.body; 12358eb238fSKowalski, Kamil } 12458eb238fSKowalski, Kamil 12558eb238fSKowalski, Kamil std::string certificate; 12658eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 12758eb238fSKowalski, Kamil 12815ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString", 12915ed6780SWilly Tu certificate, "CertificateType", 13015ed6780SWilly Tu certificateType)) 13158eb238fSKowalski, Kamil { 13258eb238fSKowalski, Kamil BMCWEB_LOG_ERROR << "Required parameters are missing"; 13358eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 134abb93cddSEd Tanous return {}; 13558eb238fSKowalski, Kamil } 13658eb238fSKowalski, Kamil 13758eb238fSKowalski, Kamil if (*certificateType != "PEM") 13858eb238fSKowalski, Kamil { 13958eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 14058eb238fSKowalski, Kamil "CertificateType"); 141abb93cddSEd Tanous return {}; 14258eb238fSKowalski, Kamil } 14358eb238fSKowalski, Kamil 14458eb238fSKowalski, Kamil return certificate; 14558eb238fSKowalski, Kamil } 14658eb238fSKowalski, Kamil 1475968caeeSMarri Devender Rao /** 1485968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 1495968caeeSMarri Devender Rao */ 1505968caeeSMarri Devender Rao class CertificateFile 1515968caeeSMarri Devender Rao { 1525968caeeSMarri Devender Rao public: 1535968caeeSMarri Devender Rao CertificateFile() = delete; 1545968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 1555968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 1565968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 1575968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 1585968caeeSMarri Devender Rao CertificateFile(const std::string& certString) 1595968caeeSMarri Devender Rao { 16072d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 1615207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 1625207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 1635207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 164e662eae8SEd Tanous if (tempDirectory != nullptr) 1655968caeeSMarri Devender Rao { 1665968caeeSMarri Devender Rao certDirectory = tempDirectory; 1675968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 1685968caeeSMarri Devender Rao std::ofstream out(certificateFile, std::ofstream::out | 1695968caeeSMarri Devender Rao std::ofstream::binary | 1705968caeeSMarri Devender Rao std::ofstream::trunc); 1715968caeeSMarri Devender Rao out << certString; 1725968caeeSMarri Devender Rao out.close(); 1738cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Creating certificate file" 1748cc8edecSEd Tanous << certificateFile.string(); 1755968caeeSMarri Devender Rao } 1765968caeeSMarri Devender Rao } 1775968caeeSMarri Devender Rao ~CertificateFile() 1785968caeeSMarri Devender Rao { 1795968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1805968caeeSMarri Devender Rao { 1818cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Removing certificate file" 1828cc8edecSEd Tanous << certificateFile.string(); 18323a21a1cSEd Tanous std::error_code ec; 18423a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 18523a21a1cSEd Tanous if (ec) 1865968caeeSMarri Devender Rao { 1875968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Failed to remove temp directory" 1888cc8edecSEd Tanous << certDirectory.string(); 1895968caeeSMarri Devender Rao } 1905968caeeSMarri Devender Rao } 1915968caeeSMarri Devender Rao } 1925968caeeSMarri Devender Rao std::string getCertFilePath() 1935968caeeSMarri Devender Rao { 1945968caeeSMarri Devender Rao return certificateFile; 1955968caeeSMarri Devender Rao } 1965968caeeSMarri Devender Rao 1975968caeeSMarri Devender Rao private: 1985968caeeSMarri Devender Rao std::filesystem::path certificateFile; 1995968caeeSMarri Devender Rao std::filesystem::path certDirectory; 2005968caeeSMarri Devender Rao }; 2015968caeeSMarri Devender Rao 20230215816SMarri Devender Rao static std::unique_ptr<sdbusplus::bus::match::match> csrMatcher; 20330215816SMarri Devender Rao /** 20430215816SMarri Devender Rao * @brief Read data from CSR D-bus object and set to response 20530215816SMarri Devender Rao * 20630215816SMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 20730215816SMarri Devender Rao * @param[in] certURI Link to certifiate collection URI 20830215816SMarri Devender Rao * @param[in] service D-Bus service name 20930215816SMarri Devender Rao * @param[in] certObjPath certificate D-Bus object path 21030215816SMarri Devender Rao * @param[in] csrObjPath CSR D-Bus object path 21130215816SMarri Devender Rao * @return None 21230215816SMarri Devender Rao */ 2138d1b46d7Szhanghch05 static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21430215816SMarri Devender Rao const std::string& certURI, const std::string& service, 21530215816SMarri Devender Rao const std::string& certObjPath, 21630215816SMarri Devender Rao const std::string& csrObjPath) 21730215816SMarri Devender Rao { 21830215816SMarri Devender Rao BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath 21930215816SMarri Devender Rao << " CSRObjectPath=" << csrObjPath 22030215816SMarri Devender Rao << " service=" << service; 22130215816SMarri Devender Rao crow::connections::systemBus->async_method_call( 22230215816SMarri Devender Rao [asyncResp, certURI](const boost::system::error_code ec, 22330215816SMarri Devender Rao const std::string& csr) { 22430215816SMarri Devender Rao if (ec) 22530215816SMarri Devender Rao { 22630215816SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 22730215816SMarri Devender Rao messages::internalError(asyncResp->res); 22830215816SMarri Devender Rao return; 22930215816SMarri Devender Rao } 23030215816SMarri Devender Rao if (csr.empty()) 23130215816SMarri Devender Rao { 23230215816SMarri Devender Rao BMCWEB_LOG_ERROR << "CSR read is empty"; 23330215816SMarri Devender Rao messages::internalError(asyncResp->res); 23430215816SMarri Devender Rao return; 23530215816SMarri Devender Rao } 23630215816SMarri Devender Rao asyncResp->res.jsonValue["CSRString"] = csr; 23730215816SMarri Devender Rao asyncResp->res.jsonValue["CertificateCollection"] = { 23830215816SMarri Devender Rao {"@odata.id", certURI}}; 23930215816SMarri Devender Rao }, 24030215816SMarri Devender Rao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 24130215816SMarri Devender Rao } 24230215816SMarri Devender Rao 24330215816SMarri Devender Rao /** 24430215816SMarri Devender Rao * Action to Generate CSR 24530215816SMarri Devender Rao */ 2467e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionGenerateCSR(App& app) 24730215816SMarri Devender Rao { 2480fda0f12SGeorge Liu BMCWEB_ROUTE( 2490fda0f12SGeorge Liu app, 2500fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 251*5344ab8eSAbhishek Patel .privileges(redfish::privileges::postCertificateService) 2520fda0f12SGeorge Liu .methods( 2530fda0f12SGeorge Liu boost::beast::http::verb:: 25445ca1b86SEd Tanous post)([&app]( 25545ca1b86SEd Tanous const crow::Request& req, 2567e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 25745ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 25845ca1b86SEd Tanous { 25945ca1b86SEd Tanous return; 26045ca1b86SEd Tanous } 2612c70f800SEd Tanous static const int rsaKeyBitLength = 2048; 2628d1b46d7Szhanghch05 26330215816SMarri Devender Rao // Required parameters 26430215816SMarri Devender Rao std::string city; 26530215816SMarri Devender Rao std::string commonName; 26630215816SMarri Devender Rao std::string country; 26730215816SMarri Devender Rao std::string organization; 26830215816SMarri Devender Rao std::string organizationalUnit; 26930215816SMarri Devender Rao std::string state; 27030215816SMarri Devender Rao nlohmann::json certificateCollection; 27130215816SMarri Devender Rao 27230215816SMarri Devender Rao // Optional parameters 27330215816SMarri Devender Rao std::optional<std::vector<std::string>> optAlternativeNames = 27430215816SMarri Devender Rao std::vector<std::string>(); 27530215816SMarri Devender Rao std::optional<std::string> optContactPerson = ""; 27630215816SMarri Devender Rao std::optional<std::string> optChallengePassword = ""; 27730215816SMarri Devender Rao std::optional<std::string> optEmail = ""; 27830215816SMarri Devender Rao std::optional<std::string> optGivenName = ""; 27930215816SMarri Devender Rao std::optional<std::string> optInitials = ""; 2802c70f800SEd Tanous std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 281aaf3206fSVernon Mauery std::optional<std::string> optKeyCurveId = "secp384r1"; 28230215816SMarri Devender Rao std::optional<std::string> optKeyPairAlgorithm = "EC"; 28330215816SMarri Devender Rao std::optional<std::vector<std::string>> optKeyUsage = 28430215816SMarri Devender Rao std::vector<std::string>(); 28530215816SMarri Devender Rao std::optional<std::string> optSurname = ""; 28630215816SMarri Devender Rao std::optional<std::string> optUnstructuredName = ""; 28715ed6780SWilly Tu if (!json_util::readJsonAction( 2880fda0f12SGeorge Liu req, asyncResp->res, "City", city, "CommonName", commonName, 2890fda0f12SGeorge Liu "ContactPerson", optContactPerson, "Country", country, 2900fda0f12SGeorge Liu "Organization", organization, "OrganizationalUnit", 2910fda0f12SGeorge Liu organizationalUnit, "State", state, "CertificateCollection", 2920fda0f12SGeorge Liu certificateCollection, "AlternativeNames", 2930fda0f12SGeorge Liu optAlternativeNames, "ChallengePassword", 2940fda0f12SGeorge Liu optChallengePassword, "Email", optEmail, "GivenName", 2950fda0f12SGeorge Liu optGivenName, "Initials", optInitials, "KeyBitLength", 2960fda0f12SGeorge Liu optKeyBitLength, "KeyCurveId", optKeyCurveId, 2970fda0f12SGeorge Liu "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage", 2980fda0f12SGeorge Liu optKeyUsage, "Surname", optSurname, "UnstructuredName", 2990fda0f12SGeorge Liu optUnstructuredName)) 30030215816SMarri Devender Rao { 30130215816SMarri Devender Rao return; 30230215816SMarri Devender Rao } 30330215816SMarri Devender Rao 30430215816SMarri Devender Rao // bmcweb has no way to store or decode a private key challenge 3057e860f15SJohn Edward Broadbent // password, which will likely cause bmcweb to crash on startup 3067e860f15SJohn Edward Broadbent // if this is not set on a post so not allowing the user to set 3077e860f15SJohn Edward Broadbent // value 30826f6976fSEd Tanous if (!optChallengePassword->empty()) 30930215816SMarri Devender Rao { 3107e860f15SJohn Edward Broadbent messages::actionParameterNotSupported( 3117e860f15SJohn Edward Broadbent asyncResp->res, "GenerateCSR", "ChallengePassword"); 31230215816SMarri Devender Rao return; 31330215816SMarri Devender Rao } 31430215816SMarri Devender Rao 31530215816SMarri Devender Rao std::string certURI; 3167e860f15SJohn Edward Broadbent if (!redfish::json_util::readJson(certificateCollection, 3177e860f15SJohn Edward Broadbent asyncResp->res, "@odata.id", 3187e860f15SJohn Edward Broadbent certURI)) 31930215816SMarri Devender Rao { 32030215816SMarri Devender Rao return; 32130215816SMarri Devender Rao } 32230215816SMarri Devender Rao 32330215816SMarri Devender Rao std::string objectPath; 32430215816SMarri Devender Rao std::string service; 3250fda0f12SGeorge Liu if (boost::starts_with( 3260fda0f12SGeorge Liu certURI, 3270fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 32830215816SMarri Devender Rao { 32930215816SMarri Devender Rao objectPath = certs::httpsObjectPath; 33030215816SMarri Devender Rao service = certs::httpsServiceName; 33130215816SMarri Devender Rao } 3323b7f0149SMarri Devender Rao else if (boost::starts_with( 3337e860f15SJohn Edward Broadbent certURI, 3347e860f15SJohn Edward Broadbent "/redfish/v1/AccountService/LDAP/Certificates")) 3353b7f0149SMarri Devender Rao { 3363b7f0149SMarri Devender Rao objectPath = certs::ldapObjectPath; 3373b7f0149SMarri Devender Rao service = certs::ldapServiceName; 3383b7f0149SMarri Devender Rao } 33930215816SMarri Devender Rao else 34030215816SMarri Devender Rao { 34130215816SMarri Devender Rao messages::actionParameterNotSupported( 34230215816SMarri Devender Rao asyncResp->res, "CertificateCollection", "GenerateCSR"); 34330215816SMarri Devender Rao return; 34430215816SMarri Devender Rao } 34530215816SMarri Devender Rao 34630215816SMarri Devender Rao // supporting only EC and RSA algorithm 3470fda0f12SGeorge Liu if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 34830215816SMarri Devender Rao { 34930215816SMarri Devender Rao messages::actionParameterNotSupported( 35030215816SMarri Devender Rao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 35130215816SMarri Devender Rao return; 35230215816SMarri Devender Rao } 35330215816SMarri Devender Rao 3547e860f15SJohn Edward Broadbent // supporting only 2048 key bit length for RSA algorithm due to 3557e860f15SJohn Edward Broadbent // time consumed in generating private key 35630215816SMarri Devender Rao if (*optKeyPairAlgorithm == "RSA" && 3572c70f800SEd Tanous *optKeyBitLength != rsaKeyBitLength) 35830215816SMarri Devender Rao { 3597e860f15SJohn Edward Broadbent messages::propertyValueNotInList( 3607e860f15SJohn Edward Broadbent asyncResp->res, std::to_string(*optKeyBitLength), 36130215816SMarri Devender Rao "KeyBitLength"); 36230215816SMarri Devender Rao return; 36330215816SMarri Devender Rao } 36430215816SMarri Devender Rao 36530215816SMarri Devender Rao // validate KeyUsage supporting only 1 type based on URL 3660fda0f12SGeorge Liu if (boost::starts_with( 3670fda0f12SGeorge Liu certURI, 3680fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 36930215816SMarri Devender Rao { 37026f6976fSEd Tanous if (optKeyUsage->empty()) 37130215816SMarri Devender Rao { 37230215816SMarri Devender Rao optKeyUsage->push_back("ServerAuthentication"); 37330215816SMarri Devender Rao } 37430215816SMarri Devender Rao else if (optKeyUsage->size() == 1) 37530215816SMarri Devender Rao { 37630215816SMarri Devender Rao if ((*optKeyUsage)[0] != "ServerAuthentication") 37730215816SMarri Devender Rao { 37830215816SMarri Devender Rao messages::propertyValueNotInList( 37930215816SMarri Devender Rao asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); 38030215816SMarri Devender Rao return; 38130215816SMarri Devender Rao } 38230215816SMarri Devender Rao } 38330215816SMarri Devender Rao else 38430215816SMarri Devender Rao { 38530215816SMarri Devender Rao messages::actionParameterNotSupported( 38630215816SMarri Devender Rao asyncResp->res, "KeyUsage", "GenerateCSR"); 38730215816SMarri Devender Rao return; 38830215816SMarri Devender Rao } 38930215816SMarri Devender Rao } 3903b7f0149SMarri Devender Rao else if (boost::starts_with( 3917e860f15SJohn Edward Broadbent certURI, 3927e860f15SJohn Edward Broadbent "/redfish/v1/AccountService/LDAP/Certificates")) 3933b7f0149SMarri Devender Rao { 39426f6976fSEd Tanous if (optKeyUsage->empty()) 3953b7f0149SMarri Devender Rao { 3963b7f0149SMarri Devender Rao optKeyUsage->push_back("ClientAuthentication"); 3973b7f0149SMarri Devender Rao } 3983b7f0149SMarri Devender Rao else if (optKeyUsage->size() == 1) 3993b7f0149SMarri Devender Rao { 4003b7f0149SMarri Devender Rao if ((*optKeyUsage)[0] != "ClientAuthentication") 4013b7f0149SMarri Devender Rao { 4023b7f0149SMarri Devender Rao messages::propertyValueNotInList( 4033b7f0149SMarri Devender Rao asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); 4043b7f0149SMarri Devender Rao return; 4053b7f0149SMarri Devender Rao } 4063b7f0149SMarri Devender Rao } 4073b7f0149SMarri Devender Rao else 4083b7f0149SMarri Devender Rao { 4093b7f0149SMarri Devender Rao messages::actionParameterNotSupported( 4103b7f0149SMarri Devender Rao asyncResp->res, "KeyUsage", "GenerateCSR"); 4113b7f0149SMarri Devender Rao return; 4123b7f0149SMarri Devender Rao } 4133b7f0149SMarri Devender Rao } 41430215816SMarri Devender Rao 4157e860f15SJohn Edward Broadbent // Only allow one CSR matcher at a time so setting retry 4167e860f15SJohn Edward Broadbent // time-out and timer expiry to 10 seconds for now. 4172c70f800SEd Tanous static const int timeOut = 10; 41830215816SMarri Devender Rao if (csrMatcher) 41930215816SMarri Devender Rao { 4207e860f15SJohn Edward Broadbent messages::serviceTemporarilyUnavailable( 4217e860f15SJohn Edward Broadbent asyncResp->res, std::to_string(timeOut)); 42230215816SMarri Devender Rao return; 42330215816SMarri Devender Rao } 42430215816SMarri Devender Rao 42530215816SMarri Devender Rao // Make this static so it survives outside this method 42630215816SMarri Devender Rao static boost::asio::steady_timer timeout(*req.ioService); 4272c70f800SEd Tanous timeout.expires_after(std::chrono::seconds(timeOut)); 4280fda0f12SGeorge Liu timeout.async_wait( 4290fda0f12SGeorge Liu [asyncResp](const boost::system::error_code& ec) { 43030215816SMarri Devender Rao csrMatcher = nullptr; 43130215816SMarri Devender Rao if (ec) 43230215816SMarri Devender Rao { 4337e860f15SJohn Edward Broadbent // operation_aborted is expected if timer is canceled 4347e860f15SJohn Edward Broadbent // before completion. 43530215816SMarri Devender Rao if (ec != boost::asio::error::operation_aborted) 43630215816SMarri Devender Rao { 43730215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Async_wait failed " << ec; 43830215816SMarri Devender Rao } 43930215816SMarri Devender Rao return; 44030215816SMarri Devender Rao } 44130215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; 44230215816SMarri Devender Rao messages::internalError(asyncResp->res); 44330215816SMarri Devender Rao }); 44430215816SMarri Devender Rao 44530215816SMarri Devender Rao // create a matcher to wait on CSR object 44630215816SMarri Devender Rao BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; 4470fda0f12SGeorge Liu std::string match("type='signal'," 44830215816SMarri Devender Rao "interface='org.freedesktop.DBus.ObjectManager'," 44930215816SMarri Devender Rao "path='" + 45030215816SMarri Devender Rao objectPath + 45130215816SMarri Devender Rao "'," 45230215816SMarri Devender Rao "member='InterfacesAdded'"); 45330215816SMarri Devender Rao csrMatcher = std::make_unique<sdbusplus::bus::match::match>( 45430215816SMarri Devender Rao *crow::connections::systemBus, match, 45530215816SMarri Devender Rao [asyncResp, service, objectPath, 45630215816SMarri Devender Rao certURI](sdbusplus::message::message& m) { 457271584abSEd Tanous timeout.cancel(); 45830215816SMarri Devender Rao if (m.is_method_error()) 45930215816SMarri Devender Rao { 46030215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Dbus method error!!!"; 46130215816SMarri Devender Rao messages::internalError(asyncResp->res); 46230215816SMarri Devender Rao return; 46330215816SMarri Devender Rao } 464b9d36b47SEd Tanous 465b9d36b47SEd Tanous dbus::utility::DBusInteracesMap interfacesProperties; 466b9d36b47SEd Tanous 46730215816SMarri Devender Rao sdbusplus::message::object_path csrObjectPath; 46830215816SMarri Devender Rao m.read(csrObjectPath, interfacesProperties); 4690fda0f12SGeorge Liu BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; 47030215816SMarri Devender Rao for (auto& interface : interfacesProperties) 47130215816SMarri Devender Rao { 4720fda0f12SGeorge Liu if (interface.first == "xyz.openbmc_project.Certs.CSR") 47330215816SMarri Devender Rao { 47430215816SMarri Devender Rao getCSR(asyncResp, certURI, service, objectPath, 47530215816SMarri Devender Rao csrObjectPath.str); 47630215816SMarri Devender Rao break; 47730215816SMarri Devender Rao } 47830215816SMarri Devender Rao } 47930215816SMarri Devender Rao }); 48030215816SMarri Devender Rao crow::connections::systemBus->async_method_call( 481914e2d5dSEd Tanous [asyncResp](const boost::system::error_code ec, 482cb13a392SEd Tanous const std::string&) { 48330215816SMarri Devender Rao if (ec) 48430215816SMarri Devender Rao { 4857e860f15SJohn Edward Broadbent BMCWEB_LOG_ERROR << "DBUS response error: " 4867e860f15SJohn Edward Broadbent << ec.message(); 48730215816SMarri Devender Rao messages::internalError(asyncResp->res); 48830215816SMarri Devender Rao return; 48930215816SMarri Devender Rao } 49030215816SMarri Devender Rao }, 49130215816SMarri Devender Rao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 4927e860f15SJohn Edward Broadbent "GenerateCSR", *optAlternativeNames, *optChallengePassword, 4937e860f15SJohn Edward Broadbent city, commonName, *optContactPerson, country, *optEmail, 4940fda0f12SGeorge Liu *optGivenName, *optInitials, *optKeyBitLength, *optKeyCurveId, 4950fda0f12SGeorge Liu *optKeyPairAlgorithm, *optKeyUsage, organization, 4960fda0f12SGeorge Liu organizationalUnit, state, *optSurname, *optUnstructuredName); 4977e860f15SJohn Edward Broadbent }); 4987e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionGenerateCSR 49930215816SMarri Devender Rao 5005968caeeSMarri Devender Rao /** 5014e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 5025968caeeSMarri Devender Rao * 5035968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 5045968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 5055968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 5065968caeeSMarri Devender Rao * @return None 5075968caeeSMarri Devender Rao */ 5085968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out, 5095968caeeSMarri Devender Rao const std::string_view value) 5105968caeeSMarri Devender Rao { 5115968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 5125968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 5135968caeeSMarri Devender Rao while (i != value.end()) 5145968caeeSMarri Devender Rao { 5155968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 5165968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 5175968caeeSMarri Devender Rao { 51817a897dfSManojkiran Eda ++i; 5195968caeeSMarri Devender Rao } 5205968caeeSMarri Devender Rao if (i == value.end()) 5215968caeeSMarri Devender Rao { 5225968caeeSMarri Devender Rao break; 5235968caeeSMarri Devender Rao } 524271584abSEd Tanous const std::string_view key(tokenBegin, 525271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 52617a897dfSManojkiran Eda ++i; 5275968caeeSMarri Devender Rao tokenBegin = i; 5285968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 5295968caeeSMarri Devender Rao { 53017a897dfSManojkiran Eda ++i; 5315968caeeSMarri Devender Rao } 532271584abSEd Tanous const std::string_view val(tokenBegin, 533271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 5345968caeeSMarri Devender Rao if (key == "L") 5355968caeeSMarri Devender Rao { 5365968caeeSMarri Devender Rao out["City"] = val; 5375968caeeSMarri Devender Rao } 5385968caeeSMarri Devender Rao else if (key == "CN") 5395968caeeSMarri Devender Rao { 5405968caeeSMarri Devender Rao out["CommonName"] = val; 5415968caeeSMarri Devender Rao } 5425968caeeSMarri Devender Rao else if (key == "C") 5435968caeeSMarri Devender Rao { 5445968caeeSMarri Devender Rao out["Country"] = val; 5455968caeeSMarri Devender Rao } 5465968caeeSMarri Devender Rao else if (key == "O") 5475968caeeSMarri Devender Rao { 5485968caeeSMarri Devender Rao out["Organization"] = val; 5495968caeeSMarri Devender Rao } 5505968caeeSMarri Devender Rao else if (key == "OU") 5515968caeeSMarri Devender Rao { 5525968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 5535968caeeSMarri Devender Rao } 5545968caeeSMarri Devender Rao else if (key == "ST") 5555968caeeSMarri Devender Rao { 5565968caeeSMarri Devender Rao out["State"] = val; 5575968caeeSMarri Devender Rao } 5585968caeeSMarri Devender Rao // skip comma character 5595968caeeSMarri Devender Rao if (i != value.end()) 5605968caeeSMarri Devender Rao { 56117a897dfSManojkiran Eda ++i; 5625968caeeSMarri Devender Rao } 5635968caeeSMarri Devender Rao } 5645968caeeSMarri Devender Rao } 5655968caeeSMarri Devender Rao 5665968caeeSMarri Devender Rao /** 5675968caeeSMarri Devender Rao * @brief Retrieve the certificates properties and append to the response 5685968caeeSMarri Devender Rao * message 5695968caeeSMarri Devender Rao * 5705968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 5715968caeeSMarri Devender Rao * @param[in] objectPath Path of the D-Bus service object 5725968caeeSMarri Devender Rao * @param[in] certId Id of the certificate 5735968caeeSMarri Devender Rao * @param[in] certURL URL of the certificate object 5745968caeeSMarri Devender Rao * @param[in] name name of the certificate 5755968caeeSMarri Devender Rao * @return None 5765968caeeSMarri Devender Rao */ 5775968caeeSMarri Devender Rao static void getCertificateProperties( 5788d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5798d1b46d7Szhanghch05 const std::string& objectPath, const std::string& service, long certId, 5808d1b46d7Szhanghch05 const std::string& certURL, const std::string& name) 5815968caeeSMarri Devender Rao { 5825968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath 5835968caeeSMarri Devender Rao << " certId=" << certId << " certURl=" << certURL; 5845968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 585b9d36b47SEd Tanous [asyncResp, certURL, certId, 586b9d36b47SEd Tanous name](const boost::system::error_code ec, 587b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& properties) { 5885968caeeSMarri Devender Rao if (ec) 5895968caeeSMarri Devender Rao { 5905968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 5918aae75adSMarri Devender Rao messages::resourceNotFound(asyncResp->res, name, 5928aae75adSMarri Devender Rao std::to_string(certId)); 5935968caeeSMarri Devender Rao return; 5945968caeeSMarri Devender Rao } 5955968caeeSMarri Devender Rao asyncResp->res.jsonValue = { 5965968caeeSMarri Devender Rao {"@odata.id", certURL}, 5975968caeeSMarri Devender Rao {"@odata.type", "#Certificate.v1_0_0.Certificate"}, 5985968caeeSMarri Devender Rao {"Id", std::to_string(certId)}, 5995968caeeSMarri Devender Rao {"Name", name}, 6005968caeeSMarri Devender Rao {"Description", name}}; 6015968caeeSMarri Devender Rao for (const auto& property : properties) 6025968caeeSMarri Devender Rao { 6035968caeeSMarri Devender Rao if (property.first == "CertificateString") 6045968caeeSMarri Devender Rao { 6055968caeeSMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = ""; 6065968caeeSMarri Devender Rao const std::string* value = 6075968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 608e662eae8SEd Tanous if (value != nullptr) 6095968caeeSMarri Devender Rao { 61037cce918SMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = *value; 6115968caeeSMarri Devender Rao } 6125968caeeSMarri Devender Rao } 6135968caeeSMarri Devender Rao else if (property.first == "KeyUsage") 6145968caeeSMarri Devender Rao { 6155968caeeSMarri Devender Rao nlohmann::json& keyUsage = 6165968caeeSMarri Devender Rao asyncResp->res.jsonValue["KeyUsage"]; 6175968caeeSMarri Devender Rao keyUsage = nlohmann::json::array(); 6185968caeeSMarri Devender Rao const std::vector<std::string>* value = 61937cce918SMarri Devender Rao std::get_if<std::vector<std::string>>(&property.second); 620e662eae8SEd Tanous if (value != nullptr) 6215968caeeSMarri Devender Rao { 6225968caeeSMarri Devender Rao for (const std::string& usage : *value) 6235968caeeSMarri Devender Rao { 6245968caeeSMarri Devender Rao keyUsage.push_back(usage); 6255968caeeSMarri Devender Rao } 6265968caeeSMarri Devender Rao } 6275968caeeSMarri Devender Rao } 6285968caeeSMarri Devender Rao else if (property.first == "Issuer") 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( 6355968caeeSMarri Devender Rao asyncResp->res.jsonValue["Issuer"], *value); 6365968caeeSMarri Devender Rao } 6375968caeeSMarri Devender Rao } 6385968caeeSMarri Devender Rao else if (property.first == "Subject") 6395968caeeSMarri Devender Rao { 6405968caeeSMarri Devender Rao const std::string* value = 6415968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 642e662eae8SEd Tanous if (value != nullptr) 6435968caeeSMarri Devender Rao { 6445968caeeSMarri Devender Rao updateCertIssuerOrSubject( 64537cce918SMarri Devender Rao asyncResp->res.jsonValue["Subject"], *value); 6465968caeeSMarri Devender Rao } 6475968caeeSMarri Devender Rao } 6485968caeeSMarri Devender Rao else if (property.first == "ValidNotAfter") 6495968caeeSMarri Devender Rao { 6505968caeeSMarri Devender Rao const uint64_t* value = 6515968caeeSMarri Devender Rao std::get_if<uint64_t>(&property.second); 652e662eae8SEd Tanous if (value != nullptr) 6535968caeeSMarri Devender Rao { 6545968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotAfter"] = 6551d8782e7SNan Zhou crow::utility::getDateTimeUint(*value); 6565968caeeSMarri Devender Rao } 6575968caeeSMarri Devender Rao } 6585968caeeSMarri Devender Rao else if (property.first == "ValidNotBefore") 6595968caeeSMarri Devender Rao { 6605968caeeSMarri Devender Rao const uint64_t* value = 6615968caeeSMarri Devender Rao std::get_if<uint64_t>(&property.second); 662e662eae8SEd Tanous if (value != nullptr) 6635968caeeSMarri Devender Rao { 6645968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotBefore"] = 6651d8782e7SNan Zhou crow::utility::getDateTimeUint(*value); 6665968caeeSMarri Devender Rao } 6675968caeeSMarri Devender Rao } 6685968caeeSMarri Devender Rao } 6695968caeeSMarri Devender Rao asyncResp->res.addHeader("Location", certURL); 6705968caeeSMarri Devender Rao }, 6715968caeeSMarri Devender Rao service, objectPath, certs::dbusPropIntf, "GetAll", 6725968caeeSMarri Devender Rao certs::certPropIntf); 6735968caeeSMarri Devender Rao } 6745968caeeSMarri Devender Rao 6755968caeeSMarri Devender Rao /** 6765968caeeSMarri Devender Rao * Action to replace an existing certificate 6775968caeeSMarri Devender Rao */ 6787e860f15SJohn Edward Broadbent inline void requestRoutesCertificateActionsReplaceCertificate(App& app) 6795968caeeSMarri Devender Rao { 6800fda0f12SGeorge Liu BMCWEB_ROUTE( 6810fda0f12SGeorge Liu app, 6820fda0f12SGeorge Liu "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 683ed398213SEd Tanous .privileges(redfish::privileges::postCertificateService) 6847e860f15SJohn Edward Broadbent .methods( 6857e860f15SJohn Edward Broadbent boost::beast::http::verb:: 68645ca1b86SEd Tanous post)([&app]( 68745ca1b86SEd Tanous const crow::Request& req, 6887e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 68945ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 69045ca1b86SEd Tanous { 69145ca1b86SEd Tanous return; 69245ca1b86SEd Tanous } 6935968caeeSMarri Devender Rao std::string certificate; 6945968caeeSMarri Devender Rao nlohmann::json certificateUri; 6955968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 6968d1b46d7Szhanghch05 69715ed6780SWilly Tu if (!json_util::readJsonAction(req, asyncResp->res, 69815ed6780SWilly Tu "CertificateString", certificate, 69915ed6780SWilly Tu "CertificateUri", certificateUri, 70015ed6780SWilly Tu "CertificateType", certificateType)) 7015968caeeSMarri Devender Rao { 7025968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Required parameters are missing"; 7035968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 7045968caeeSMarri Devender Rao return; 7055968caeeSMarri Devender Rao } 7065968caeeSMarri Devender Rao 7075968caeeSMarri Devender Rao if (!certificateType) 7085968caeeSMarri Devender Rao { 7095968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 7105968caeeSMarri Devender Rao return; 7115968caeeSMarri Devender Rao } 7125968caeeSMarri Devender Rao if (certificateType != "PEM") 7135968caeeSMarri Devender Rao { 7145968caeeSMarri Devender Rao messages::actionParameterNotSupported( 7155968caeeSMarri Devender Rao asyncResp->res, "CertificateType", "ReplaceCertificate"); 7165968caeeSMarri Devender Rao return; 7175968caeeSMarri Devender Rao } 7185968caeeSMarri Devender Rao 7195968caeeSMarri Devender Rao std::string certURI; 7205968caeeSMarri Devender Rao if (!redfish::json_util::readJson(certificateUri, asyncResp->res, 7215968caeeSMarri Devender Rao "@odata.id", certURI)) 7225968caeeSMarri Devender Rao { 7235968caeeSMarri Devender Rao messages::actionParameterMissing( 7245968caeeSMarri Devender Rao asyncResp->res, "ReplaceCertificate", "CertificateUri"); 7255968caeeSMarri Devender Rao return; 7265968caeeSMarri Devender Rao } 7275968caeeSMarri Devender Rao 7285968caeeSMarri Devender Rao BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI; 7295968caeeSMarri Devender Rao long id = getIDFromURL(certURI); 7305968caeeSMarri Devender Rao if (id < 0) 7315968caeeSMarri Devender Rao { 7327e860f15SJohn Edward Broadbent messages::actionParameterValueFormatError( 7337e860f15SJohn Edward Broadbent asyncResp->res, certURI, "CertificateUri", 7345968caeeSMarri Devender Rao "ReplaceCertificate"); 7355968caeeSMarri Devender Rao return; 7365968caeeSMarri Devender Rao } 7375968caeeSMarri Devender Rao std::string objectPath; 7385968caeeSMarri Devender Rao std::string name; 73937cce918SMarri Devender Rao std::string service; 7400fda0f12SGeorge Liu if (boost::starts_with( 7410fda0f12SGeorge Liu certURI, 7420fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")) 7435968caeeSMarri Devender Rao { 7447e860f15SJohn Edward Broadbent objectPath = std::string(certs::httpsObjectPath) + "/" + 7457e860f15SJohn Edward Broadbent std::to_string(id); 7465968caeeSMarri Devender Rao name = "HTTPS certificate"; 74737cce918SMarri Devender Rao service = certs::httpsServiceName; 74837cce918SMarri Devender Rao } 74937cce918SMarri Devender Rao else if (boost::starts_with( 7507e860f15SJohn Edward Broadbent certURI, 7517e860f15SJohn Edward Broadbent "/redfish/v1/AccountService/LDAP/Certificates/")) 75237cce918SMarri Devender Rao { 7537e860f15SJohn Edward Broadbent objectPath = std::string(certs::ldapObjectPath) + "/" + 7547e860f15SJohn Edward Broadbent std::to_string(id); 75537cce918SMarri Devender Rao name = "LDAP certificate"; 75637cce918SMarri Devender Rao service = certs::ldapServiceName; 7575968caeeSMarri Devender Rao } 758cfcd5f6bSMarri Devender Rao else if (boost::starts_with( 759cfcd5f6bSMarri Devender Rao certURI, 760cfcd5f6bSMarri Devender Rao "/redfish/v1/Managers/bmc/Truststore/Certificates/")) 761cfcd5f6bSMarri Devender Rao { 762cfcd5f6bSMarri Devender Rao objectPath = std::string(certs::authorityObjectPath) + "/" + 763cfcd5f6bSMarri Devender Rao std::to_string(id); 764cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 765cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 766cfcd5f6bSMarri Devender Rao } 7675968caeeSMarri Devender Rao else 7685968caeeSMarri Devender Rao { 7695968caeeSMarri Devender Rao messages::actionParameterNotSupported( 7705968caeeSMarri Devender Rao asyncResp->res, "CertificateUri", "ReplaceCertificate"); 7715968caeeSMarri Devender Rao return; 7725968caeeSMarri Devender Rao } 7735968caeeSMarri Devender Rao 7745968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 7755968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 7765968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 77737cce918SMarri Devender Rao [asyncResp, certFile, objectPath, service, certURI, id, 7785968caeeSMarri Devender Rao name](const boost::system::error_code ec) { 7795968caeeSMarri Devender Rao if (ec) 7805968caeeSMarri Devender Rao { 7815968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 78290d2d1e8SJiaqing Zhao if (ec.value() == 78390d2d1e8SJiaqing Zhao boost::system::linux_error::bad_request_descriptor) 78490d2d1e8SJiaqing Zhao { 7858aae75adSMarri Devender Rao messages::resourceNotFound(asyncResp->res, name, 7868aae75adSMarri Devender Rao std::to_string(id)); 7875968caeeSMarri Devender Rao return; 7885968caeeSMarri Devender Rao } 78990d2d1e8SJiaqing Zhao messages::internalError(asyncResp->res); 79090d2d1e8SJiaqing Zhao return; 79190d2d1e8SJiaqing Zhao } 79237cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, service, id, 7935968caeeSMarri Devender Rao certURI, name); 7945968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 7955968caeeSMarri Devender Rao << certFile->getCertFilePath(); 7965968caeeSMarri Devender Rao }, 7975968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 7985968caeeSMarri Devender Rao certFile->getCertFilePath()); 7997e860f15SJohn Edward Broadbent }); 8007e860f15SJohn Edward Broadbent } // requestRoutesCertificateActionsReplaceCertificate 8015968caeeSMarri Devender Rao 8025968caeeSMarri Devender Rao /** 8035968caeeSMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 8045968caeeSMarri Devender Rao * of a component, account or service. 8055968caeeSMarri Devender Rao */ 8065968caeeSMarri Devender Rao 8077e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificate(App& app) 8085968caeeSMarri Devender Rao { 8097e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 8107e860f15SJohn Edward Broadbent app, 8117e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/") 812ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 8137e860f15SJohn Edward Broadbent .methods( 8147e860f15SJohn Edward Broadbent boost::beast::http::verb:: 81545ca1b86SEd Tanous get)([&app](const crow::Request& req, 8167e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8177e860f15SJohn Edward Broadbent const std::string& param) -> void { 81845ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 81945ca1b86SEd Tanous { 82045ca1b86SEd Tanous return; 82145ca1b86SEd Tanous } 8227e860f15SJohn Edward Broadbent if (param.empty()) 8235968caeeSMarri Devender Rao { 8245968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 8255968caeeSMarri Devender Rao return; 8265968caeeSMarri Devender Rao } 8275968caeeSMarri Devender Rao long id = getIDFromURL(req.url); 8285968caeeSMarri Devender Rao 8297e860f15SJohn Edward Broadbent BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID=" 8307e860f15SJohn Edward Broadbent << std::to_string(id); 8315968caeeSMarri Devender Rao std::string certURL = 8325968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" + 8335968caeeSMarri Devender Rao std::to_string(id); 8345968caeeSMarri Devender Rao std::string objectPath = certs::httpsObjectPath; 8355968caeeSMarri Devender Rao objectPath += "/"; 8365968caeeSMarri Devender Rao objectPath += std::to_string(id); 8377e860f15SJohn Edward Broadbent getCertificateProperties(asyncResp, objectPath, 8387e860f15SJohn Edward Broadbent certs::httpsServiceName, id, certURL, 8397e860f15SJohn Edward Broadbent "HTTPS Certificate"); 8407e860f15SJohn Edward Broadbent }); 8415968caeeSMarri Devender Rao } 8425968caeeSMarri Devender Rao 8435968caeeSMarri Devender Rao /** 8445968caeeSMarri Devender Rao * Collection of HTTPS certificates 8455968caeeSMarri Devender Rao */ 8467e860f15SJohn Edward Broadbent inline void requestRoutesHTTPSCertificateCollection(App& app) 8475968caeeSMarri Devender Rao { 8487e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 8495968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 850ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 85145ca1b86SEd Tanous .methods(boost::beast::http::verb::get)([&app](const crow::Request& req, 85245ca1b86SEd Tanous const std::shared_ptr< 85345ca1b86SEd Tanous bmcweb::AsyncResp>& 85445ca1b86SEd Tanous asyncResp) { 85545ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 85645ca1b86SEd Tanous { 85745ca1b86SEd Tanous return; 85845ca1b86SEd Tanous } 8598d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 8605968caeeSMarri Devender Rao {"@odata.id", 8615968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"}, 8625968caeeSMarri Devender Rao {"@odata.type", "#CertificateCollection.CertificateCollection"}, 8635968caeeSMarri Devender Rao {"Name", "HTTPS Certificates Collection"}, 8645968caeeSMarri Devender Rao {"Description", "A Collection of HTTPS certificate instances"}}; 8658d1b46d7Szhanghch05 8665968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 8675968caeeSMarri Devender Rao [asyncResp](const boost::system::error_code ec, 868711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 8695968caeeSMarri Devender Rao if (ec) 8705968caeeSMarri Devender Rao { 8715968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 8725968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 8735968caeeSMarri Devender Rao return; 8745968caeeSMarri Devender Rao } 8757e860f15SJohn Edward Broadbent nlohmann::json& members = 8767e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 8775968caeeSMarri Devender Rao members = nlohmann::json::array(); 8785968caeeSMarri Devender Rao for (const auto& cert : certs) 8795968caeeSMarri Devender Rao { 8805968caeeSMarri Devender Rao long id = getIDFromURL(cert.first.str); 88137cce918SMarri Devender Rao if (id >= 0) 8825968caeeSMarri Devender Rao { 8835968caeeSMarri Devender Rao members.push_back( 8845968caeeSMarri Devender Rao {{"@odata.id", 8850fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" + 8865968caeeSMarri Devender Rao std::to_string(id)}}); 8875968caeeSMarri Devender Rao } 8885968caeeSMarri Devender Rao } 8895968caeeSMarri Devender Rao asyncResp->res.jsonValue["Members@odata.count"] = 8905968caeeSMarri Devender Rao members.size(); 8915968caeeSMarri Devender Rao }, 89237cce918SMarri Devender Rao certs::httpsServiceName, certs::httpsObjectPath, 89337cce918SMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 8947e860f15SJohn Edward Broadbent }); 8955968caeeSMarri Devender Rao 8967e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 8977e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 898ed398213SEd Tanous .privileges(redfish::privileges::postCertificateCollection) 8990fda0f12SGeorge Liu .methods( 9000fda0f12SGeorge Liu boost::beast::http::verb:: 90145ca1b86SEd Tanous post)([&app]( 90245ca1b86SEd Tanous const crow::Request& req, 9037e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 90445ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 90545ca1b86SEd Tanous { 90645ca1b86SEd Tanous return; 90745ca1b86SEd Tanous } 9085968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; 9098d1b46d7Szhanghch05 9100fda0f12SGeorge Liu asyncResp->res.jsonValue = {{"Name", "HTTPS Certificate"}, 9115968caeeSMarri Devender Rao {"Description", "HTTPS Certificate"}}; 9125968caeeSMarri Devender Rao 9137e860f15SJohn Edward Broadbent std::string certFileBody = 9147e860f15SJohn Edward Broadbent getCertificateFromReqBody(asyncResp, req); 91558eb238fSKowalski, Kamil 91658eb238fSKowalski, Kamil if (certFileBody.empty()) 91758eb238fSKowalski, Kamil { 9180fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 919a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 92058eb238fSKowalski, Kamil return; 92158eb238fSKowalski, Kamil } 92258eb238fSKowalski, Kamil 9235968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 92458eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 9255968caeeSMarri Devender Rao 9265968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 927656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 928656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 9295968caeeSMarri Devender Rao if (ec) 9305968caeeSMarri Devender Rao { 9315968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 9325968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 9335968caeeSMarri Devender Rao return; 9345968caeeSMarri Devender Rao } 935656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 936656ec7e3SZbigniew Kurzynski if (certId < 0) 937656ec7e3SZbigniew Kurzynski { 938656ec7e3SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid objectPath value" 939656ec7e3SZbigniew Kurzynski << objectPath; 940656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 941656ec7e3SZbigniew Kurzynski return; 942656ec7e3SZbigniew Kurzynski } 9435968caeeSMarri Devender Rao std::string certURL = 9440fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" + 9455968caeeSMarri Devender Rao std::to_string(certId); 9460fda0f12SGeorge Liu getCertificateProperties(asyncResp, objectPath, 9470fda0f12SGeorge Liu certs::httpsServiceName, certId, 9480fda0f12SGeorge Liu certURL, "HTTPS Certificate"); 9495968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 9505968caeeSMarri Devender Rao << certFile->getCertFilePath(); 9515968caeeSMarri Devender Rao }, 95237cce918SMarri Devender Rao certs::httpsServiceName, certs::httpsObjectPath, 9530fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 9547e860f15SJohn Edward Broadbent }); 9557e860f15SJohn Edward Broadbent } // requestRoutesHTTPSCertificateCollection 9565968caeeSMarri Devender Rao 9575968caeeSMarri Devender Rao /** 95837cce918SMarri Devender Rao * @brief Retrieve the certificates installed list and append to the 95937cce918SMarri Devender Rao * response 96037cce918SMarri Devender Rao * 96137cce918SMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 96237cce918SMarri Devender Rao * @param[in] certURL Path of the certificate object 96337cce918SMarri Devender Rao * @param[in] path Path of the D-Bus service object 96437cce918SMarri Devender Rao * @return None 96537cce918SMarri Devender Rao */ 9664f48d5f6SEd Tanous inline void 9674f48d5f6SEd Tanous getCertificateLocations(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9688d1b46d7Szhanghch05 const std::string& certURL, const std::string& path, 96937cce918SMarri Devender Rao const std::string& service) 97037cce918SMarri Devender Rao { 97137cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL 97237cce918SMarri Devender Rao << " Path=" << path << " service= " << service; 97337cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 97437cce918SMarri Devender Rao [asyncResp, certURL](const boost::system::error_code ec, 975711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 97637cce918SMarri Devender Rao if (ec) 97737cce918SMarri Devender Rao { 9789c8e039eSJonathan Doman BMCWEB_LOG_WARNING 9799c8e039eSJonathan Doman << "Certificate collection query failed: " << ec 9809c8e039eSJonathan Doman << ", skipping " << certURL; 98137cce918SMarri Devender Rao return; 98237cce918SMarri Devender Rao } 98337cce918SMarri Devender Rao nlohmann::json& links = 98437cce918SMarri Devender Rao asyncResp->res.jsonValue["Links"]["Certificates"]; 9859eb808c1SEd Tanous for (const auto& cert : certs) 98637cce918SMarri Devender Rao { 98737cce918SMarri Devender Rao long id = getIDFromURL(cert.first.str); 98837cce918SMarri Devender Rao if (id >= 0) 98937cce918SMarri Devender Rao { 99037cce918SMarri Devender Rao links.push_back( 99137cce918SMarri Devender Rao {{"@odata.id", certURL + std::to_string(id)}}); 99237cce918SMarri Devender Rao } 99337cce918SMarri Devender Rao } 99437cce918SMarri Devender Rao asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] = 99537cce918SMarri Devender Rao links.size(); 99637cce918SMarri Devender Rao }, 99737cce918SMarri Devender Rao service, path, certs::dbusObjManagerIntf, "GetManagedObjects"); 9985968caeeSMarri Devender Rao } 9997e860f15SJohn Edward Broadbent 10007e860f15SJohn Edward Broadbent /** 10017e860f15SJohn Edward Broadbent * The certificate location schema defines a resource that an administrator 10027e860f15SJohn Edward Broadbent * can use in order to locate all certificates installed on a given service. 10037e860f15SJohn Edward Broadbent */ 10047e860f15SJohn Edward Broadbent inline void requestRoutesCertificateLocations(App& app) 10057e860f15SJohn Edward Broadbent { 10067e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 1007ed398213SEd Tanous .privileges(redfish::privileges::getCertificateLocations) 100845ca1b86SEd Tanous .methods(boost::beast::http::verb::get)([&app](const crow::Request& req, 100945ca1b86SEd Tanous const std::shared_ptr< 101045ca1b86SEd Tanous bmcweb::AsyncResp>& 101145ca1b86SEd Tanous asyncResp) { 101245ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 101345ca1b86SEd Tanous { 101445ca1b86SEd Tanous return; 101545ca1b86SEd Tanous } 10167e860f15SJohn Edward Broadbent asyncResp->res.jsonValue = { 10177e860f15SJohn Edward Broadbent {"@odata.id", 10187e860f15SJohn Edward Broadbent "/redfish/v1/CertificateService/CertificateLocations"}, 10197e860f15SJohn Edward Broadbent {"@odata.type", 10207e860f15SJohn Edward Broadbent "#CertificateLocations.v1_0_0.CertificateLocations"}, 10217e860f15SJohn Edward Broadbent {"Name", "Certificate Locations"}, 10227e860f15SJohn Edward Broadbent {"Id", "CertificateLocations"}, 10237e860f15SJohn Edward Broadbent {"Description", 10247e860f15SJohn Edward Broadbent "Defines a resource that an administrator can use in order to " 10257e860f15SJohn Edward Broadbent "locate all certificates installed on a given service"}}; 10267e860f15SJohn Edward Broadbent 10277e860f15SJohn Edward Broadbent nlohmann::json& links = 10287e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Links"]["Certificates"]; 10297e860f15SJohn Edward Broadbent links = nlohmann::json::array(); 10307e860f15SJohn Edward Broadbent getCertificateLocations( 10317e860f15SJohn Edward Broadbent asyncResp, 10327e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/", 10337e860f15SJohn Edward Broadbent certs::httpsObjectPath, certs::httpsServiceName); 10347e860f15SJohn Edward Broadbent getCertificateLocations( 10357e860f15SJohn Edward Broadbent asyncResp, "/redfish/v1/AccountService/LDAP/Certificates/", 10367e860f15SJohn Edward Broadbent certs::ldapObjectPath, certs::ldapServiceName); 10377e860f15SJohn Edward Broadbent getCertificateLocations( 10387e860f15SJohn Edward Broadbent asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/", 10397e860f15SJohn Edward Broadbent certs::authorityObjectPath, certs::authorityServiceName); 10407e860f15SJohn Edward Broadbent }); 10417e860f15SJohn Edward Broadbent } 10427e860f15SJohn Edward Broadbent // requestRoutesCertificateLocations 104337cce918SMarri Devender Rao 104437cce918SMarri Devender Rao /** 104537cce918SMarri Devender Rao * Collection of LDAP certificates 104637cce918SMarri Devender Rao */ 10477e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificateCollection(App& app) 104837cce918SMarri Devender Rao { 10497e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1050ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 105145ca1b86SEd Tanous .methods(boost::beast::http::verb::get)([&app](const crow::Request& req, 105245ca1b86SEd Tanous const std::shared_ptr< 105345ca1b86SEd Tanous bmcweb::AsyncResp>& 105445ca1b86SEd Tanous asyncResp) { 105545ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 105645ca1b86SEd Tanous { 105745ca1b86SEd Tanous return; 105845ca1b86SEd Tanous } 10598d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 10600fda0f12SGeorge Liu {"@odata.id", "/redfish/v1/AccountService/LDAP/Certificates"}, 10610fda0f12SGeorge Liu {"@odata.type", "#CertificateCollection.CertificateCollection"}, 106237cce918SMarri Devender Rao {"Name", "LDAP Certificates Collection"}, 10630fda0f12SGeorge Liu {"Description", "A Collection of LDAP certificate instances"}}; 10648d1b46d7Szhanghch05 106537cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 106637cce918SMarri Devender Rao [asyncResp](const boost::system::error_code ec, 1067711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 10687e860f15SJohn Edward Broadbent nlohmann::json& members = 10697e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 10709c8e039eSJonathan Doman nlohmann::json& count = 10719c8e039eSJonathan Doman asyncResp->res.jsonValue["Members@odata.count"]; 10729c8e039eSJonathan Doman members = nlohmann::json::array(); 10739c8e039eSJonathan Doman count = 0; 107437cce918SMarri Devender Rao if (ec) 107537cce918SMarri Devender Rao { 10760fda0f12SGeorge Liu BMCWEB_LOG_WARNING << "LDAP certificate query failed: " 10770fda0f12SGeorge Liu << ec; 107837cce918SMarri Devender Rao return; 107937cce918SMarri Devender Rao } 108037cce918SMarri Devender Rao for (const auto& cert : certs) 108137cce918SMarri Devender Rao { 108237cce918SMarri Devender Rao long id = getIDFromURL(cert.first.str); 108337cce918SMarri Devender Rao if (id >= 0) 108437cce918SMarri Devender Rao { 108537cce918SMarri Devender Rao members.push_back( 10860fda0f12SGeorge Liu {{"@odata.id", 10870fda0f12SGeorge Liu "/redfish/v1/AccountService/LDAP/Certificates/" + 108837cce918SMarri Devender Rao std::to_string(id)}}); 108937cce918SMarri Devender Rao } 109037cce918SMarri Devender Rao } 10919c8e039eSJonathan Doman count = members.size(); 109237cce918SMarri Devender Rao }, 109337cce918SMarri Devender Rao certs::ldapServiceName, certs::ldapObjectPath, 109437cce918SMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 10957e860f15SJohn Edward Broadbent }); 109637cce918SMarri Devender Rao 10977e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1098ed398213SEd Tanous .privileges(redfish::privileges::postCertificateCollection) 10997e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 110045ca1b86SEd Tanous [&app](const crow::Request& req, 11017e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 110245ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 110345ca1b86SEd Tanous { 110445ca1b86SEd Tanous return; 110545ca1b86SEd Tanous } 11067e860f15SJohn Edward Broadbent std::string certFileBody = 11077e860f15SJohn Edward Broadbent getCertificateFromReqBody(asyncResp, req); 110858eb238fSKowalski, Kamil 110958eb238fSKowalski, Kamil if (certFileBody.empty()) 111058eb238fSKowalski, Kamil { 11117e860f15SJohn Edward Broadbent BMCWEB_LOG_ERROR 11127e860f15SJohn Edward Broadbent << "Cannot get certificate from request body."; 1113a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 111458eb238fSKowalski, Kamil return; 111558eb238fSKowalski, Kamil } 111658eb238fSKowalski, Kamil 111758eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 111858eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 111958eb238fSKowalski, Kamil 112037cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 1121656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1122656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 112337cce918SMarri Devender Rao if (ec) 112437cce918SMarri Devender Rao { 112537cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 112637cce918SMarri Devender Rao messages::internalError(asyncResp->res); 112737cce918SMarri Devender Rao return; 112837cce918SMarri Devender Rao } 1129656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 1130656ec7e3SZbigniew Kurzynski if (certId < 0) 1131656ec7e3SZbigniew Kurzynski { 1132656ec7e3SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid objectPath value" 1133656ec7e3SZbigniew Kurzynski << objectPath; 1134656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 1135656ec7e3SZbigniew Kurzynski return; 1136656ec7e3SZbigniew Kurzynski } 113737cce918SMarri Devender Rao std::string certURL = 113837cce918SMarri Devender Rao "/redfish/v1/AccountService/LDAP/Certificates/" + 113937cce918SMarri Devender Rao std::to_string(certId); 114037cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 114137cce918SMarri Devender Rao certs::ldapServiceName, certId, 114237cce918SMarri Devender Rao certURL, "LDAP Certificate"); 114337cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "LDAP certificate install file=" 114437cce918SMarri Devender Rao << certFile->getCertFilePath(); 114537cce918SMarri Devender Rao }, 114637cce918SMarri Devender Rao certs::ldapServiceName, certs::ldapObjectPath, 11477e860f15SJohn Edward Broadbent certs::certInstallIntf, "Install", 11487e860f15SJohn Edward Broadbent certFile->getCertFilePath()); 11497e860f15SJohn Edward Broadbent }); 11507e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificateCollection 115137cce918SMarri Devender Rao 115237cce918SMarri Devender Rao /** 115337cce918SMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 115437cce918SMarri Devender Rao * of a component, account or service. 115537cce918SMarri Devender Rao */ 11567e860f15SJohn Edward Broadbent inline void requestRoutesLDAPCertificate(App& app) 115737cce918SMarri Devender Rao { 11587e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1159ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 11607e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 116145ca1b86SEd Tanous [&app](const crow::Request& req, 11627e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 11637e860f15SJohn Edward Broadbent const std::string&) { 116445ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 116545ca1b86SEd Tanous { 116645ca1b86SEd Tanous return; 116745ca1b86SEd Tanous } 116837cce918SMarri Devender Rao long id = getIDFromURL(req.url); 116937cce918SMarri Devender Rao if (id < 0) 117037cce918SMarri Devender Rao { 117137cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "Invalid url value" << req.url; 117237cce918SMarri Devender Rao messages::internalError(asyncResp->res); 117337cce918SMarri Devender Rao return; 117437cce918SMarri Devender Rao } 11757e860f15SJohn Edward Broadbent BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" 11767e860f15SJohn Edward Broadbent << std::to_string(id); 11777e860f15SJohn Edward Broadbent std::string certURL = 11787e860f15SJohn Edward Broadbent "/redfish/v1/AccountService/LDAP/Certificates/" + 117937cce918SMarri Devender Rao std::to_string(id); 118037cce918SMarri Devender Rao std::string objectPath = certs::ldapObjectPath; 118137cce918SMarri Devender Rao objectPath += "/"; 118237cce918SMarri Devender Rao objectPath += std::to_string(id); 11837e860f15SJohn Edward Broadbent getCertificateProperties(asyncResp, objectPath, 11847e860f15SJohn Edward Broadbent certs::ldapServiceName, id, certURL, 11857e860f15SJohn Edward Broadbent "LDAP Certificate"); 11867e860f15SJohn Edward Broadbent }); 11877e860f15SJohn Edward Broadbent } // requestRoutesLDAPCertificate 1188cfcd5f6bSMarri Devender Rao /** 1189cfcd5f6bSMarri Devender Rao * Collection of TrustStoreCertificate certificates 1190cfcd5f6bSMarri Devender Rao */ 11917e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificateCollection(App& app) 1192cfcd5f6bSMarri Devender Rao { 11937e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1194ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 119545ca1b86SEd Tanous .methods(boost::beast::http::verb::get)([&app](const crow::Request& req, 119645ca1b86SEd Tanous const std::shared_ptr< 119745ca1b86SEd Tanous bmcweb::AsyncResp>& 119845ca1b86SEd Tanous asyncResp) { 119945ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 120045ca1b86SEd Tanous { 120145ca1b86SEd Tanous return; 120245ca1b86SEd Tanous } 12038d1b46d7Szhanghch05 asyncResp->res.jsonValue = { 12047e860f15SJohn Edward Broadbent {"@odata.id", 12057e860f15SJohn Edward Broadbent "/redfish/v1/Managers/bmc/Truststore/Certificates/"}, 12060fda0f12SGeorge Liu {"@odata.type", "#CertificateCollection.CertificateCollection"}, 1207cfcd5f6bSMarri Devender Rao {"Name", "TrustStore Certificates Collection"}, 1208cfcd5f6bSMarri Devender Rao {"Description", 1209cfcd5f6bSMarri Devender Rao "A Collection of TrustStore certificate instances"}}; 12108d1b46d7Szhanghch05 1211cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1212cfcd5f6bSMarri Devender Rao [asyncResp](const boost::system::error_code ec, 1213711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& certs) { 1214cfcd5f6bSMarri Devender Rao if (ec) 1215cfcd5f6bSMarri Devender Rao { 1216cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1217cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1218cfcd5f6bSMarri Devender Rao return; 1219cfcd5f6bSMarri Devender Rao } 12207e860f15SJohn Edward Broadbent nlohmann::json& members = 12217e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Members"]; 1222cfcd5f6bSMarri Devender Rao members = nlohmann::json::array(); 1223cfcd5f6bSMarri Devender Rao for (const auto& cert : certs) 1224cfcd5f6bSMarri Devender Rao { 1225cfcd5f6bSMarri Devender Rao long id = getIDFromURL(cert.first.str); 1226cfcd5f6bSMarri Devender Rao if (id >= 0) 1227cfcd5f6bSMarri Devender Rao { 1228cfcd5f6bSMarri Devender Rao members.push_back( 12290fda0f12SGeorge Liu {{"@odata.id", 12300fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/Truststore/Certificates/" + 1231cfcd5f6bSMarri Devender Rao std::to_string(id)}}); 1232cfcd5f6bSMarri Devender Rao } 1233cfcd5f6bSMarri Devender Rao } 1234cfcd5f6bSMarri Devender Rao asyncResp->res.jsonValue["Members@odata.count"] = 1235cfcd5f6bSMarri Devender Rao members.size(); 1236cfcd5f6bSMarri Devender Rao }, 1237cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 1238cfcd5f6bSMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 12397e860f15SJohn Edward Broadbent }); 1240cfcd5f6bSMarri Devender Rao 12417e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1242ed398213SEd Tanous .privileges(redfish::privileges::postCertificateCollection) 12430fda0f12SGeorge Liu .methods( 12440fda0f12SGeorge Liu boost::beast::http::verb:: 124545ca1b86SEd Tanous post)([&app]( 124645ca1b86SEd Tanous const crow::Request& req, 12477e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 124845ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 124945ca1b86SEd Tanous { 125045ca1b86SEd Tanous return; 125145ca1b86SEd Tanous } 12527e860f15SJohn Edward Broadbent std::string certFileBody = 12537e860f15SJohn Edward Broadbent getCertificateFromReqBody(asyncResp, req); 1254a08752f5SZbigniew Kurzynski 1255a08752f5SZbigniew Kurzynski if (certFileBody.empty()) 1256a08752f5SZbigniew Kurzynski { 12570fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1258a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1259a08752f5SZbigniew Kurzynski return; 1260a08752f5SZbigniew Kurzynski } 1261a08752f5SZbigniew Kurzynski 1262a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1263a08752f5SZbigniew Kurzynski std::make_shared<CertificateFile>(certFileBody); 1264cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1265656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1266656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1267cfcd5f6bSMarri Devender Rao if (ec) 1268cfcd5f6bSMarri Devender Rao { 1269cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1270cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1271cfcd5f6bSMarri Devender Rao return; 1272cfcd5f6bSMarri Devender Rao } 1273656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 1274656ec7e3SZbigniew Kurzynski if (certId < 0) 1275656ec7e3SZbigniew Kurzynski { 1276656ec7e3SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid objectPath value" 1277656ec7e3SZbigniew Kurzynski << objectPath; 1278656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 1279656ec7e3SZbigniew Kurzynski return; 1280656ec7e3SZbigniew Kurzynski } 12810fda0f12SGeorge Liu std::string certURL = 12820fda0f12SGeorge Liu "/redfish/v1/Managers/bmc/Truststore/Certificates/" + 1283cfcd5f6bSMarri Devender Rao std::to_string(certId); 1284656ec7e3SZbigniew Kurzynski 12857e860f15SJohn Edward Broadbent getCertificateProperties( 12867e860f15SJohn Edward Broadbent asyncResp, objectPath, certs::authorityServiceName, 12877e860f15SJohn Edward Broadbent certId, certURL, "TrustStore Certificate"); 12880fda0f12SGeorge Liu BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" 1289cfcd5f6bSMarri Devender Rao << certFile->getCertFilePath(); 1290cfcd5f6bSMarri Devender Rao }, 1291cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 12920fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 12937e860f15SJohn Edward Broadbent }); 12947e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificateCollection 1295cfcd5f6bSMarri Devender Rao 1296cfcd5f6bSMarri Devender Rao /** 1297cfcd5f6bSMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 1298cfcd5f6bSMarri Devender Rao * of a component, account or service. 1299cfcd5f6bSMarri Devender Rao */ 13007e860f15SJohn Edward Broadbent inline void requestRoutesTrustStoreCertificate(App& app) 1301cfcd5f6bSMarri Devender Rao { 13027e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1303ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 13047e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 130545ca1b86SEd Tanous [&app](const crow::Request& req, 13067e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 13077e860f15SJohn Edward Broadbent const std::string&) { 130845ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 130945ca1b86SEd Tanous { 131045ca1b86SEd Tanous return; 131145ca1b86SEd Tanous } 1312cfcd5f6bSMarri Devender Rao long id = getIDFromURL(req.url); 1313cfcd5f6bSMarri Devender Rao if (id < 0) 1314cfcd5f6bSMarri Devender Rao { 1315cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "Invalid url value" << req.url; 1316cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1317cfcd5f6bSMarri Devender Rao return; 1318cfcd5f6bSMarri Devender Rao } 1319cfcd5f6bSMarri Devender Rao BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID=" 1320cfcd5f6bSMarri Devender Rao << std::to_string(id); 1321cfcd5f6bSMarri Devender Rao std::string certURL = 1322cfcd5f6bSMarri Devender Rao "/redfish/v1/Managers/bmc/Truststore/Certificates/" + 1323cfcd5f6bSMarri Devender Rao std::to_string(id); 1324cfcd5f6bSMarri Devender Rao std::string objectPath = certs::authorityObjectPath; 1325cfcd5f6bSMarri Devender Rao objectPath += "/"; 1326cfcd5f6bSMarri Devender Rao objectPath += std::to_string(id); 1327cfcd5f6bSMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 13287e860f15SJohn Edward Broadbent certs::authorityServiceName, id, 13297e860f15SJohn Edward Broadbent certURL, "TrustStore Certificate"); 13307e860f15SJohn Edward Broadbent }); 133107a60299SZbigniew Kurzynski 13327e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1333ed398213SEd Tanous .privileges(redfish::privileges::deleteCertificate) 13347e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 133545ca1b86SEd Tanous [&app](const crow::Request& req, 13367e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 13377e860f15SJohn Edward Broadbent const std::string& param) { 133845ca1b86SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 133945ca1b86SEd Tanous { 134045ca1b86SEd Tanous return; 134145ca1b86SEd Tanous } 13427e860f15SJohn Edward Broadbent if (param.empty()) 134307a60299SZbigniew Kurzynski { 134407a60299SZbigniew Kurzynski messages::internalError(asyncResp->res); 134507a60299SZbigniew Kurzynski return; 134607a60299SZbigniew Kurzynski } 134707a60299SZbigniew Kurzynski 134807a60299SZbigniew Kurzynski long id = getIDFromURL(req.url); 134907a60299SZbigniew Kurzynski if (id < 0) 135007a60299SZbigniew Kurzynski { 135107a60299SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid url value: " << req.url; 13527e860f15SJohn Edward Broadbent messages::resourceNotFound(asyncResp->res, 13537e860f15SJohn Edward Broadbent "TrustStore Certificate", 135407a60299SZbigniew Kurzynski std::string(req.url)); 135507a60299SZbigniew Kurzynski return; 135607a60299SZbigniew Kurzynski } 135707a60299SZbigniew Kurzynski BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID=" 135807a60299SZbigniew Kurzynski << std::to_string(id); 135907a60299SZbigniew Kurzynski std::string certPath = certs::authorityObjectPath; 136007a60299SZbigniew Kurzynski certPath += "/"; 136107a60299SZbigniew Kurzynski certPath += std::to_string(id); 136207a60299SZbigniew Kurzynski 136307a60299SZbigniew Kurzynski crow::connections::systemBus->async_method_call( 136407a60299SZbigniew Kurzynski [asyncResp, id](const boost::system::error_code ec) { 136507a60299SZbigniew Kurzynski if (ec) 136607a60299SZbigniew Kurzynski { 136707a60299SZbigniew Kurzynski messages::resourceNotFound(asyncResp->res, 136807a60299SZbigniew Kurzynski "TrustStore Certificate", 136907a60299SZbigniew Kurzynski std::to_string(id)); 137007a60299SZbigniew Kurzynski return; 137107a60299SZbigniew Kurzynski } 137207a60299SZbigniew Kurzynski BMCWEB_LOG_INFO << "Certificate deleted"; 13737e860f15SJohn Edward Broadbent asyncResp->res.result( 13747e860f15SJohn Edward Broadbent boost::beast::http::status::no_content); 137507a60299SZbigniew Kurzynski }, 137607a60299SZbigniew Kurzynski certs::authorityServiceName, certPath, certs::objDeleteIntf, 137707a60299SZbigniew Kurzynski "Delete"); 13787e860f15SJohn Edward Broadbent }); 13797e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate 13805968caeeSMarri Devender Rao } // namespace redfish 1381