15968caeeSMarri Devender Rao /* 25968caeeSMarri Devender Rao // Copyright (c) 2018 IBM Corporation 35968caeeSMarri Devender Rao // 45968caeeSMarri Devender Rao // Licensed under the Apache License, Version 2.0 (the "License"); 55968caeeSMarri Devender Rao // you may not use this file except in compliance with the License. 65968caeeSMarri Devender Rao // You may obtain a copy of the License at 75968caeeSMarri Devender Rao // 85968caeeSMarri Devender Rao // http://www.apache.org/licenses/LICENSE-2.0 95968caeeSMarri Devender Rao // 105968caeeSMarri Devender Rao // Unless required by applicable law or agreed to in writing, software 115968caeeSMarri Devender Rao // distributed under the License is distributed on an "AS IS" BASIS, 125968caeeSMarri Devender Rao // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135968caeeSMarri Devender Rao // See the License for the specific language governing permissions and 145968caeeSMarri Devender Rao // limitations under the License. 155968caeeSMarri Devender Rao */ 165968caeeSMarri Devender Rao #pragma once 175968caeeSMarri Devender Rao 185968caeeSMarri Devender Rao #include "node.hpp" 195968caeeSMarri Devender Rao 20e6604b11SIwona Klimaszewska #include <boost/convert.hpp> 21e6604b11SIwona Klimaszewska #include <boost/convert/strtol.hpp> 221214b7e7SGunnar Mills 235968caeeSMarri Devender Rao #include <variant> 245968caeeSMarri Devender Rao namespace redfish 255968caeeSMarri Devender Rao { 265968caeeSMarri Devender Rao namespace certs 275968caeeSMarri Devender Rao { 285968caeeSMarri Devender Rao constexpr char const* httpsObjectPath = 295968caeeSMarri Devender Rao "/xyz/openbmc_project/certs/server/https"; 305968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 315968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 3207a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 335968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 345968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties"; 355968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 3637cce918SMarri Devender Rao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 3737cce918SMarri Devender Rao constexpr char const* httpsServiceName = 3837cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Server.Https"; 3937cce918SMarri Devender Rao constexpr char const* ldapServiceName = 4037cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 41cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName = 42cfcd5f6bSMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Authority.Ldap"; 43cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath = 44cfcd5f6bSMarri Devender Rao "/xyz/openbmc_project/certs/authority/ldap"; 455968caeeSMarri Devender Rao } // namespace certs 465968caeeSMarri Devender Rao 475968caeeSMarri Devender Rao /** 485968caeeSMarri Devender Rao * The Certificate schema defines a Certificate Service which represents the 495968caeeSMarri Devender Rao * actions available to manage certificates and links to where certificates 505968caeeSMarri Devender Rao * are installed. 515968caeeSMarri Devender Rao */ 525968caeeSMarri Devender Rao class CertificateService : public Node 535968caeeSMarri Devender Rao { 545968caeeSMarri Devender Rao public: 5552cc112dSEd Tanous CertificateService(App& app) : Node(app, "/redfish/v1/CertificateService/") 565968caeeSMarri Devender Rao { 575968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate 584e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish 595968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF 605968caeeSMarri Devender Rao // publish Privilege details for certificate service 615968caeeSMarri Devender Rao entityPrivileges = { 625968caeeSMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 635968caeeSMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 645968caeeSMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 655968caeeSMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 665968caeeSMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 675968caeeSMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 685968caeeSMarri Devender Rao } 695968caeeSMarri Devender Rao 705968caeeSMarri Devender Rao private: 71cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 72cb13a392SEd Tanous const std::vector<std::string>&) override 735968caeeSMarri Devender Rao { 745968caeeSMarri Devender Rao res.jsonValue = { 755968caeeSMarri Devender Rao {"@odata.type", "#CertificateService.v1_0_0.CertificateService"}, 765968caeeSMarri Devender Rao {"@odata.id", "/redfish/v1/CertificateService"}, 775968caeeSMarri Devender Rao {"Id", "CertificateService"}, 785968caeeSMarri Devender Rao {"Name", "Certificate Service"}, 795968caeeSMarri Devender Rao {"Description", "Actions available to manage certificates"}}; 805968caeeSMarri Devender Rao res.jsonValue["CertificateLocations"] = { 815968caeeSMarri Devender Rao {"@odata.id", 825968caeeSMarri Devender Rao "/redfish/v1/CertificateService/CertificateLocations"}}; 835968caeeSMarri Devender Rao res.jsonValue["Actions"]["#CertificateService.ReplaceCertificate"] = { 845968caeeSMarri Devender Rao {"target", "/redfish/v1/CertificateService/Actions/" 855968caeeSMarri Devender Rao "CertificateService.ReplaceCertificate"}, 865968caeeSMarri Devender Rao {"CertificateType@Redfish.AllowableValues", {"PEM"}}}; 8730215816SMarri Devender Rao res.jsonValue["Actions"]["#CertificateService.GenerateCSR"] = { 8830215816SMarri Devender Rao {"target", "/redfish/v1/CertificateService/Actions/" 8930215816SMarri Devender Rao "CertificateService.GenerateCSR"}}; 905968caeeSMarri Devender Rao res.end(); 915968caeeSMarri Devender Rao } 925968caeeSMarri Devender Rao }; // CertificateService 9337cce918SMarri Devender Rao 945968caeeSMarri Devender Rao /** 955968caeeSMarri Devender Rao * @brief Find the ID specified in the URL 965968caeeSMarri Devender Rao * Finds the numbers specified after the last "/" in the URL and returns. 975968caeeSMarri Devender Rao * @param[in] path URL 985968caeeSMarri Devender Rao * @return -1 on failure and number on success 995968caeeSMarri Devender Rao */ 10023a21a1cSEd Tanous inline long getIDFromURL(const std::string_view url) 1015968caeeSMarri Devender Rao { 102f23b7296SEd Tanous std::size_t found = url.rfind('/'); 1035968caeeSMarri Devender Rao if (found == std::string::npos) 1045968caeeSMarri Devender Rao { 1055968caeeSMarri Devender Rao return -1; 1065968caeeSMarri Devender Rao } 107e6604b11SIwona Klimaszewska 1085968caeeSMarri Devender Rao if ((found + 1) < url.length()) 1095968caeeSMarri Devender Rao { 1105968caeeSMarri Devender Rao std::string_view str = url.substr(found + 1); 111e6604b11SIwona Klimaszewska 112e6604b11SIwona Klimaszewska return boost::convert<long>(str, boost::cnv::strtol()).value_or(-1); 1135968caeeSMarri Devender Rao } 114e6604b11SIwona Klimaszewska 1155968caeeSMarri Devender Rao return -1; 1165968caeeSMarri Devender Rao } 1175968caeeSMarri Devender Rao 11823a21a1cSEd Tanous inline std::string 11958eb238fSKowalski, Kamil getCertificateFromReqBody(const std::shared_ptr<AsyncResp>& asyncResp, 12058eb238fSKowalski, Kamil const crow::Request& req) 12158eb238fSKowalski, Kamil { 12258eb238fSKowalski, Kamil nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false); 12358eb238fSKowalski, Kamil 12458eb238fSKowalski, Kamil if (reqJson.is_discarded()) 12558eb238fSKowalski, Kamil { 12658eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 12758eb238fSKowalski, Kamil return req.body; 12858eb238fSKowalski, Kamil } 12958eb238fSKowalski, Kamil 13058eb238fSKowalski, Kamil std::string certificate; 13158eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 13258eb238fSKowalski, Kamil 13358eb238fSKowalski, Kamil if (!json_util::readJson(reqJson, asyncResp->res, "CertificateString", 13458eb238fSKowalski, Kamil certificate, "CertificateType", certificateType)) 13558eb238fSKowalski, Kamil { 13658eb238fSKowalski, Kamil BMCWEB_LOG_ERROR << "Required parameters are missing"; 13758eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 13858eb238fSKowalski, Kamil return std::string(); 13958eb238fSKowalski, Kamil } 14058eb238fSKowalski, Kamil 14158eb238fSKowalski, Kamil if (*certificateType != "PEM") 14258eb238fSKowalski, Kamil { 14358eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 14458eb238fSKowalski, Kamil "CertificateType"); 14558eb238fSKowalski, Kamil return std::string(); 14658eb238fSKowalski, Kamil } 14758eb238fSKowalski, Kamil 14858eb238fSKowalski, Kamil return certificate; 14958eb238fSKowalski, Kamil } 15058eb238fSKowalski, Kamil 1515968caeeSMarri Devender Rao /** 1525968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 1535968caeeSMarri Devender Rao */ 1545968caeeSMarri Devender Rao class CertificateFile 1555968caeeSMarri Devender Rao { 1565968caeeSMarri Devender Rao public: 1575968caeeSMarri Devender Rao CertificateFile() = delete; 1585968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 1595968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 1605968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 1615968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 1625968caeeSMarri Devender Rao CertificateFile(const std::string& certString) 1635968caeeSMarri Devender Rao { 16472d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 1655207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 1665207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 1675207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 1685968caeeSMarri Devender Rao if (tempDirectory) 1695968caeeSMarri Devender Rao { 1705968caeeSMarri Devender Rao certDirectory = tempDirectory; 1715968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 1725968caeeSMarri Devender Rao std::ofstream out(certificateFile, std::ofstream::out | 1735968caeeSMarri Devender Rao std::ofstream::binary | 1745968caeeSMarri Devender Rao std::ofstream::trunc); 1755968caeeSMarri Devender Rao out << certString; 1765968caeeSMarri Devender Rao out.close(); 1775968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "Creating certificate file" << certificateFile; 1785968caeeSMarri Devender Rao } 1795968caeeSMarri Devender Rao } 1805968caeeSMarri Devender Rao ~CertificateFile() 1815968caeeSMarri Devender Rao { 1825968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1835968caeeSMarri Devender Rao { 1845968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "Removing certificate file" << certificateFile; 18523a21a1cSEd Tanous std::error_code ec; 18623a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 18723a21a1cSEd Tanous if (ec) 1885968caeeSMarri Devender Rao { 1895968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Failed to remove temp directory" 1905968caeeSMarri Devender Rao << certDirectory; 1915968caeeSMarri Devender Rao } 1925968caeeSMarri Devender Rao } 1935968caeeSMarri Devender Rao } 1945968caeeSMarri Devender Rao std::string getCertFilePath() 1955968caeeSMarri Devender Rao { 1965968caeeSMarri Devender Rao return certificateFile; 1975968caeeSMarri Devender Rao } 1985968caeeSMarri Devender Rao 1995968caeeSMarri Devender Rao private: 2005968caeeSMarri Devender Rao std::filesystem::path certificateFile; 2015968caeeSMarri Devender Rao std::filesystem::path certDirectory; 2025968caeeSMarri Devender Rao }; 2035968caeeSMarri Devender Rao 20430215816SMarri Devender Rao static std::unique_ptr<sdbusplus::bus::match::match> csrMatcher; 20530215816SMarri Devender Rao /** 20630215816SMarri Devender Rao * @brief Read data from CSR D-bus object and set to response 20730215816SMarri Devender Rao * 20830215816SMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 20930215816SMarri Devender Rao * @param[in] certURI Link to certifiate collection URI 21030215816SMarri Devender Rao * @param[in] service D-Bus service name 21130215816SMarri Devender Rao * @param[in] certObjPath certificate D-Bus object path 21230215816SMarri Devender Rao * @param[in] csrObjPath CSR D-Bus object path 21330215816SMarri Devender Rao * @return None 21430215816SMarri Devender Rao */ 21530215816SMarri Devender Rao static void getCSR(const std::shared_ptr<AsyncResp>& asyncResp, 21630215816SMarri Devender Rao const std::string& certURI, const std::string& service, 21730215816SMarri Devender Rao const std::string& certObjPath, 21830215816SMarri Devender Rao const std::string& csrObjPath) 21930215816SMarri Devender Rao { 22030215816SMarri Devender Rao BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath 22130215816SMarri Devender Rao << " CSRObjectPath=" << csrObjPath 22230215816SMarri Devender Rao << " service=" << service; 22330215816SMarri Devender Rao crow::connections::systemBus->async_method_call( 22430215816SMarri Devender Rao [asyncResp, certURI](const boost::system::error_code ec, 22530215816SMarri Devender Rao const std::string& csr) { 22630215816SMarri Devender Rao if (ec) 22730215816SMarri Devender Rao { 22830215816SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 22930215816SMarri Devender Rao messages::internalError(asyncResp->res); 23030215816SMarri Devender Rao return; 23130215816SMarri Devender Rao } 23230215816SMarri Devender Rao if (csr.empty()) 23330215816SMarri Devender Rao { 23430215816SMarri Devender Rao BMCWEB_LOG_ERROR << "CSR read is empty"; 23530215816SMarri Devender Rao messages::internalError(asyncResp->res); 23630215816SMarri Devender Rao return; 23730215816SMarri Devender Rao } 23830215816SMarri Devender Rao asyncResp->res.jsonValue["CSRString"] = csr; 23930215816SMarri Devender Rao asyncResp->res.jsonValue["CertificateCollection"] = { 24030215816SMarri Devender Rao {"@odata.id", certURI}}; 24130215816SMarri Devender Rao }, 24230215816SMarri Devender Rao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 24330215816SMarri Devender Rao } 24430215816SMarri Devender Rao 24530215816SMarri Devender Rao /** 24630215816SMarri Devender Rao * Action to Generate CSR 24730215816SMarri Devender Rao */ 24830215816SMarri Devender Rao class CertificateActionGenerateCSR : public Node 24930215816SMarri Devender Rao { 25030215816SMarri Devender Rao public: 25152cc112dSEd Tanous CertificateActionGenerateCSR(App& app) : 25230215816SMarri Devender Rao Node(app, "/redfish/v1/CertificateService/Actions/" 25330215816SMarri Devender Rao "CertificateService.GenerateCSR/") 25430215816SMarri Devender Rao { 25530215816SMarri Devender Rao entityPrivileges = { 25630215816SMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 25730215816SMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 25830215816SMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 25930215816SMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 26030215816SMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 26130215816SMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 26230215816SMarri Devender Rao } 26330215816SMarri Devender Rao 26430215816SMarri Devender Rao private: 26530215816SMarri Devender Rao void doPost(crow::Response& res, const crow::Request& req, 266cb13a392SEd Tanous const std::vector<std::string>&) override 26730215816SMarri Devender Rao { 2682c70f800SEd Tanous static const int rsaKeyBitLength = 2048; 26930215816SMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 27030215816SMarri Devender Rao // Required parameters 27130215816SMarri Devender Rao std::string city; 27230215816SMarri Devender Rao std::string commonName; 27330215816SMarri Devender Rao std::string country; 27430215816SMarri Devender Rao std::string organization; 27530215816SMarri Devender Rao std::string organizationalUnit; 27630215816SMarri Devender Rao std::string state; 27730215816SMarri Devender Rao nlohmann::json certificateCollection; 27830215816SMarri Devender Rao 27930215816SMarri Devender Rao // Optional parameters 28030215816SMarri Devender Rao std::optional<std::vector<std::string>> optAlternativeNames = 28130215816SMarri Devender Rao std::vector<std::string>(); 28230215816SMarri Devender Rao std::optional<std::string> optContactPerson = ""; 28330215816SMarri Devender Rao std::optional<std::string> optChallengePassword = ""; 28430215816SMarri Devender Rao std::optional<std::string> optEmail = ""; 28530215816SMarri Devender Rao std::optional<std::string> optGivenName = ""; 28630215816SMarri Devender Rao std::optional<std::string> optInitials = ""; 2872c70f800SEd Tanous std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 288aaf3206fSVernon Mauery std::optional<std::string> optKeyCurveId = "secp384r1"; 28930215816SMarri Devender Rao std::optional<std::string> optKeyPairAlgorithm = "EC"; 29030215816SMarri Devender Rao std::optional<std::vector<std::string>> optKeyUsage = 29130215816SMarri Devender Rao std::vector<std::string>(); 29230215816SMarri Devender Rao std::optional<std::string> optSurname = ""; 29330215816SMarri Devender Rao std::optional<std::string> optUnstructuredName = ""; 29430215816SMarri Devender Rao if (!json_util::readJson( 29530215816SMarri Devender Rao req, asyncResp->res, "City", city, "CommonName", commonName, 29630215816SMarri Devender Rao "ContactPerson", optContactPerson, "Country", country, 29730215816SMarri Devender Rao "Organization", organization, "OrganizationalUnit", 29830215816SMarri Devender Rao organizationalUnit, "State", state, "CertificateCollection", 29930215816SMarri Devender Rao certificateCollection, "AlternativeNames", optAlternativeNames, 30030215816SMarri Devender Rao "ChallengePassword", optChallengePassword, "Email", optEmail, 30130215816SMarri Devender Rao "GivenName", optGivenName, "Initials", optInitials, 30230215816SMarri Devender Rao "KeyBitLength", optKeyBitLength, "KeyCurveId", optKeyCurveId, 30330215816SMarri Devender Rao "KeyPairAlgorithm", optKeyPairAlgorithm, "KeyUsage", 30430215816SMarri Devender Rao optKeyUsage, "Surname", optSurname, "UnstructuredName", 30530215816SMarri Devender Rao optUnstructuredName)) 30630215816SMarri Devender Rao { 30730215816SMarri Devender Rao return; 30830215816SMarri Devender Rao } 30930215816SMarri Devender Rao 31030215816SMarri Devender Rao // bmcweb has no way to store or decode a private key challenge 31130215816SMarri Devender Rao // password, which will likely cause bmcweb to crash on startup if this 31230215816SMarri Devender Rao // is not set on a post so not allowing the user to set value 31330215816SMarri Devender Rao if (*optChallengePassword != "") 31430215816SMarri Devender Rao { 31530215816SMarri Devender Rao messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 31630215816SMarri Devender Rao "ChallengePassword"); 31730215816SMarri Devender Rao return; 31830215816SMarri Devender Rao } 31930215816SMarri Devender Rao 32030215816SMarri Devender Rao std::string certURI; 32130215816SMarri Devender Rao if (!redfish::json_util::readJson(certificateCollection, asyncResp->res, 32230215816SMarri Devender Rao "@odata.id", certURI)) 32330215816SMarri Devender Rao { 32430215816SMarri Devender Rao return; 32530215816SMarri Devender Rao } 32630215816SMarri Devender Rao 32730215816SMarri Devender Rao std::string objectPath; 32830215816SMarri Devender Rao std::string service; 32930215816SMarri Devender Rao if (boost::starts_with( 33030215816SMarri Devender Rao certURI, 33130215816SMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 33230215816SMarri Devender Rao { 33330215816SMarri Devender Rao objectPath = certs::httpsObjectPath; 33430215816SMarri Devender Rao service = certs::httpsServiceName; 33530215816SMarri Devender Rao } 3363b7f0149SMarri Devender Rao else if (boost::starts_with( 3373b7f0149SMarri Devender Rao certURI, "/redfish/v1/AccountService/LDAP/Certificates")) 3383b7f0149SMarri Devender Rao { 3393b7f0149SMarri Devender Rao objectPath = certs::ldapObjectPath; 3403b7f0149SMarri Devender Rao service = certs::ldapServiceName; 3413b7f0149SMarri Devender Rao } 34230215816SMarri Devender Rao else 34330215816SMarri Devender Rao { 34430215816SMarri Devender Rao messages::actionParameterNotSupported( 34530215816SMarri Devender Rao asyncResp->res, "CertificateCollection", "GenerateCSR"); 34630215816SMarri Devender Rao return; 34730215816SMarri Devender Rao } 34830215816SMarri Devender Rao 34930215816SMarri Devender Rao // supporting only EC and RSA algorithm 35030215816SMarri Devender Rao if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 35130215816SMarri Devender Rao { 35230215816SMarri Devender Rao messages::actionParameterNotSupported( 35330215816SMarri Devender Rao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 35430215816SMarri Devender Rao return; 35530215816SMarri Devender Rao } 35630215816SMarri Devender Rao 35730215816SMarri Devender Rao // supporting only 2048 key bit length for RSA algorithm due to time 35830215816SMarri Devender Rao // consumed in generating private key 35930215816SMarri Devender Rao if (*optKeyPairAlgorithm == "RSA" && 3602c70f800SEd Tanous *optKeyBitLength != rsaKeyBitLength) 36130215816SMarri Devender Rao { 36230215816SMarri Devender Rao messages::propertyValueNotInList(asyncResp->res, 36330215816SMarri Devender Rao std::to_string(*optKeyBitLength), 36430215816SMarri Devender Rao "KeyBitLength"); 36530215816SMarri Devender Rao return; 36630215816SMarri Devender Rao } 36730215816SMarri Devender Rao 36830215816SMarri Devender Rao // validate KeyUsage supporting only 1 type based on URL 36930215816SMarri Devender Rao if (boost::starts_with( 37030215816SMarri Devender Rao certURI, 37130215816SMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 37230215816SMarri Devender Rao { 37330215816SMarri Devender Rao if (optKeyUsage->size() == 0) 37430215816SMarri Devender Rao { 37530215816SMarri Devender Rao optKeyUsage->push_back("ServerAuthentication"); 37630215816SMarri Devender Rao } 37730215816SMarri Devender Rao else if (optKeyUsage->size() == 1) 37830215816SMarri Devender Rao { 37930215816SMarri Devender Rao if ((*optKeyUsage)[0] != "ServerAuthentication") 38030215816SMarri Devender Rao { 38130215816SMarri Devender Rao messages::propertyValueNotInList( 38230215816SMarri Devender Rao asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); 38330215816SMarri Devender Rao return; 38430215816SMarri Devender Rao } 38530215816SMarri Devender Rao } 38630215816SMarri Devender Rao else 38730215816SMarri Devender Rao { 38830215816SMarri Devender Rao messages::actionParameterNotSupported( 38930215816SMarri Devender Rao asyncResp->res, "KeyUsage", "GenerateCSR"); 39030215816SMarri Devender Rao return; 39130215816SMarri Devender Rao } 39230215816SMarri Devender Rao } 3933b7f0149SMarri Devender Rao else if (boost::starts_with( 3943b7f0149SMarri Devender Rao certURI, "/redfish/v1/AccountService/LDAP/Certificates")) 3953b7f0149SMarri Devender Rao { 3963b7f0149SMarri Devender Rao if (optKeyUsage->size() == 0) 3973b7f0149SMarri Devender Rao { 3983b7f0149SMarri Devender Rao optKeyUsage->push_back("ClientAuthentication"); 3993b7f0149SMarri Devender Rao } 4003b7f0149SMarri Devender Rao else if (optKeyUsage->size() == 1) 4013b7f0149SMarri Devender Rao { 4023b7f0149SMarri Devender Rao if ((*optKeyUsage)[0] != "ClientAuthentication") 4033b7f0149SMarri Devender Rao { 4043b7f0149SMarri Devender Rao messages::propertyValueNotInList( 4053b7f0149SMarri Devender Rao asyncResp->res, (*optKeyUsage)[0], "KeyUsage"); 4063b7f0149SMarri Devender Rao return; 4073b7f0149SMarri Devender Rao } 4083b7f0149SMarri Devender Rao } 4093b7f0149SMarri Devender Rao else 4103b7f0149SMarri Devender Rao { 4113b7f0149SMarri Devender Rao messages::actionParameterNotSupported( 4123b7f0149SMarri Devender Rao asyncResp->res, "KeyUsage", "GenerateCSR"); 4133b7f0149SMarri Devender Rao return; 4143b7f0149SMarri Devender Rao } 4153b7f0149SMarri Devender Rao } 41630215816SMarri Devender Rao 41730215816SMarri Devender Rao // Only allow one CSR matcher at a time so setting retry time-out and 41830215816SMarri Devender Rao // timer expiry to 10 seconds for now. 4192c70f800SEd Tanous static const int timeOut = 10; 42030215816SMarri Devender Rao if (csrMatcher) 42130215816SMarri Devender Rao { 42230215816SMarri Devender Rao messages::serviceTemporarilyUnavailable(asyncResp->res, 4232c70f800SEd Tanous std::to_string(timeOut)); 42430215816SMarri Devender Rao return; 42530215816SMarri Devender Rao } 42630215816SMarri Devender Rao 42730215816SMarri Devender Rao // Make this static so it survives outside this method 42830215816SMarri Devender Rao static boost::asio::steady_timer timeout(*req.ioService); 4292c70f800SEd Tanous timeout.expires_after(std::chrono::seconds(timeOut)); 43030215816SMarri Devender Rao timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 43130215816SMarri Devender Rao csrMatcher = nullptr; 43230215816SMarri Devender Rao if (ec) 43330215816SMarri Devender Rao { 43430215816SMarri Devender Rao // operation_aborted is expected if timer is canceled before 43530215816SMarri Devender Rao // completion. 43630215816SMarri Devender Rao if (ec != boost::asio::error::operation_aborted) 43730215816SMarri Devender Rao { 43830215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Async_wait failed " << ec; 43930215816SMarri Devender Rao } 44030215816SMarri Devender Rao return; 44130215816SMarri Devender Rao } 44230215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; 44330215816SMarri Devender Rao messages::internalError(asyncResp->res); 44430215816SMarri Devender Rao }); 44530215816SMarri Devender Rao 44630215816SMarri Devender Rao // create a matcher to wait on CSR object 44730215816SMarri Devender Rao BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; 44830215816SMarri Devender Rao std::string match("type='signal'," 44930215816SMarri Devender Rao "interface='org.freedesktop.DBus.ObjectManager'," 45030215816SMarri Devender Rao "path='" + 45130215816SMarri Devender Rao objectPath + 45230215816SMarri Devender Rao "'," 45330215816SMarri Devender Rao "member='InterfacesAdded'"); 45430215816SMarri Devender Rao csrMatcher = std::make_unique<sdbusplus::bus::match::match>( 45530215816SMarri Devender Rao *crow::connections::systemBus, match, 45630215816SMarri Devender Rao [asyncResp, service, objectPath, 45730215816SMarri Devender Rao certURI](sdbusplus::message::message& m) { 458271584abSEd Tanous timeout.cancel(); 45930215816SMarri Devender Rao if (m.is_method_error()) 46030215816SMarri Devender Rao { 46130215816SMarri Devender Rao BMCWEB_LOG_ERROR << "Dbus method error!!!"; 46230215816SMarri Devender Rao messages::internalError(asyncResp->res); 46330215816SMarri Devender Rao return; 46430215816SMarri Devender Rao } 46530215816SMarri Devender Rao std::vector<std::pair< 46630215816SMarri Devender Rao std::string, std::vector<std::pair< 46730215816SMarri Devender Rao std::string, std::variant<std::string>>>>> 46830215816SMarri Devender Rao interfacesProperties; 46930215816SMarri Devender Rao sdbusplus::message::object_path csrObjectPath; 47030215816SMarri Devender Rao m.read(csrObjectPath, interfacesProperties); 47130215816SMarri Devender Rao BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; 47230215816SMarri Devender Rao for (auto& interface : interfacesProperties) 47330215816SMarri Devender Rao { 47430215816SMarri Devender Rao if (interface.first == "xyz.openbmc_project.Certs.CSR") 47530215816SMarri Devender Rao { 47630215816SMarri Devender Rao getCSR(asyncResp, certURI, service, objectPath, 47730215816SMarri Devender Rao csrObjectPath.str); 47830215816SMarri Devender Rao break; 47930215816SMarri Devender Rao } 48030215816SMarri Devender Rao } 48130215816SMarri Devender Rao }); 48230215816SMarri Devender Rao crow::connections::systemBus->async_method_call( 483271584abSEd Tanous [asyncResp](const boost::system::error_code& ec, 484cb13a392SEd Tanous const std::string&) { 48530215816SMarri Devender Rao if (ec) 48630215816SMarri Devender Rao { 48730215816SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message(); 48830215816SMarri Devender Rao messages::internalError(asyncResp->res); 48930215816SMarri Devender Rao return; 49030215816SMarri Devender Rao } 49130215816SMarri Devender Rao }, 49230215816SMarri Devender Rao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 49330215816SMarri Devender Rao "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 49430215816SMarri Devender Rao commonName, *optContactPerson, country, *optEmail, *optGivenName, 49530215816SMarri Devender Rao *optInitials, *optKeyBitLength, *optKeyCurveId, 49630215816SMarri Devender Rao *optKeyPairAlgorithm, *optKeyUsage, organization, 49730215816SMarri Devender Rao organizationalUnit, state, *optSurname, *optUnstructuredName); 49830215816SMarri Devender Rao } 49930215816SMarri Devender Rao }; // CertificateActionGenerateCSR 50030215816SMarri Devender Rao 5015968caeeSMarri Devender Rao /** 5024e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 5035968caeeSMarri Devender Rao * 5045968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 5055968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 5065968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 5075968caeeSMarri Devender Rao * @return None 5085968caeeSMarri Devender Rao */ 5095968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out, 5105968caeeSMarri Devender Rao const std::string_view value) 5115968caeeSMarri Devender Rao { 5125968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 5135968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 5145968caeeSMarri Devender Rao while (i != value.end()) 5155968caeeSMarri Devender Rao { 5165968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 5175968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 5185968caeeSMarri Devender Rao { 51917a897dfSManojkiran Eda ++i; 5205968caeeSMarri Devender Rao } 5215968caeeSMarri Devender Rao if (i == value.end()) 5225968caeeSMarri Devender Rao { 5235968caeeSMarri Devender Rao break; 5245968caeeSMarri Devender Rao } 525271584abSEd Tanous const std::string_view key(tokenBegin, 526271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 52717a897dfSManojkiran Eda ++i; 5285968caeeSMarri Devender Rao tokenBegin = i; 5295968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 5305968caeeSMarri Devender Rao { 53117a897dfSManojkiran Eda ++i; 5325968caeeSMarri Devender Rao } 533271584abSEd Tanous const std::string_view val(tokenBegin, 534271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 5355968caeeSMarri Devender Rao if (key == "L") 5365968caeeSMarri Devender Rao { 5375968caeeSMarri Devender Rao out["City"] = val; 5385968caeeSMarri Devender Rao } 5395968caeeSMarri Devender Rao else if (key == "CN") 5405968caeeSMarri Devender Rao { 5415968caeeSMarri Devender Rao out["CommonName"] = val; 5425968caeeSMarri Devender Rao } 5435968caeeSMarri Devender Rao else if (key == "C") 5445968caeeSMarri Devender Rao { 5455968caeeSMarri Devender Rao out["Country"] = val; 5465968caeeSMarri Devender Rao } 5475968caeeSMarri Devender Rao else if (key == "O") 5485968caeeSMarri Devender Rao { 5495968caeeSMarri Devender Rao out["Organization"] = val; 5505968caeeSMarri Devender Rao } 5515968caeeSMarri Devender Rao else if (key == "OU") 5525968caeeSMarri Devender Rao { 5535968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 5545968caeeSMarri Devender Rao } 5555968caeeSMarri Devender Rao else if (key == "ST") 5565968caeeSMarri Devender Rao { 5575968caeeSMarri Devender Rao out["State"] = val; 5585968caeeSMarri Devender Rao } 5595968caeeSMarri Devender Rao // skip comma character 5605968caeeSMarri Devender Rao if (i != value.end()) 5615968caeeSMarri Devender Rao { 56217a897dfSManojkiran Eda ++i; 5635968caeeSMarri Devender Rao } 5645968caeeSMarri Devender Rao } 5655968caeeSMarri Devender Rao } 5665968caeeSMarri Devender Rao 5675968caeeSMarri Devender Rao /** 5685968caeeSMarri Devender Rao * @brief Retrieve the certificates properties and append to the response 5695968caeeSMarri Devender Rao * message 5705968caeeSMarri Devender Rao * 5715968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 5725968caeeSMarri Devender Rao * @param[in] objectPath Path of the D-Bus service object 5735968caeeSMarri Devender Rao * @param[in] certId Id of the certificate 5745968caeeSMarri Devender Rao * @param[in] certURL URL of the certificate object 5755968caeeSMarri Devender Rao * @param[in] name name of the certificate 5765968caeeSMarri Devender Rao * @return None 5775968caeeSMarri Devender Rao */ 5785968caeeSMarri Devender Rao static void getCertificateProperties( 5795968caeeSMarri Devender Rao const std::shared_ptr<AsyncResp>& asyncResp, const std::string& objectPath, 58037cce918SMarri Devender Rao const std::string& service, long certId, const std::string& certURL, 58137cce918SMarri Devender Rao const std::string& name) 5825968caeeSMarri Devender Rao { 5835968caeeSMarri Devender Rao using PropertyType = 5845968caeeSMarri Devender Rao std::variant<std::string, uint64_t, std::vector<std::string>>; 5855968caeeSMarri Devender Rao using PropertiesMap = boost::container::flat_map<std::string, PropertyType>; 5865968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath 5875968caeeSMarri Devender Rao << " certId=" << certId << " certURl=" << certURL; 5885968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 58937cce918SMarri Devender Rao [asyncResp, certURL, certId, name](const boost::system::error_code ec, 5905968caeeSMarri Devender Rao const PropertiesMap& properties) { 5915968caeeSMarri Devender Rao if (ec) 5925968caeeSMarri Devender Rao { 5935968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 5948aae75adSMarri Devender Rao messages::resourceNotFound(asyncResp->res, name, 5958aae75adSMarri Devender Rao std::to_string(certId)); 5965968caeeSMarri Devender Rao return; 5975968caeeSMarri Devender Rao } 5985968caeeSMarri Devender Rao asyncResp->res.jsonValue = { 5995968caeeSMarri Devender Rao {"@odata.id", certURL}, 6005968caeeSMarri Devender Rao {"@odata.type", "#Certificate.v1_0_0.Certificate"}, 6015968caeeSMarri Devender Rao {"Id", std::to_string(certId)}, 6025968caeeSMarri Devender Rao {"Name", name}, 6035968caeeSMarri Devender Rao {"Description", name}}; 6045968caeeSMarri Devender Rao for (const auto& property : properties) 6055968caeeSMarri Devender Rao { 6065968caeeSMarri Devender Rao if (property.first == "CertificateString") 6075968caeeSMarri Devender Rao { 6085968caeeSMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = ""; 6095968caeeSMarri Devender Rao const std::string* value = 6105968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 6115968caeeSMarri Devender Rao if (value) 6125968caeeSMarri Devender Rao { 61337cce918SMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = *value; 6145968caeeSMarri Devender Rao } 6155968caeeSMarri Devender Rao } 6165968caeeSMarri Devender Rao else if (property.first == "KeyUsage") 6175968caeeSMarri Devender Rao { 6185968caeeSMarri Devender Rao nlohmann::json& keyUsage = 6195968caeeSMarri Devender Rao asyncResp->res.jsonValue["KeyUsage"]; 6205968caeeSMarri Devender Rao keyUsage = nlohmann::json::array(); 6215968caeeSMarri Devender Rao const std::vector<std::string>* value = 62237cce918SMarri Devender Rao std::get_if<std::vector<std::string>>(&property.second); 6235968caeeSMarri Devender Rao if (value) 6245968caeeSMarri Devender Rao { 6255968caeeSMarri Devender Rao for (const std::string& usage : *value) 6265968caeeSMarri Devender Rao { 6275968caeeSMarri Devender Rao keyUsage.push_back(usage); 6285968caeeSMarri Devender Rao } 6295968caeeSMarri Devender Rao } 6305968caeeSMarri Devender Rao } 6315968caeeSMarri Devender Rao else if (property.first == "Issuer") 6325968caeeSMarri Devender Rao { 6335968caeeSMarri Devender Rao const std::string* value = 6345968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 6355968caeeSMarri Devender Rao if (value) 6365968caeeSMarri Devender Rao { 6375968caeeSMarri Devender Rao updateCertIssuerOrSubject( 6385968caeeSMarri Devender Rao asyncResp->res.jsonValue["Issuer"], *value); 6395968caeeSMarri Devender Rao } 6405968caeeSMarri Devender Rao } 6415968caeeSMarri Devender Rao else if (property.first == "Subject") 6425968caeeSMarri Devender Rao { 6435968caeeSMarri Devender Rao const std::string* value = 6445968caeeSMarri Devender Rao std::get_if<std::string>(&property.second); 6455968caeeSMarri Devender Rao if (value) 6465968caeeSMarri Devender Rao { 6475968caeeSMarri Devender Rao updateCertIssuerOrSubject( 64837cce918SMarri Devender Rao asyncResp->res.jsonValue["Subject"], *value); 6495968caeeSMarri Devender Rao } 6505968caeeSMarri Devender Rao } 6515968caeeSMarri Devender Rao else if (property.first == "ValidNotAfter") 6525968caeeSMarri Devender Rao { 6535968caeeSMarri Devender Rao const uint64_t* value = 6545968caeeSMarri Devender Rao std::get_if<uint64_t>(&property.second); 6555968caeeSMarri Devender Rao if (value) 6565968caeeSMarri Devender Rao { 65737cce918SMarri Devender Rao std::time_t time = static_cast<std::time_t>(*value); 6585968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotAfter"] = 6595968caeeSMarri Devender Rao crow::utility::getDateTime(time); 6605968caeeSMarri Devender Rao } 6615968caeeSMarri Devender Rao } 6625968caeeSMarri Devender Rao else if (property.first == "ValidNotBefore") 6635968caeeSMarri Devender Rao { 6645968caeeSMarri Devender Rao const uint64_t* value = 6655968caeeSMarri Devender Rao std::get_if<uint64_t>(&property.second); 6665968caeeSMarri Devender Rao if (value) 6675968caeeSMarri Devender Rao { 66837cce918SMarri Devender Rao std::time_t time = static_cast<std::time_t>(*value); 6695968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotBefore"] = 6705968caeeSMarri Devender Rao crow::utility::getDateTime(time); 6715968caeeSMarri Devender Rao } 6725968caeeSMarri Devender Rao } 6735968caeeSMarri Devender Rao } 6745968caeeSMarri Devender Rao asyncResp->res.addHeader("Location", certURL); 6755968caeeSMarri Devender Rao }, 6765968caeeSMarri Devender Rao service, objectPath, certs::dbusPropIntf, "GetAll", 6775968caeeSMarri Devender Rao certs::certPropIntf); 6785968caeeSMarri Devender Rao } 6795968caeeSMarri Devender Rao 6805968caeeSMarri Devender Rao using GetObjectType = 6815968caeeSMarri Devender Rao std::vector<std::pair<std::string, std::vector<std::string>>>; 6825968caeeSMarri Devender Rao 6835968caeeSMarri Devender Rao /** 6845968caeeSMarri Devender Rao * Action to replace an existing certificate 6855968caeeSMarri Devender Rao */ 6865968caeeSMarri Devender Rao class CertificateActionsReplaceCertificate : public Node 6875968caeeSMarri Devender Rao { 6885968caeeSMarri Devender Rao public: 68952cc112dSEd Tanous CertificateActionsReplaceCertificate(App& app) : 6905968caeeSMarri Devender Rao Node(app, "/redfish/v1/CertificateService/Actions/" 6915968caeeSMarri Devender Rao "CertificateService.ReplaceCertificate/") 6925968caeeSMarri Devender Rao { 6935968caeeSMarri Devender Rao entityPrivileges = { 6945968caeeSMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 6955968caeeSMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 6965968caeeSMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 6975968caeeSMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 6985968caeeSMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 6995968caeeSMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7005968caeeSMarri Devender Rao } 7015968caeeSMarri Devender Rao 7025968caeeSMarri Devender Rao private: 7035968caeeSMarri Devender Rao void doPost(crow::Response& res, const crow::Request& req, 704cb13a392SEd Tanous const std::vector<std::string>&) override 7055968caeeSMarri Devender Rao { 7065968caeeSMarri Devender Rao std::string certificate; 7075968caeeSMarri Devender Rao nlohmann::json certificateUri; 7085968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 7095968caeeSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 7105968caeeSMarri Devender Rao if (!json_util::readJson(req, asyncResp->res, "CertificateString", 7115968caeeSMarri Devender Rao certificate, "CertificateUri", certificateUri, 7125968caeeSMarri Devender Rao "CertificateType", certificateType)) 7135968caeeSMarri Devender Rao { 7145968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Required parameters are missing"; 7155968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 7165968caeeSMarri Devender Rao return; 7175968caeeSMarri Devender Rao } 7185968caeeSMarri Devender Rao 7195968caeeSMarri Devender Rao if (!certificateType) 7205968caeeSMarri Devender Rao { 7215968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 7225968caeeSMarri Devender Rao return; 7235968caeeSMarri Devender Rao } 7245968caeeSMarri Devender Rao if (certificateType != "PEM") 7255968caeeSMarri Devender Rao { 7265968caeeSMarri Devender Rao messages::actionParameterNotSupported( 7275968caeeSMarri Devender Rao asyncResp->res, "CertificateType", "ReplaceCertificate"); 7285968caeeSMarri Devender Rao return; 7295968caeeSMarri Devender Rao } 7305968caeeSMarri Devender Rao 7315968caeeSMarri Devender Rao std::string certURI; 7325968caeeSMarri Devender Rao if (!redfish::json_util::readJson(certificateUri, asyncResp->res, 7335968caeeSMarri Devender Rao "@odata.id", certURI)) 7345968caeeSMarri Devender Rao { 7355968caeeSMarri Devender Rao messages::actionParameterMissing( 7365968caeeSMarri Devender Rao asyncResp->res, "ReplaceCertificate", "CertificateUri"); 7375968caeeSMarri Devender Rao return; 7385968caeeSMarri Devender Rao } 7395968caeeSMarri Devender Rao 7405968caeeSMarri Devender Rao BMCWEB_LOG_INFO << "Certificate URI to replace" << certURI; 7415968caeeSMarri Devender Rao long id = getIDFromURL(certURI); 7425968caeeSMarri Devender Rao if (id < 0) 7435968caeeSMarri Devender Rao { 7445968caeeSMarri Devender Rao messages::actionParameterValueFormatError(asyncResp->res, certURI, 7455968caeeSMarri Devender Rao "CertificateUri", 7465968caeeSMarri Devender Rao "ReplaceCertificate"); 7475968caeeSMarri Devender Rao return; 7485968caeeSMarri Devender Rao } 7495968caeeSMarri Devender Rao std::string objectPath; 7505968caeeSMarri Devender Rao std::string name; 75137cce918SMarri Devender Rao std::string service; 7525968caeeSMarri Devender Rao if (boost::starts_with( 7535968caeeSMarri Devender Rao certURI, 7545968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/")) 7555968caeeSMarri Devender Rao { 7565968caeeSMarri Devender Rao objectPath = 7575968caeeSMarri Devender Rao std::string(certs::httpsObjectPath) + "/" + std::to_string(id); 7585968caeeSMarri Devender Rao name = "HTTPS certificate"; 75937cce918SMarri Devender Rao service = certs::httpsServiceName; 76037cce918SMarri Devender Rao } 76137cce918SMarri Devender Rao else if (boost::starts_with( 76237cce918SMarri Devender Rao certURI, "/redfish/v1/AccountService/LDAP/Certificates/")) 76337cce918SMarri Devender Rao { 76437cce918SMarri Devender Rao objectPath = 76537cce918SMarri Devender Rao std::string(certs::ldapObjectPath) + "/" + std::to_string(id); 76637cce918SMarri Devender Rao name = "LDAP certificate"; 76737cce918SMarri Devender Rao service = certs::ldapServiceName; 7685968caeeSMarri Devender Rao } 769cfcd5f6bSMarri Devender Rao else if (boost::starts_with( 770cfcd5f6bSMarri Devender Rao certURI, 771cfcd5f6bSMarri Devender Rao "/redfish/v1/Managers/bmc/Truststore/Certificates/")) 772cfcd5f6bSMarri Devender Rao { 773cfcd5f6bSMarri Devender Rao objectPath = std::string(certs::authorityObjectPath) + "/" + 774cfcd5f6bSMarri Devender Rao std::to_string(id); 775cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 776cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 777cfcd5f6bSMarri Devender Rao } 7785968caeeSMarri Devender Rao else 7795968caeeSMarri Devender Rao { 7805968caeeSMarri Devender Rao messages::actionParameterNotSupported( 7815968caeeSMarri Devender Rao asyncResp->res, "CertificateUri", "ReplaceCertificate"); 7825968caeeSMarri Devender Rao return; 7835968caeeSMarri Devender Rao } 7845968caeeSMarri Devender Rao 7855968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 7865968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 7875968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 78837cce918SMarri Devender Rao [asyncResp, certFile, objectPath, service, certURI, id, 7895968caeeSMarri Devender Rao name](const boost::system::error_code ec) { 7905968caeeSMarri Devender Rao if (ec) 7915968caeeSMarri Devender Rao { 7925968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 7938aae75adSMarri Devender Rao messages::resourceNotFound(asyncResp->res, name, 7948aae75adSMarri Devender Rao std::to_string(id)); 7955968caeeSMarri Devender Rao return; 7965968caeeSMarri Devender Rao } 79737cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, service, id, 7985968caeeSMarri Devender Rao certURI, name); 7995968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 8005968caeeSMarri Devender Rao << certFile->getCertFilePath(); 8015968caeeSMarri Devender Rao }, 8025968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 8035968caeeSMarri Devender Rao certFile->getCertFilePath()); 8045968caeeSMarri Devender Rao } 8055968caeeSMarri Devender Rao }; // CertificateActionsReplaceCertificate 8065968caeeSMarri Devender Rao 8075968caeeSMarri Devender Rao /** 8085968caeeSMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 8095968caeeSMarri Devender Rao * of a component, account or service. 8105968caeeSMarri Devender Rao */ 8115968caeeSMarri Devender Rao class HTTPSCertificate : public Node 8125968caeeSMarri Devender Rao { 8135968caeeSMarri Devender Rao public: 81452cc112dSEd Tanous HTTPSCertificate(App& app) : 8155968caeeSMarri Devender Rao Node(app, 8165968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" 8175968caeeSMarri Devender Rao "<str>/", 8185968caeeSMarri Devender Rao std::string()) 8195968caeeSMarri Devender Rao { 8205968caeeSMarri Devender Rao entityPrivileges = { 8215968caeeSMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 8225968caeeSMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 8235968caeeSMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 8245968caeeSMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 8255968caeeSMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 8265968caeeSMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8275968caeeSMarri Devender Rao } 8285968caeeSMarri Devender Rao 8295968caeeSMarri Devender Rao void doGet(crow::Response& res, const crow::Request& req, 8305968caeeSMarri Devender Rao const std::vector<std::string>& params) override 8315968caeeSMarri Devender Rao { 8325968caeeSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 8335968caeeSMarri Devender Rao if (params.size() != 1) 8345968caeeSMarri Devender Rao { 8355968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 8365968caeeSMarri Devender Rao return; 8375968caeeSMarri Devender Rao } 8385968caeeSMarri Devender Rao long id = getIDFromURL(req.url); 8395968caeeSMarri Devender Rao 8405968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPSCertificate::doGet ID=" << std::to_string(id); 8415968caeeSMarri Devender Rao std::string certURL = 8425968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/" + 8435968caeeSMarri Devender Rao std::to_string(id); 8445968caeeSMarri Devender Rao std::string objectPath = certs::httpsObjectPath; 8455968caeeSMarri Devender Rao objectPath += "/"; 8465968caeeSMarri Devender Rao objectPath += std::to_string(id); 84737cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName, 84837cce918SMarri Devender Rao id, certURL, "HTTPS Certificate"); 8495968caeeSMarri Devender Rao } 8505968caeeSMarri Devender Rao 8515968caeeSMarri Devender Rao }; // namespace redfish 8525968caeeSMarri Devender Rao 8535968caeeSMarri Devender Rao /** 8545968caeeSMarri Devender Rao * Collection of HTTPS certificates 8555968caeeSMarri Devender Rao */ 8565968caeeSMarri Devender Rao class HTTPSCertificateCollection : public Node 8575968caeeSMarri Devender Rao { 8585968caeeSMarri Devender Rao public: 85952cc112dSEd Tanous HTTPSCertificateCollection(App& app) : 8605968caeeSMarri Devender Rao Node(app, 8615968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 8625968caeeSMarri Devender Rao { 8635968caeeSMarri Devender Rao entityPrivileges = { 8645968caeeSMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 8655968caeeSMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 8665968caeeSMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 8675968caeeSMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 8685968caeeSMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 8695968caeeSMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8705968caeeSMarri Devender Rao } 871cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 872cb13a392SEd Tanous const std::vector<std::string>&) override 8735968caeeSMarri Devender Rao { 8745968caeeSMarri Devender Rao res.jsonValue = { 8755968caeeSMarri Devender Rao {"@odata.id", 8765968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"}, 8775968caeeSMarri Devender Rao {"@odata.type", "#CertificateCollection.CertificateCollection"}, 8785968caeeSMarri Devender Rao {"Name", "HTTPS Certificates Collection"}, 8795968caeeSMarri Devender Rao {"Description", "A Collection of HTTPS certificate instances"}}; 8805968caeeSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 8815968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 8825968caeeSMarri Devender Rao [asyncResp](const boost::system::error_code ec, 8835968caeeSMarri Devender Rao const ManagedObjectType& certs) { 8845968caeeSMarri Devender Rao if (ec) 8855968caeeSMarri Devender Rao { 8865968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 8875968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 8885968caeeSMarri Devender Rao return; 8895968caeeSMarri Devender Rao } 89037cce918SMarri Devender Rao nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 8915968caeeSMarri Devender Rao members = nlohmann::json::array(); 8925968caeeSMarri Devender Rao for (const auto& cert : certs) 8935968caeeSMarri Devender Rao { 8945968caeeSMarri Devender Rao long id = getIDFromURL(cert.first.str); 89537cce918SMarri Devender Rao if (id >= 0) 8965968caeeSMarri Devender Rao { 8975968caeeSMarri Devender Rao members.push_back( 8985968caeeSMarri Devender Rao {{"@odata.id", 8995968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/" 9005968caeeSMarri Devender Rao "NetworkProtocol/HTTPS/Certificates/" + 9015968caeeSMarri Devender Rao std::to_string(id)}}); 9025968caeeSMarri Devender Rao } 9035968caeeSMarri Devender Rao } 9045968caeeSMarri Devender Rao asyncResp->res.jsonValue["Members@odata.count"] = 9055968caeeSMarri Devender Rao members.size(); 9065968caeeSMarri Devender Rao }, 90737cce918SMarri Devender Rao certs::httpsServiceName, certs::httpsObjectPath, 90837cce918SMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 9095968caeeSMarri Devender Rao } 9105968caeeSMarri Devender Rao 9115968caeeSMarri Devender Rao void doPost(crow::Response& res, const crow::Request& req, 912cb13a392SEd Tanous const std::vector<std::string>&) override 9135968caeeSMarri Devender Rao { 9145968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; 9155968caeeSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 9165968caeeSMarri Devender Rao asyncResp->res.jsonValue = {{"Name", "HTTPS Certificate"}, 9175968caeeSMarri Devender Rao {"Description", "HTTPS Certificate"}}; 9185968caeeSMarri Devender Rao 91958eb238fSKowalski, Kamil std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 92058eb238fSKowalski, Kamil 92158eb238fSKowalski, Kamil if (certFileBody.empty()) 92258eb238fSKowalski, Kamil { 923a08752f5SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 924a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 92558eb238fSKowalski, Kamil return; 92658eb238fSKowalski, Kamil } 92758eb238fSKowalski, Kamil 9285968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 92958eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 9305968caeeSMarri Devender Rao 9315968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 932656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 933656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 9345968caeeSMarri Devender Rao if (ec) 9355968caeeSMarri Devender Rao { 9365968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 9375968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 9385968caeeSMarri Devender Rao return; 9395968caeeSMarri Devender Rao } 940656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 941656ec7e3SZbigniew Kurzynski if (certId < 0) 942656ec7e3SZbigniew Kurzynski { 943656ec7e3SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid objectPath value" 944656ec7e3SZbigniew Kurzynski << objectPath; 945656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 946656ec7e3SZbigniew Kurzynski return; 947656ec7e3SZbigniew Kurzynski } 9485968caeeSMarri Devender Rao std::string certURL = 9495968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/" 9505968caeeSMarri Devender Rao "Certificates/" + 9515968caeeSMarri Devender Rao std::to_string(certId); 95237cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 95337cce918SMarri Devender Rao certs::httpsServiceName, certId, 9545968caeeSMarri Devender Rao certURL, "HTTPS Certificate"); 9555968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 9565968caeeSMarri Devender Rao << certFile->getCertFilePath(); 9575968caeeSMarri Devender Rao }, 95837cce918SMarri Devender Rao certs::httpsServiceName, certs::httpsObjectPath, 95937cce918SMarri Devender Rao certs::certInstallIntf, "Install", certFile->getCertFilePath()); 9605968caeeSMarri Devender Rao } 9615968caeeSMarri Devender Rao }; // HTTPSCertificateCollection 9625968caeeSMarri Devender Rao 9635968caeeSMarri Devender Rao /** 9645968caeeSMarri Devender Rao * The certificate location schema defines a resource that an administrator 9655968caeeSMarri Devender Rao * can use in order to locate all certificates installed on a given service. 9665968caeeSMarri Devender Rao */ 9675968caeeSMarri Devender Rao class CertificateLocations : public Node 9685968caeeSMarri Devender Rao { 9695968caeeSMarri Devender Rao public: 97052cc112dSEd Tanous CertificateLocations(App& app) : 9715968caeeSMarri Devender Rao Node(app, "/redfish/v1/CertificateService/CertificateLocations/") 9725968caeeSMarri Devender Rao { 9735968caeeSMarri Devender Rao entityPrivileges = { 9745968caeeSMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 9755968caeeSMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 9765968caeeSMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 9775968caeeSMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 9785968caeeSMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 9795968caeeSMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 9805968caeeSMarri Devender Rao } 9815968caeeSMarri Devender Rao 9825968caeeSMarri Devender Rao private: 983cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 984cb13a392SEd Tanous const std::vector<std::string>&) override 9855968caeeSMarri Devender Rao { 9865968caeeSMarri Devender Rao res.jsonValue = { 9875968caeeSMarri Devender Rao {"@odata.id", 9885968caeeSMarri Devender Rao "/redfish/v1/CertificateService/CertificateLocations"}, 9895968caeeSMarri Devender Rao {"@odata.type", 9905968caeeSMarri Devender Rao "#CertificateLocations.v1_0_0.CertificateLocations"}, 9915968caeeSMarri Devender Rao {"Name", "Certificate Locations"}, 9925968caeeSMarri Devender Rao {"Id", "CertificateLocations"}, 9935968caeeSMarri Devender Rao {"Description", 9945968caeeSMarri Devender Rao "Defines a resource that an administrator can use in order to " 9955968caeeSMarri Devender Rao "locate all certificates installed on a given service"}}; 9965968caeeSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 9975968caeeSMarri Devender Rao nlohmann::json& links = 9985968caeeSMarri Devender Rao asyncResp->res.jsonValue["Links"]["Certificates"]; 9995968caeeSMarri Devender Rao links = nlohmann::json::array(); 10005968caeeSMarri Devender Rao getCertificateLocations( 10015968caeeSMarri Devender Rao asyncResp, 10025968caeeSMarri Devender Rao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/", 100337cce918SMarri Devender Rao certs::httpsObjectPath, certs::httpsServiceName); 100437cce918SMarri Devender Rao getCertificateLocations(asyncResp, 100537cce918SMarri Devender Rao "/redfish/v1/AccountService/LDAP/Certificates/", 100637cce918SMarri Devender Rao certs::ldapObjectPath, certs::ldapServiceName); 1007cfcd5f6bSMarri Devender Rao getCertificateLocations( 1008cfcd5f6bSMarri Devender Rao asyncResp, "/redfish/v1/Managers/bmc/Truststore/Certificates/", 1009cfcd5f6bSMarri Devender Rao certs::authorityObjectPath, certs::authorityServiceName); 101037cce918SMarri Devender Rao } 101137cce918SMarri Devender Rao /** 101237cce918SMarri Devender Rao * @brief Retrieve the certificates installed list and append to the 101337cce918SMarri Devender Rao * response 101437cce918SMarri Devender Rao * 101537cce918SMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 101637cce918SMarri Devender Rao * @param[in] certURL Path of the certificate object 101737cce918SMarri Devender Rao * @param[in] path Path of the D-Bus service object 101837cce918SMarri Devender Rao * @return None 101937cce918SMarri Devender Rao */ 102037cce918SMarri Devender Rao void getCertificateLocations(std::shared_ptr<AsyncResp>& asyncResp, 102137cce918SMarri Devender Rao const std::string& certURL, 102237cce918SMarri Devender Rao const std::string& path, 102337cce918SMarri Devender Rao const std::string& service) 102437cce918SMarri Devender Rao { 102537cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateLocations URI=" << certURL 102637cce918SMarri Devender Rao << " Path=" << path << " service= " << service; 102737cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 102837cce918SMarri Devender Rao [asyncResp, certURL](const boost::system::error_code ec, 102937cce918SMarri Devender Rao const ManagedObjectType& certs) { 103037cce918SMarri Devender Rao if (ec) 103137cce918SMarri Devender Rao { 1032*9c8e039eSJonathan Doman BMCWEB_LOG_WARNING 1033*9c8e039eSJonathan Doman << "Certificate collection query failed: " << ec 1034*9c8e039eSJonathan Doman << ", skipping " << certURL; 103537cce918SMarri Devender Rao return; 103637cce918SMarri Devender Rao } 103737cce918SMarri Devender Rao nlohmann::json& links = 103837cce918SMarri Devender Rao asyncResp->res.jsonValue["Links"]["Certificates"]; 103937cce918SMarri Devender Rao for (auto& cert : certs) 104037cce918SMarri Devender Rao { 104137cce918SMarri Devender Rao long id = getIDFromURL(cert.first.str); 104237cce918SMarri Devender Rao if (id >= 0) 104337cce918SMarri Devender Rao { 104437cce918SMarri Devender Rao links.push_back( 104537cce918SMarri Devender Rao {{"@odata.id", certURL + std::to_string(id)}}); 104637cce918SMarri Devender Rao } 104737cce918SMarri Devender Rao } 104837cce918SMarri Devender Rao asyncResp->res.jsonValue["Links"]["Certificates@odata.count"] = 104937cce918SMarri Devender Rao links.size(); 105037cce918SMarri Devender Rao }, 105137cce918SMarri Devender Rao service, path, certs::dbusObjManagerIntf, "GetManagedObjects"); 10525968caeeSMarri Devender Rao } 10535968caeeSMarri Devender Rao }; // CertificateLocations 105437cce918SMarri Devender Rao 105537cce918SMarri Devender Rao /** 105637cce918SMarri Devender Rao * Collection of LDAP certificates 105737cce918SMarri Devender Rao */ 105837cce918SMarri Devender Rao class LDAPCertificateCollection : public Node 105937cce918SMarri Devender Rao { 106037cce918SMarri Devender Rao public: 106152cc112dSEd Tanous LDAPCertificateCollection(App& app) : 106237cce918SMarri Devender Rao Node(app, "/redfish/v1/AccountService/LDAP/Certificates/") 106337cce918SMarri Devender Rao { 106437cce918SMarri Devender Rao entityPrivileges = { 106537cce918SMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 106637cce918SMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 106737cce918SMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 106837cce918SMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 106937cce918SMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 107037cce918SMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 107137cce918SMarri Devender Rao } 1072cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 1073cb13a392SEd Tanous const std::vector<std::string>&) override 107437cce918SMarri Devender Rao { 107537cce918SMarri Devender Rao res.jsonValue = { 107637cce918SMarri Devender Rao {"@odata.id", "/redfish/v1/AccountService/LDAP/Certificates"}, 107737cce918SMarri Devender Rao {"@odata.type", "#CertificateCollection.CertificateCollection"}, 107837cce918SMarri Devender Rao {"Name", "LDAP Certificates Collection"}, 107937cce918SMarri Devender Rao {"Description", "A Collection of LDAP certificate instances"}}; 108037cce918SMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 108137cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 108237cce918SMarri Devender Rao [asyncResp](const boost::system::error_code ec, 108337cce918SMarri Devender Rao const ManagedObjectType& certs) { 1084*9c8e039eSJonathan Doman nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 1085*9c8e039eSJonathan Doman nlohmann::json& count = 1086*9c8e039eSJonathan Doman asyncResp->res.jsonValue["Members@odata.count"]; 1087*9c8e039eSJonathan Doman members = nlohmann::json::array(); 1088*9c8e039eSJonathan Doman count = 0; 108937cce918SMarri Devender Rao if (ec) 109037cce918SMarri Devender Rao { 1091*9c8e039eSJonathan Doman BMCWEB_LOG_WARNING << "LDAP certificate query failed: " 1092*9c8e039eSJonathan Doman << ec; 109337cce918SMarri Devender Rao return; 109437cce918SMarri Devender Rao } 109537cce918SMarri Devender Rao for (const auto& cert : certs) 109637cce918SMarri Devender Rao { 109737cce918SMarri Devender Rao long id = getIDFromURL(cert.first.str); 109837cce918SMarri Devender Rao if (id >= 0) 109937cce918SMarri Devender Rao { 110037cce918SMarri Devender Rao members.push_back( 110137cce918SMarri Devender Rao {{"@odata.id", "/redfish/v1/AccountService/" 110237cce918SMarri Devender Rao "LDAP/Certificates/" + 110337cce918SMarri Devender Rao std::to_string(id)}}); 110437cce918SMarri Devender Rao } 110537cce918SMarri Devender Rao } 1106*9c8e039eSJonathan Doman count = members.size(); 110737cce918SMarri Devender Rao }, 110837cce918SMarri Devender Rao certs::ldapServiceName, certs::ldapObjectPath, 110937cce918SMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 111037cce918SMarri Devender Rao } 111137cce918SMarri Devender Rao 111237cce918SMarri Devender Rao void doPost(crow::Response& res, const crow::Request& req, 1113cb13a392SEd Tanous const std::vector<std::string>&) override 111437cce918SMarri Devender Rao { 111537cce918SMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 111658eb238fSKowalski, Kamil std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 111758eb238fSKowalski, Kamil 111858eb238fSKowalski, Kamil if (certFileBody.empty()) 111958eb238fSKowalski, Kamil { 1120a08752f5SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1121a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 112258eb238fSKowalski, Kamil return; 112358eb238fSKowalski, Kamil } 112458eb238fSKowalski, Kamil 112558eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 112658eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 112758eb238fSKowalski, Kamil 112837cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 1129656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1130656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 113137cce918SMarri Devender Rao if (ec) 113237cce918SMarri Devender Rao { 113337cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 113437cce918SMarri Devender Rao messages::internalError(asyncResp->res); 113537cce918SMarri Devender Rao return; 113637cce918SMarri Devender Rao } 1137656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 1138656ec7e3SZbigniew Kurzynski if (certId < 0) 1139656ec7e3SZbigniew Kurzynski { 1140656ec7e3SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid objectPath value" 1141656ec7e3SZbigniew Kurzynski << objectPath; 1142656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 1143656ec7e3SZbigniew Kurzynski return; 1144656ec7e3SZbigniew Kurzynski } 114537cce918SMarri Devender Rao std::string certURL = 114637cce918SMarri Devender Rao "/redfish/v1/AccountService/LDAP/Certificates/" + 114737cce918SMarri Devender Rao std::to_string(certId); 114837cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 114937cce918SMarri Devender Rao certs::ldapServiceName, certId, 115037cce918SMarri Devender Rao certURL, "LDAP Certificate"); 115137cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "LDAP certificate install file=" 115237cce918SMarri Devender Rao << certFile->getCertFilePath(); 115337cce918SMarri Devender Rao }, 115437cce918SMarri Devender Rao certs::ldapServiceName, certs::ldapObjectPath, 115537cce918SMarri Devender Rao certs::certInstallIntf, "Install", certFile->getCertFilePath()); 115637cce918SMarri Devender Rao } 115737cce918SMarri Devender Rao }; // LDAPCertificateCollection 115837cce918SMarri Devender Rao 115937cce918SMarri Devender Rao /** 116037cce918SMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 116137cce918SMarri Devender Rao * of a component, account or service. 116237cce918SMarri Devender Rao */ 116337cce918SMarri Devender Rao class LDAPCertificate : public Node 116437cce918SMarri Devender Rao { 116537cce918SMarri Devender Rao public: 116652cc112dSEd Tanous LDAPCertificate(App& app) : 116737cce918SMarri Devender Rao Node(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/", 116837cce918SMarri Devender Rao std::string()) 116937cce918SMarri Devender Rao { 117037cce918SMarri Devender Rao entityPrivileges = { 117137cce918SMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 117237cce918SMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 117337cce918SMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 117437cce918SMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 117537cce918SMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 117637cce918SMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 117737cce918SMarri Devender Rao } 117837cce918SMarri Devender Rao 117937cce918SMarri Devender Rao void doGet(crow::Response& res, const crow::Request& req, 1180cb13a392SEd Tanous const std::vector<std::string>&) override 118137cce918SMarri Devender Rao { 118237cce918SMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 118337cce918SMarri Devender Rao long id = getIDFromURL(req.url); 118437cce918SMarri Devender Rao if (id < 0) 118537cce918SMarri Devender Rao { 118637cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "Invalid url value" << req.url; 118737cce918SMarri Devender Rao messages::internalError(asyncResp->res); 118837cce918SMarri Devender Rao return; 118937cce918SMarri Devender Rao } 119037cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << std::to_string(id); 119137cce918SMarri Devender Rao std::string certURL = "/redfish/v1/AccountService/LDAP/Certificates/" + 119237cce918SMarri Devender Rao std::to_string(id); 119337cce918SMarri Devender Rao std::string objectPath = certs::ldapObjectPath; 119437cce918SMarri Devender Rao objectPath += "/"; 119537cce918SMarri Devender Rao objectPath += std::to_string(id); 119637cce918SMarri Devender Rao getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName, 119737cce918SMarri Devender Rao id, certURL, "LDAP Certificate"); 119837cce918SMarri Devender Rao } 119937cce918SMarri Devender Rao }; // LDAPCertificate 1200cfcd5f6bSMarri Devender Rao /** 1201cfcd5f6bSMarri Devender Rao * Collection of TrustStoreCertificate certificates 1202cfcd5f6bSMarri Devender Rao */ 1203cfcd5f6bSMarri Devender Rao class TrustStoreCertificateCollection : public Node 1204cfcd5f6bSMarri Devender Rao { 1205cfcd5f6bSMarri Devender Rao public: 120652cc112dSEd Tanous TrustStoreCertificateCollection(App& app) : 1207cfcd5f6bSMarri Devender Rao Node(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1208cfcd5f6bSMarri Devender Rao { 1209cfcd5f6bSMarri Devender Rao entityPrivileges = { 1210cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 1211cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 1212cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1213cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1214cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1215cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1216cfcd5f6bSMarri Devender Rao } 1217cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 1218cb13a392SEd Tanous const std::vector<std::string>&) override 1219cfcd5f6bSMarri Devender Rao { 1220cfcd5f6bSMarri Devender Rao res.jsonValue = { 1221cfcd5f6bSMarri Devender Rao {"@odata.id", "/redfish/v1/Managers/bmc/Truststore/Certificates/"}, 1222cfcd5f6bSMarri Devender Rao {"@odata.type", "#CertificateCollection.CertificateCollection"}, 1223cfcd5f6bSMarri Devender Rao {"Name", "TrustStore Certificates Collection"}, 1224cfcd5f6bSMarri Devender Rao {"Description", 1225cfcd5f6bSMarri Devender Rao "A Collection of TrustStore certificate instances"}}; 1226cfcd5f6bSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 1227cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1228cfcd5f6bSMarri Devender Rao [asyncResp](const boost::system::error_code ec, 1229cfcd5f6bSMarri Devender Rao const ManagedObjectType& certs) { 1230cfcd5f6bSMarri Devender Rao if (ec) 1231cfcd5f6bSMarri Devender Rao { 1232cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1233cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1234cfcd5f6bSMarri Devender Rao return; 1235cfcd5f6bSMarri Devender Rao } 1236cfcd5f6bSMarri Devender Rao nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 1237cfcd5f6bSMarri Devender Rao members = nlohmann::json::array(); 1238cfcd5f6bSMarri Devender Rao for (const auto& cert : certs) 1239cfcd5f6bSMarri Devender Rao { 1240cfcd5f6bSMarri Devender Rao long id = getIDFromURL(cert.first.str); 1241cfcd5f6bSMarri Devender Rao if (id >= 0) 1242cfcd5f6bSMarri Devender Rao { 1243cfcd5f6bSMarri Devender Rao members.push_back( 1244cfcd5f6bSMarri Devender Rao {{"@odata.id", "/redfish/v1/Managers/bmc/" 1245cfcd5f6bSMarri Devender Rao "Truststore/Certificates/" + 1246cfcd5f6bSMarri Devender Rao std::to_string(id)}}); 1247cfcd5f6bSMarri Devender Rao } 1248cfcd5f6bSMarri Devender Rao } 1249cfcd5f6bSMarri Devender Rao asyncResp->res.jsonValue["Members@odata.count"] = 1250cfcd5f6bSMarri Devender Rao members.size(); 1251cfcd5f6bSMarri Devender Rao }, 1252cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 1253cfcd5f6bSMarri Devender Rao certs::dbusObjManagerIntf, "GetManagedObjects"); 1254cfcd5f6bSMarri Devender Rao } 1255cfcd5f6bSMarri Devender Rao 1256cfcd5f6bSMarri Devender Rao void doPost(crow::Response& res, const crow::Request& req, 1257cb13a392SEd Tanous const std::vector<std::string>&) override 1258cfcd5f6bSMarri Devender Rao { 1259cfcd5f6bSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 1260a08752f5SZbigniew Kurzynski std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 1261a08752f5SZbigniew Kurzynski 1262a08752f5SZbigniew Kurzynski if (certFileBody.empty()) 1263a08752f5SZbigniew Kurzynski { 1264a08752f5SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1265a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1266a08752f5SZbigniew Kurzynski return; 1267a08752f5SZbigniew Kurzynski } 1268a08752f5SZbigniew Kurzynski 1269a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1270a08752f5SZbigniew Kurzynski std::make_shared<CertificateFile>(certFileBody); 1271cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1272656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1273656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1274cfcd5f6bSMarri Devender Rao if (ec) 1275cfcd5f6bSMarri Devender Rao { 1276cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1277cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1278cfcd5f6bSMarri Devender Rao return; 1279cfcd5f6bSMarri Devender Rao } 1280656ec7e3SZbigniew Kurzynski long certId = getIDFromURL(objectPath); 1281656ec7e3SZbigniew Kurzynski if (certId < 0) 1282656ec7e3SZbigniew Kurzynski { 1283656ec7e3SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid objectPath value" 1284656ec7e3SZbigniew Kurzynski << objectPath; 1285656ec7e3SZbigniew Kurzynski messages::internalError(asyncResp->res); 1286656ec7e3SZbigniew Kurzynski return; 1287656ec7e3SZbigniew Kurzynski } 1288cfcd5f6bSMarri Devender Rao std::string certURL = "/redfish/v1/Managers/bmc/" 1289cfcd5f6bSMarri Devender Rao "Truststore/Certificates/" + 1290cfcd5f6bSMarri Devender Rao std::to_string(certId); 1291656ec7e3SZbigniew Kurzynski 1292cfcd5f6bSMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 1293cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certId, 1294cfcd5f6bSMarri Devender Rao certURL, "TrustStore Certificate"); 1295cfcd5f6bSMarri Devender Rao BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" 1296cfcd5f6bSMarri Devender Rao << certFile->getCertFilePath(); 1297cfcd5f6bSMarri Devender Rao }, 1298cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 1299cfcd5f6bSMarri Devender Rao certs::certInstallIntf, "Install", certFile->getCertFilePath()); 1300cfcd5f6bSMarri Devender Rao } 1301cfcd5f6bSMarri Devender Rao }; // TrustStoreCertificateCollection 1302cfcd5f6bSMarri Devender Rao 1303cfcd5f6bSMarri Devender Rao /** 1304cfcd5f6bSMarri Devender Rao * Certificate resource describes a certificate used to prove the identity 1305cfcd5f6bSMarri Devender Rao * of a component, account or service. 1306cfcd5f6bSMarri Devender Rao */ 1307cfcd5f6bSMarri Devender Rao class TrustStoreCertificate : public Node 1308cfcd5f6bSMarri Devender Rao { 1309cfcd5f6bSMarri Devender Rao public: 131052cc112dSEd Tanous TrustStoreCertificate(App& app) : 1311cfcd5f6bSMarri Devender Rao Node(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/", 1312cfcd5f6bSMarri Devender Rao std::string()) 1313cfcd5f6bSMarri Devender Rao { 1314cfcd5f6bSMarri Devender Rao entityPrivileges = { 1315cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::get, {{"Login"}}}, 1316cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::head, {{"Login"}}}, 1317cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1318cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1319cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1320cfcd5f6bSMarri Devender Rao {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1321cfcd5f6bSMarri Devender Rao } 1322cfcd5f6bSMarri Devender Rao 1323cfcd5f6bSMarri Devender Rao void doGet(crow::Response& res, const crow::Request& req, 1324cb13a392SEd Tanous const std::vector<std::string>&) override 1325cfcd5f6bSMarri Devender Rao { 1326cfcd5f6bSMarri Devender Rao auto asyncResp = std::make_shared<AsyncResp>(res); 1327cfcd5f6bSMarri Devender Rao long id = getIDFromURL(req.url); 1328cfcd5f6bSMarri Devender Rao if (id < 0) 1329cfcd5f6bSMarri Devender Rao { 1330cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "Invalid url value" << req.url; 1331cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1332cfcd5f6bSMarri Devender Rao return; 1333cfcd5f6bSMarri Devender Rao } 1334cfcd5f6bSMarri Devender Rao BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doGet ID=" 1335cfcd5f6bSMarri Devender Rao << std::to_string(id); 1336cfcd5f6bSMarri Devender Rao std::string certURL = 1337cfcd5f6bSMarri Devender Rao "/redfish/v1/Managers/bmc/Truststore/Certificates/" + 1338cfcd5f6bSMarri Devender Rao std::to_string(id); 1339cfcd5f6bSMarri Devender Rao std::string objectPath = certs::authorityObjectPath; 1340cfcd5f6bSMarri Devender Rao objectPath += "/"; 1341cfcd5f6bSMarri Devender Rao objectPath += std::to_string(id); 1342cfcd5f6bSMarri Devender Rao getCertificateProperties(asyncResp, objectPath, 1343cfcd5f6bSMarri Devender Rao certs::authorityServiceName, id, certURL, 1344cfcd5f6bSMarri Devender Rao "TrustStore Certificate"); 1345cfcd5f6bSMarri Devender Rao } 134607a60299SZbigniew Kurzynski 134707a60299SZbigniew Kurzynski void doDelete(crow::Response& res, const crow::Request& req, 134807a60299SZbigniew Kurzynski const std::vector<std::string>& params) override 134907a60299SZbigniew Kurzynski { 135007a60299SZbigniew Kurzynski auto asyncResp = std::make_shared<AsyncResp>(res); 135107a60299SZbigniew Kurzynski 135207a60299SZbigniew Kurzynski if (params.size() != 1) 135307a60299SZbigniew Kurzynski { 135407a60299SZbigniew Kurzynski messages::internalError(asyncResp->res); 135507a60299SZbigniew Kurzynski return; 135607a60299SZbigniew Kurzynski } 135707a60299SZbigniew Kurzynski 135807a60299SZbigniew Kurzynski long id = getIDFromURL(req.url); 135907a60299SZbigniew Kurzynski if (id < 0) 136007a60299SZbigniew Kurzynski { 136107a60299SZbigniew Kurzynski BMCWEB_LOG_ERROR << "Invalid url value: " << req.url; 136207a60299SZbigniew Kurzynski messages::resourceNotFound(asyncResp->res, "TrustStore Certificate", 136307a60299SZbigniew Kurzynski std::string(req.url)); 136407a60299SZbigniew Kurzynski return; 136507a60299SZbigniew Kurzynski } 136607a60299SZbigniew Kurzynski BMCWEB_LOG_DEBUG << "TrustStoreCertificate::doDelete ID=" 136707a60299SZbigniew Kurzynski << std::to_string(id); 136807a60299SZbigniew Kurzynski std::string certPath = certs::authorityObjectPath; 136907a60299SZbigniew Kurzynski certPath += "/"; 137007a60299SZbigniew Kurzynski certPath += std::to_string(id); 137107a60299SZbigniew Kurzynski 137207a60299SZbigniew Kurzynski crow::connections::systemBus->async_method_call( 137307a60299SZbigniew Kurzynski [asyncResp, id](const boost::system::error_code ec) { 137407a60299SZbigniew Kurzynski if (ec) 137507a60299SZbigniew Kurzynski { 137607a60299SZbigniew Kurzynski messages::resourceNotFound(asyncResp->res, 137707a60299SZbigniew Kurzynski "TrustStore Certificate", 137807a60299SZbigniew Kurzynski std::to_string(id)); 137907a60299SZbigniew Kurzynski return; 138007a60299SZbigniew Kurzynski } 138107a60299SZbigniew Kurzynski BMCWEB_LOG_INFO << "Certificate deleted"; 138207a60299SZbigniew Kurzynski asyncResp->res.result(boost::beast::http::status::no_content); 138307a60299SZbigniew Kurzynski }, 138407a60299SZbigniew Kurzynski certs::authorityServiceName, certPath, certs::objDeleteIntf, 138507a60299SZbigniew Kurzynski "Delete"); 138607a60299SZbigniew Kurzynski } 1387cfcd5f6bSMarri Devender Rao }; // TrustStoreCertificate 13885968caeeSMarri Devender Rao } // namespace redfish 1389