15968caeeSMarri Devender Rao #pragma once 25968caeeSMarri Devender Rao 33ccb3adbSEd Tanous #include "app.hpp" 43ccb3adbSEd Tanous #include "async_resp.hpp" 57a1dbc48SGeorge Liu #include "dbus_utility.hpp" 61aa0c2b8SEd Tanous #include "http/parsing.hpp" 73ccb3adbSEd Tanous #include "http_response.hpp" 83ccb3adbSEd Tanous #include "query.hpp" 93ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 109b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp" 113ccb3adbSEd Tanous #include "utils/json_utils.hpp" 123ccb3adbSEd Tanous #include "utils/time_utils.hpp" 139b12d1f9SKrzysztof Grobelny 1490d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp> 15ef4c65b7SEd Tanous #include <boost/url/format.hpp> 169b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 173ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp> 189b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 191214b7e7SGunnar Mills 207a1dbc48SGeorge Liu #include <array> 213ccb3adbSEd Tanous #include <memory> 227a1dbc48SGeorge Liu #include <string_view> 237a1dbc48SGeorge Liu 245968caeeSMarri Devender Rao namespace redfish 255968caeeSMarri Devender Rao { 265968caeeSMarri Devender Rao namespace certs 275968caeeSMarri Devender Rao { 2889492a15SPatrick Williams constexpr const char* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 2989492a15SPatrick Williams constexpr const char* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 3089492a15SPatrick Williams constexpr const char* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 3189492a15SPatrick Williams constexpr const char* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 3289492a15SPatrick Williams constexpr const char* dbusPropIntf = "org.freedesktop.DBus.Properties"; 3389492a15SPatrick Williams constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 3489492a15SPatrick Williams constexpr const char* httpsServiceName = 3537cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Server.Https"; 3689492a15SPatrick Williams constexpr const char* ldapServiceName = 3737cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 3889492a15SPatrick Williams constexpr const char* authorityServiceName = 39cfcd5f6bSMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Authority.Ldap"; 4089492a15SPatrick Williams constexpr const char* baseObjectPath = "/xyz/openbmc_project/certs"; 4189492a15SPatrick Williams constexpr const char* httpsObjectPath = 42c6a8dfb1SJiaqing Zhao "/xyz/openbmc_project/certs/server/https"; 4389492a15SPatrick Williams constexpr const char* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 4489492a15SPatrick Williams constexpr const char* authorityObjectPath = 45cfcd5f6bSMarri Devender Rao "/xyz/openbmc_project/certs/authority/ldap"; 465968caeeSMarri Devender Rao } // namespace certs 475968caeeSMarri Devender Rao 485968caeeSMarri Devender Rao /** 495968caeeSMarri Devender Rao * The Certificate schema defines a Certificate Service which represents the 505968caeeSMarri Devender Rao * actions available to manage certificates and links to where certificates 515968caeeSMarri Devender Rao * are installed. 525968caeeSMarri Devender Rao */ 537e860f15SJohn Edward Broadbent 548d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody( 558d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5658eb238fSKowalski, Kamil const crow::Request& req) 5758eb238fSKowalski, Kamil { 581aa0c2b8SEd Tanous nlohmann::json reqJson; 591aa0c2b8SEd Tanous JsonParseResult ret = parseRequestAsJson(req, reqJson); 601aa0c2b8SEd Tanous if (ret != JsonParseResult::Success) 6158eb238fSKowalski, Kamil { 6258eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 6333c6b580SEd Tanous return req.body(); 6458eb238fSKowalski, Kamil } 6558eb238fSKowalski, Kamil 6658eb238fSKowalski, Kamil std::string certificate; 6758eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 6858eb238fSKowalski, Kamil 6915ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString", 7015ed6780SWilly Tu certificate, "CertificateType", 7115ed6780SWilly Tu certificateType)) 7258eb238fSKowalski, Kamil { 7358eb238fSKowalski, Kamil BMCWEB_LOG_ERROR << "Required parameters are missing"; 7458eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 75abb93cddSEd Tanous return {}; 7658eb238fSKowalski, Kamil } 7758eb238fSKowalski, Kamil 7858eb238fSKowalski, Kamil if (*certificateType != "PEM") 7958eb238fSKowalski, Kamil { 8058eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 8158eb238fSKowalski, Kamil "CertificateType"); 82abb93cddSEd Tanous return {}; 8358eb238fSKowalski, Kamil } 8458eb238fSKowalski, Kamil 8558eb238fSKowalski, Kamil return certificate; 8658eb238fSKowalski, Kamil } 8758eb238fSKowalski, Kamil 885968caeeSMarri Devender Rao /** 895968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 905968caeeSMarri Devender Rao */ 915968caeeSMarri Devender Rao class CertificateFile 925968caeeSMarri Devender Rao { 935968caeeSMarri Devender Rao public: 945968caeeSMarri Devender Rao CertificateFile() = delete; 955968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 965968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 975968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 985968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 994e23a444SEd Tanous explicit CertificateFile(const std::string& certString) 1005968caeeSMarri Devender Rao { 10172d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 1025207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 1035207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 1045207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 105e662eae8SEd Tanous if (tempDirectory != nullptr) 1065968caeeSMarri Devender Rao { 1075968caeeSMarri Devender Rao certDirectory = tempDirectory; 1085968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 1095968caeeSMarri Devender Rao std::ofstream out(certificateFile, std::ofstream::out | 1105968caeeSMarri Devender Rao std::ofstream::binary | 1115968caeeSMarri Devender Rao std::ofstream::trunc); 1125968caeeSMarri Devender Rao out << certString; 1135968caeeSMarri Devender Rao out.close(); 1148cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Creating certificate file" 1158cc8edecSEd Tanous << certificateFile.string(); 1165968caeeSMarri Devender Rao } 1175968caeeSMarri Devender Rao } 1185968caeeSMarri Devender Rao ~CertificateFile() 1195968caeeSMarri Devender Rao { 1205968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1215968caeeSMarri Devender Rao { 1228cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Removing certificate file" 1238cc8edecSEd Tanous << certificateFile.string(); 12423a21a1cSEd Tanous std::error_code ec; 12523a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 12623a21a1cSEd Tanous if (ec) 1275968caeeSMarri Devender Rao { 1285968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Failed to remove temp directory" 1298cc8edecSEd Tanous << certDirectory.string(); 1305968caeeSMarri Devender Rao } 1315968caeeSMarri Devender Rao } 1325968caeeSMarri Devender Rao } 1335968caeeSMarri Devender Rao std::string getCertFilePath() 1345968caeeSMarri Devender Rao { 1355968caeeSMarri Devender Rao return certificateFile; 1365968caeeSMarri Devender Rao } 1375968caeeSMarri Devender Rao 1385968caeeSMarri Devender Rao private: 1395968caeeSMarri Devender Rao std::filesystem::path certificateFile; 1405968caeeSMarri Devender Rao std::filesystem::path certDirectory; 1415968caeeSMarri Devender Rao }; 1425968caeeSMarri Devender Rao 1435968caeeSMarri Devender Rao /** 1444e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 1455968caeeSMarri Devender Rao * 1465968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 1475968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 1485968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 1495968caeeSMarri Devender Rao * @return None 1505968caeeSMarri Devender Rao */ 1515968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out, 15226ccae32SEd Tanous std::string_view value) 1535968caeeSMarri Devender Rao { 1545968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 1555968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 1565968caeeSMarri Devender Rao while (i != value.end()) 1575968caeeSMarri Devender Rao { 1585968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 1595968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 1605968caeeSMarri Devender Rao { 1616da47babSPatrick Williams std::advance(i, 1); 1625968caeeSMarri Devender Rao } 1635968caeeSMarri Devender Rao if (i == value.end()) 1645968caeeSMarri Devender Rao { 1655968caeeSMarri Devender Rao break; 1665968caeeSMarri Devender Rao } 16726ccae32SEd Tanous std::string_view key(tokenBegin, static_cast<size_t>(i - tokenBegin)); 1686da47babSPatrick Williams std::advance(i, 1); 1695968caeeSMarri Devender Rao tokenBegin = i; 1705968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 1715968caeeSMarri Devender Rao { 1726da47babSPatrick Williams std::advance(i, 1); 1735968caeeSMarri Devender Rao } 17426ccae32SEd Tanous std::string_view val(tokenBegin, static_cast<size_t>(i - tokenBegin)); 1755968caeeSMarri Devender Rao if (key == "L") 1765968caeeSMarri Devender Rao { 1775968caeeSMarri Devender Rao out["City"] = val; 1785968caeeSMarri Devender Rao } 1795968caeeSMarri Devender Rao else if (key == "CN") 1805968caeeSMarri Devender Rao { 1815968caeeSMarri Devender Rao out["CommonName"] = val; 1825968caeeSMarri Devender Rao } 1835968caeeSMarri Devender Rao else if (key == "C") 1845968caeeSMarri Devender Rao { 1855968caeeSMarri Devender Rao out["Country"] = val; 1865968caeeSMarri Devender Rao } 1875968caeeSMarri Devender Rao else if (key == "O") 1885968caeeSMarri Devender Rao { 1895968caeeSMarri Devender Rao out["Organization"] = val; 1905968caeeSMarri Devender Rao } 1915968caeeSMarri Devender Rao else if (key == "OU") 1925968caeeSMarri Devender Rao { 1935968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 1945968caeeSMarri Devender Rao } 1955968caeeSMarri Devender Rao else if (key == "ST") 1965968caeeSMarri Devender Rao { 1975968caeeSMarri Devender Rao out["State"] = val; 1985968caeeSMarri Devender Rao } 1995968caeeSMarri Devender Rao // skip comma character 2005968caeeSMarri Devender Rao if (i != value.end()) 2015968caeeSMarri Devender Rao { 2026da47babSPatrick Williams std::advance(i, 1); 2035968caeeSMarri Devender Rao } 2045968caeeSMarri Devender Rao } 2055968caeeSMarri Devender Rao } 2065968caeeSMarri Devender Rao 2075968caeeSMarri Devender Rao /** 208d3f92ce7SJiaqing Zhao * @brief Retrieve the installed certificate list 209d3f92ce7SJiaqing Zhao * 210d3f92ce7SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 211d3f92ce7SJiaqing Zhao * @param[in] basePath DBus object path to search 212d3f92ce7SJiaqing Zhao * @param[in] listPtr Json pointer to the list in asyncResp 213d3f92ce7SJiaqing Zhao * @param[in] countPtr Json pointer to the count in asyncResp 214d3f92ce7SJiaqing Zhao * @return None 215d3f92ce7SJiaqing Zhao */ 216d3f92ce7SJiaqing Zhao static void 217d3f92ce7SJiaqing Zhao getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 218d3f92ce7SJiaqing Zhao const std::string& basePath, 219d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& listPtr, 220d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& countPtr) 221d3f92ce7SJiaqing Zhao { 2227a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 2237a1dbc48SGeorge Liu certs::certPropIntf}; 2247a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 2257a1dbc48SGeorge Liu basePath, 0, interfaces, 226d3f92ce7SJiaqing Zhao [asyncResp, listPtr, countPtr]( 2277a1dbc48SGeorge Liu const boost::system::error_code& ec, 228d3f92ce7SJiaqing Zhao const dbus::utility::MapperGetSubTreePathsResponse& certPaths) { 229d3f92ce7SJiaqing Zhao if (ec) 230d3f92ce7SJiaqing Zhao { 231d3f92ce7SJiaqing Zhao BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec; 232d3f92ce7SJiaqing Zhao messages::internalError(asyncResp->res); 233d3f92ce7SJiaqing Zhao return; 234d3f92ce7SJiaqing Zhao } 235d3f92ce7SJiaqing Zhao 236d3f92ce7SJiaqing Zhao nlohmann::json& links = asyncResp->res.jsonValue[listPtr]; 237d3f92ce7SJiaqing Zhao links = nlohmann::json::array(); 238d3f92ce7SJiaqing Zhao for (const auto& certPath : certPaths) 239d3f92ce7SJiaqing Zhao { 240d3f92ce7SJiaqing Zhao sdbusplus::message::object_path objPath(certPath); 241d3f92ce7SJiaqing Zhao std::string certId = objPath.filename(); 242d3f92ce7SJiaqing Zhao if (certId.empty()) 243d3f92ce7SJiaqing Zhao { 244d3f92ce7SJiaqing Zhao BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath; 245d3f92ce7SJiaqing Zhao continue; 246d3f92ce7SJiaqing Zhao } 247d3f92ce7SJiaqing Zhao 248d3f92ce7SJiaqing Zhao boost::urls::url certURL; 249d3f92ce7SJiaqing Zhao if (objPath.parent_path() == certs::httpsObjectPath) 250d3f92ce7SJiaqing Zhao { 251ef4c65b7SEd Tanous certURL = boost::urls::format( 252ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}", 253ef4c65b7SEd Tanous certId); 254d3f92ce7SJiaqing Zhao } 255d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::ldapObjectPath) 256d3f92ce7SJiaqing Zhao { 257ef4c65b7SEd Tanous certURL = boost::urls::format( 258ef4c65b7SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/{}", certId); 259d3f92ce7SJiaqing Zhao } 260d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::authorityObjectPath) 261d3f92ce7SJiaqing Zhao { 262ef4c65b7SEd Tanous certURL = boost::urls::format( 263ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", 264ef4c65b7SEd Tanous certId); 265d3f92ce7SJiaqing Zhao } 266d3f92ce7SJiaqing Zhao else 267d3f92ce7SJiaqing Zhao { 268d3f92ce7SJiaqing Zhao continue; 269d3f92ce7SJiaqing Zhao } 270d3f92ce7SJiaqing Zhao 271d3f92ce7SJiaqing Zhao nlohmann::json::object_t link; 272d3f92ce7SJiaqing Zhao link["@odata.id"] = certURL; 273d3f92ce7SJiaqing Zhao links.emplace_back(std::move(link)); 274d3f92ce7SJiaqing Zhao } 275d3f92ce7SJiaqing Zhao 276d3f92ce7SJiaqing Zhao asyncResp->res.jsonValue[countPtr] = links.size(); 2777a1dbc48SGeorge Liu }); 278d3f92ce7SJiaqing Zhao } 279d3f92ce7SJiaqing Zhao 280d3f92ce7SJiaqing Zhao /** 2815968caeeSMarri Devender Rao * @brief Retrieve the certificates properties and append to the response 2825968caeeSMarri Devender Rao * message 2835968caeeSMarri Devender Rao * 2845968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 2855968caeeSMarri Devender Rao * @param[in] objectPath Path of the D-Bus service object 2865968caeeSMarri Devender Rao * @param[in] certId Id of the certificate 2875968caeeSMarri Devender Rao * @param[in] certURL URL of the certificate object 2885968caeeSMarri Devender Rao * @param[in] name name of the certificate 2895968caeeSMarri Devender Rao * @return None 2905968caeeSMarri Devender Rao */ 2915968caeeSMarri Devender Rao static void getCertificateProperties( 2928d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 293e19e97e2SJiaqing Zhao const std::string& objectPath, const std::string& service, 2941e312598SJiaqing Zhao const std::string& certId, const boost::urls::url& certURL, 295e19e97e2SJiaqing Zhao const std::string& name) 2965968caeeSMarri Devender Rao { 2975968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath 2985968caeeSMarri Devender Rao << " certId=" << certId << " certURl=" << certURL; 2999b12d1f9SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 3009b12d1f9SKrzysztof Grobelny *crow::connections::systemBus, service, objectPath, certs::certPropIntf, 301b9d36b47SEd Tanous [asyncResp, certURL, certId, 3025e7e2dc5SEd Tanous name](const boost::system::error_code& ec, 303b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& properties) { 3045968caeeSMarri Devender Rao if (ec) 3055968caeeSMarri Devender Rao { 3065968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 307d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", certId); 3085968caeeSMarri Devender Rao return; 3095968caeeSMarri Devender Rao } 3109b12d1f9SKrzysztof Grobelny 3119b12d1f9SKrzysztof Grobelny const std::string* certificateString = nullptr; 3129b12d1f9SKrzysztof Grobelny const std::vector<std::string>* keyUsage = nullptr; 3139b12d1f9SKrzysztof Grobelny const std::string* issuer = nullptr; 3149b12d1f9SKrzysztof Grobelny const std::string* subject = nullptr; 3159b12d1f9SKrzysztof Grobelny const uint64_t* validNotAfter = nullptr; 3169b12d1f9SKrzysztof Grobelny const uint64_t* validNotBefore = nullptr; 3179b12d1f9SKrzysztof Grobelny 3189b12d1f9SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 3199b12d1f9SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "CertificateString", 3209b12d1f9SKrzysztof Grobelny certificateString, "KeyUsage", keyUsage, "Issuer", issuer, 3219b12d1f9SKrzysztof Grobelny "Subject", subject, "ValidNotAfter", validNotAfter, 3229b12d1f9SKrzysztof Grobelny "ValidNotBefore", validNotBefore); 3239b12d1f9SKrzysztof Grobelny 3249b12d1f9SKrzysztof Grobelny if (!success) 3259b12d1f9SKrzysztof Grobelny { 3269b12d1f9SKrzysztof Grobelny messages::internalError(asyncResp->res); 3279b12d1f9SKrzysztof Grobelny return; 3289b12d1f9SKrzysztof Grobelny } 3299b12d1f9SKrzysztof Grobelny 3301476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = certURL; 3311476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3321476687dSEd Tanous "#Certificate.v1_0_0.Certificate"; 333e19e97e2SJiaqing Zhao asyncResp->res.jsonValue["Id"] = certId; 3341476687dSEd Tanous asyncResp->res.jsonValue["Name"] = name; 3351476687dSEd Tanous asyncResp->res.jsonValue["Description"] = name; 3365968caeeSMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = ""; 3379b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array(); 3389b12d1f9SKrzysztof Grobelny 3399b12d1f9SKrzysztof Grobelny if (certificateString != nullptr) 3405968caeeSMarri Devender Rao { 3419b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["CertificateString"] = *certificateString; 3425968caeeSMarri Devender Rao } 3439b12d1f9SKrzysztof Grobelny 3449b12d1f9SKrzysztof Grobelny if (keyUsage != nullptr) 3455968caeeSMarri Devender Rao { 3469b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = *keyUsage; 3475968caeeSMarri Devender Rao } 3489b12d1f9SKrzysztof Grobelny 3499b12d1f9SKrzysztof Grobelny if (issuer != nullptr) 3505968caeeSMarri Devender Rao { 3519b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"], 3529b12d1f9SKrzysztof Grobelny *issuer); 3535968caeeSMarri Devender Rao } 3549b12d1f9SKrzysztof Grobelny 3559b12d1f9SKrzysztof Grobelny if (subject != nullptr) 3565968caeeSMarri Devender Rao { 3579b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"], 3589b12d1f9SKrzysztof Grobelny *subject); 3595968caeeSMarri Devender Rao } 3609b12d1f9SKrzysztof Grobelny 3619b12d1f9SKrzysztof Grobelny if (validNotAfter != nullptr) 3625968caeeSMarri Devender Rao { 3635968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotAfter"] = 3649b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotAfter); 3655968caeeSMarri Devender Rao } 3669b12d1f9SKrzysztof Grobelny 3679b12d1f9SKrzysztof Grobelny if (validNotBefore != nullptr) 3685968caeeSMarri Devender Rao { 3695968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotBefore"] = 3709b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotBefore); 3715968caeeSMarri Devender Rao } 3729b12d1f9SKrzysztof Grobelny 3731e312598SJiaqing Zhao asyncResp->res.addHeader( 374d9f6c621SEd Tanous boost::beast::http::field::location, 375d9f6c621SEd Tanous std::string_view(certURL.data(), certURL.size())); 3769b12d1f9SKrzysztof Grobelny }); 3775968caeeSMarri Devender Rao } 3785968caeeSMarri Devender Rao 3797a3a8f7aSJiaqing Zhao static void 3807a3a8f7aSJiaqing Zhao deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3817a3a8f7aSJiaqing Zhao const std::string& service, 3827a3a8f7aSJiaqing Zhao const sdbusplus::message::object_path& objectPath) 3837a3a8f7aSJiaqing Zhao { 3847a3a8f7aSJiaqing Zhao crow::connections::systemBus->async_method_call( 3857a3a8f7aSJiaqing Zhao [asyncResp, 3865e7e2dc5SEd Tanous id{objectPath.filename()}](const boost::system::error_code& ec) { 3877a3a8f7aSJiaqing Zhao if (ec) 3887a3a8f7aSJiaqing Zhao { 3897a3a8f7aSJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 3907a3a8f7aSJiaqing Zhao return; 3917a3a8f7aSJiaqing Zhao } 3927a3a8f7aSJiaqing Zhao BMCWEB_LOG_INFO << "Certificate deleted"; 3937a3a8f7aSJiaqing Zhao asyncResp->res.result(boost::beast::http::status::no_content); 3947a3a8f7aSJiaqing Zhao }, 3957a3a8f7aSJiaqing Zhao service, objectPath, certs::objDeleteIntf, "Delete"); 3967a3a8f7aSJiaqing Zhao } 3977a3a8f7aSJiaqing Zhao 398828252d5SJiaqing Zhao inline void handleCertificateServiceGet( 399828252d5SJiaqing Zhao App& app, const crow::Request& req, 400828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 4015968caeeSMarri Devender Rao { 402828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 403828252d5SJiaqing Zhao { 404828252d5SJiaqing Zhao return; 405828252d5SJiaqing Zhao } 406828252d5SJiaqing Zhao 4073e72c202SNinad Palsule if (req.session == nullptr) 4083e72c202SNinad Palsule { 4093e72c202SNinad Palsule messages::internalError(asyncResp->res); 4103e72c202SNinad Palsule return; 4113e72c202SNinad Palsule } 4123e72c202SNinad Palsule 413828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 414828252d5SJiaqing Zhao "#CertificateService.v1_0_0.CertificateService"; 415828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService"; 416828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateService"; 417828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Service"; 418828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 419828252d5SJiaqing Zhao "Actions available to manage certificates"; 420828252d5SJiaqing Zhao // /redfish/v1/CertificateService/CertificateLocations is something 421828252d5SJiaqing Zhao // only ConfigureManager can access then only display when the user 422828252d5SJiaqing Zhao // has permissions ConfigureManager 423828252d5SJiaqing Zhao Privileges effectiveUserPrivileges = 4243e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 425828252d5SJiaqing Zhao if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 426828252d5SJiaqing Zhao effectiveUserPrivileges)) 427828252d5SJiaqing Zhao { 428828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = 429828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 430828252d5SJiaqing Zhao } 431828252d5SJiaqing Zhao nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; 432828252d5SJiaqing Zhao nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"]; 433828252d5SJiaqing Zhao replace["target"] = 434828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; 435828252d5SJiaqing Zhao nlohmann::json::array_t allowed; 436ad539545SPatrick Williams allowed.emplace_back("PEM"); 437828252d5SJiaqing Zhao replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); 438828252d5SJiaqing Zhao actions["#CertificateService.GenerateCSR"]["target"] = 439828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; 440828252d5SJiaqing Zhao } 441828252d5SJiaqing Zhao 442828252d5SJiaqing Zhao inline void handleCertificateLocationsGet( 443828252d5SJiaqing Zhao App& app, const crow::Request& req, 444828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 445828252d5SJiaqing Zhao { 446828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 447828252d5SJiaqing Zhao { 448828252d5SJiaqing Zhao return; 449828252d5SJiaqing Zhao } 450828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = 451828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 452828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 453828252d5SJiaqing Zhao "#CertificateLocations.v1_0_0.CertificateLocations"; 454828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Locations"; 455828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateLocations"; 456828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 457828252d5SJiaqing Zhao "Defines a resource that an administrator can use in order to " 458828252d5SJiaqing Zhao "locate all certificates installed on a given service"; 459828252d5SJiaqing Zhao 460828252d5SJiaqing Zhao getCertificateList(asyncResp, certs::baseObjectPath, 461828252d5SJiaqing Zhao "/Links/Certificates"_json_pointer, 462828252d5SJiaqing Zhao "/Links/Certificates@odata.count"_json_pointer); 463828252d5SJiaqing Zhao } 464828252d5SJiaqing Zhao 465828252d5SJiaqing Zhao inline void handleReplaceCertificateAction( 466828252d5SJiaqing Zhao App& app, const crow::Request& req, 467828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 468828252d5SJiaqing Zhao { 4693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 47045ca1b86SEd Tanous { 47145ca1b86SEd Tanous return; 47245ca1b86SEd Tanous } 4735968caeeSMarri Devender Rao std::string certificate; 4745968caeeSMarri Devender Rao nlohmann::json certificateUri; 4755968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 4768d1b46d7Szhanghch05 477002d39b4SEd Tanous if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString", 478002d39b4SEd Tanous certificate, "CertificateUri", 479002d39b4SEd Tanous certificateUri, "CertificateType", 480002d39b4SEd Tanous certificateType)) 4815968caeeSMarri Devender Rao { 4825968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Required parameters are missing"; 4835968caeeSMarri Devender Rao return; 4845968caeeSMarri Devender Rao } 4855968caeeSMarri Devender Rao 4865968caeeSMarri Devender Rao if (!certificateType) 4875968caeeSMarri Devender Rao { 4885968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 4895968caeeSMarri Devender Rao return; 4905968caeeSMarri Devender Rao } 4915968caeeSMarri Devender Rao if (certificateType != "PEM") 4925968caeeSMarri Devender Rao { 493828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateType", 494828252d5SJiaqing Zhao "ReplaceCertificate"); 4955968caeeSMarri Devender Rao return; 4965968caeeSMarri Devender Rao } 4975968caeeSMarri Devender Rao 4985968caeeSMarri Devender Rao std::string certURI; 4995968caeeSMarri Devender Rao if (!redfish::json_util::readJson(certificateUri, asyncResp->res, 5005968caeeSMarri Devender Rao "@odata.id", certURI)) 5015968caeeSMarri Devender Rao { 502828252d5SJiaqing Zhao messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate", 503828252d5SJiaqing Zhao "CertificateUri"); 5045968caeeSMarri Devender Rao return; 5055968caeeSMarri Devender Rao } 50675b63a2cSJiaqing Zhao BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI; 5075968caeeSMarri Devender Rao 50875b63a2cSJiaqing Zhao boost::urls::result<boost::urls::url_view> parsedUrl = 50975b63a2cSJiaqing Zhao boost::urls::parse_relative_ref(certURI); 51075b63a2cSJiaqing Zhao if (!parsedUrl) 5115968caeeSMarri Devender Rao { 512828252d5SJiaqing Zhao messages::actionParameterValueFormatError( 513828252d5SJiaqing Zhao asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate"); 5145968caeeSMarri Devender Rao return; 5155968caeeSMarri Devender Rao } 51675b63a2cSJiaqing Zhao 51775b63a2cSJiaqing Zhao std::string id; 51875b63a2cSJiaqing Zhao sdbusplus::message::object_path objectPath; 5195968caeeSMarri Devender Rao std::string name; 52037cce918SMarri Devender Rao std::string service; 521828252d5SJiaqing Zhao if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers", 522828252d5SJiaqing Zhao "bmc", "NetworkProtocol", "HTTPS", 523828252d5SJiaqing Zhao "Certificates", std::ref(id))) 5245968caeeSMarri Devender Rao { 52589492a15SPatrick Williams objectPath = sdbusplus::message::object_path(certs::httpsObjectPath) / 52689492a15SPatrick Williams id; 5275968caeeSMarri Devender Rao name = "HTTPS certificate"; 52837cce918SMarri Devender Rao service = certs::httpsServiceName; 52937cce918SMarri Devender Rao } 53075b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 53175b63a2cSJiaqing Zhao "AccountService", "LDAP", 53275b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 53337cce918SMarri Devender Rao { 53489492a15SPatrick Williams objectPath = sdbusplus::message::object_path(certs::ldapObjectPath) / 53589492a15SPatrick Williams id; 53637cce918SMarri Devender Rao name = "LDAP certificate"; 53737cce918SMarri Devender Rao service = certs::ldapServiceName; 5385968caeeSMarri Devender Rao } 53975b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 54075b63a2cSJiaqing Zhao "Managers", "bmc", "Truststore", 54175b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 542cfcd5f6bSMarri Devender Rao { 54375b63a2cSJiaqing Zhao objectPath = 544828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 545cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 546cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 547cfcd5f6bSMarri Devender Rao } 5485968caeeSMarri Devender Rao else 5495968caeeSMarri Devender Rao { 550828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateUri", 551828252d5SJiaqing Zhao "ReplaceCertificate"); 5525968caeeSMarri Devender Rao return; 5535968caeeSMarri Devender Rao } 5545968caeeSMarri Devender Rao 5555968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 5565968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 5575968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 5581e312598SJiaqing Zhao [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, 5595e7e2dc5SEd Tanous name](const boost::system::error_code& ec) { 5605968caeeSMarri Devender Rao if (ec) 5615968caeeSMarri Devender Rao { 5625968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 56390d2d1e8SJiaqing Zhao if (ec.value() == 56490d2d1e8SJiaqing Zhao boost::system::linux_error::bad_request_descriptor) 56590d2d1e8SJiaqing Zhao { 566828252d5SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 5675968caeeSMarri Devender Rao return; 5685968caeeSMarri Devender Rao } 56990d2d1e8SJiaqing Zhao messages::internalError(asyncResp->res); 57090d2d1e8SJiaqing Zhao return; 57190d2d1e8SJiaqing Zhao } 572828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, service, id, url, name); 5735968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 5745968caeeSMarri Devender Rao << certFile->getCertFilePath(); 5755968caeeSMarri Devender Rao }, 5765968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 5775968caeeSMarri Devender Rao certFile->getCertFilePath()); 578828252d5SJiaqing Zhao } 5795968caeeSMarri Devender Rao 580cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 581828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher; 5825968caeeSMarri Devender Rao /** 583828252d5SJiaqing Zhao * @brief Read data from CSR D-bus object and set to response 584828252d5SJiaqing Zhao * 585828252d5SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 586828252d5SJiaqing Zhao * @param[in] certURI Link to certifiate collection URI 587828252d5SJiaqing Zhao * @param[in] service D-Bus service name 588828252d5SJiaqing Zhao * @param[in] certObjPath certificate D-Bus object path 589828252d5SJiaqing Zhao * @param[in] csrObjPath CSR D-Bus object path 590828252d5SJiaqing Zhao * @return None 5915968caeeSMarri Devender Rao */ 592828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 593828252d5SJiaqing Zhao const std::string& certURI, const std::string& service, 594828252d5SJiaqing Zhao const std::string& certObjPath, 595828252d5SJiaqing Zhao const std::string& csrObjPath) 5965968caeeSMarri Devender Rao { 597828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath 598828252d5SJiaqing Zhao << " CSRObjectPath=" << csrObjPath 599828252d5SJiaqing Zhao << " service=" << service; 600828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 6015e7e2dc5SEd Tanous [asyncResp, certURI](const boost::system::error_code& ec, 602828252d5SJiaqing Zhao const std::string& csr) { 603828252d5SJiaqing Zhao if (ec) 604828252d5SJiaqing Zhao { 605828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 606828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 607828252d5SJiaqing Zhao return; 608828252d5SJiaqing Zhao } 609828252d5SJiaqing Zhao if (csr.empty()) 610828252d5SJiaqing Zhao { 611828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "CSR read is empty"; 612828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 613828252d5SJiaqing Zhao return; 614828252d5SJiaqing Zhao } 615828252d5SJiaqing Zhao asyncResp->res.jsonValue["CSRString"] = csr; 616828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = 617828252d5SJiaqing Zhao certURI; 618828252d5SJiaqing Zhao }, 619828252d5SJiaqing Zhao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 620828252d5SJiaqing Zhao } 621828252d5SJiaqing Zhao 622828252d5SJiaqing Zhao inline void 623828252d5SJiaqing Zhao handleGenerateCSRAction(App& app, const crow::Request& req, 624828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 625828252d5SJiaqing Zhao { 6263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 62745ca1b86SEd Tanous { 62845ca1b86SEd Tanous return; 62945ca1b86SEd Tanous } 630828252d5SJiaqing Zhao static const int rsaKeyBitLength = 2048; 6315968caeeSMarri Devender Rao 632828252d5SJiaqing Zhao // Required parameters 633828252d5SJiaqing Zhao std::string city; 634828252d5SJiaqing Zhao std::string commonName; 635828252d5SJiaqing Zhao std::string country; 636828252d5SJiaqing Zhao std::string organization; 637828252d5SJiaqing Zhao std::string organizationalUnit; 638828252d5SJiaqing Zhao std::string state; 639828252d5SJiaqing Zhao nlohmann::json certificateCollection; 640828252d5SJiaqing Zhao 641828252d5SJiaqing Zhao // Optional parameters 642828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optAlternativeNames = 643828252d5SJiaqing Zhao std::vector<std::string>(); 644828252d5SJiaqing Zhao std::optional<std::string> optContactPerson = ""; 645828252d5SJiaqing Zhao std::optional<std::string> optChallengePassword = ""; 646828252d5SJiaqing Zhao std::optional<std::string> optEmail = ""; 647828252d5SJiaqing Zhao std::optional<std::string> optGivenName = ""; 648828252d5SJiaqing Zhao std::optional<std::string> optInitials = ""; 649828252d5SJiaqing Zhao std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 650828252d5SJiaqing Zhao std::optional<std::string> optKeyCurveId = "secp384r1"; 651828252d5SJiaqing Zhao std::optional<std::string> optKeyPairAlgorithm = "EC"; 652828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optKeyUsage = 653828252d5SJiaqing Zhao std::vector<std::string>(); 654828252d5SJiaqing Zhao std::optional<std::string> optSurname = ""; 655828252d5SJiaqing Zhao std::optional<std::string> optUnstructuredName = ""; 656828252d5SJiaqing Zhao if (!json_util::readJsonAction( 657828252d5SJiaqing Zhao req, asyncResp->res, "City", city, "CommonName", commonName, 658828252d5SJiaqing Zhao "ContactPerson", optContactPerson, "Country", country, 659828252d5SJiaqing Zhao "Organization", organization, "OrganizationalUnit", 660828252d5SJiaqing Zhao organizationalUnit, "State", state, "CertificateCollection", 661828252d5SJiaqing Zhao certificateCollection, "AlternativeNames", optAlternativeNames, 662828252d5SJiaqing Zhao "ChallengePassword", optChallengePassword, "Email", optEmail, 663828252d5SJiaqing Zhao "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength", 664828252d5SJiaqing Zhao optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm", 665828252d5SJiaqing Zhao optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname, 666828252d5SJiaqing Zhao "UnstructuredName", optUnstructuredName)) 667828252d5SJiaqing Zhao { 668828252d5SJiaqing Zhao return; 6695968caeeSMarri Devender Rao } 6705968caeeSMarri Devender Rao 671828252d5SJiaqing Zhao // bmcweb has no way to store or decode a private key challenge 672828252d5SJiaqing Zhao // password, which will likely cause bmcweb to crash on startup 673828252d5SJiaqing Zhao // if this is not set on a post so not allowing the user to set 674828252d5SJiaqing Zhao // value 675828252d5SJiaqing Zhao if (!optChallengePassword->empty()) 6765968caeeSMarri Devender Rao { 677828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 678828252d5SJiaqing Zhao "ChallengePassword"); 679828252d5SJiaqing Zhao return; 680828252d5SJiaqing Zhao } 681828252d5SJiaqing Zhao 682828252d5SJiaqing Zhao std::string certURI; 683828252d5SJiaqing Zhao if (!redfish::json_util::readJson(certificateCollection, asyncResp->res, 684828252d5SJiaqing Zhao "@odata.id", certURI)) 685828252d5SJiaqing Zhao { 686828252d5SJiaqing Zhao return; 687828252d5SJiaqing Zhao } 688828252d5SJiaqing Zhao 689828252d5SJiaqing Zhao std::string objectPath; 690828252d5SJiaqing Zhao std::string service; 691828252d5SJiaqing Zhao if (certURI.starts_with( 692828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 693828252d5SJiaqing Zhao { 694828252d5SJiaqing Zhao objectPath = certs::httpsObjectPath; 695828252d5SJiaqing Zhao service = certs::httpsServiceName; 696828252d5SJiaqing Zhao } 697828252d5SJiaqing Zhao else if (certURI.starts_with( 698828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 699828252d5SJiaqing Zhao { 700828252d5SJiaqing Zhao objectPath = certs::ldapObjectPath; 701828252d5SJiaqing Zhao service = certs::ldapServiceName; 702828252d5SJiaqing Zhao } 703828252d5SJiaqing Zhao else 704828252d5SJiaqing Zhao { 705828252d5SJiaqing Zhao messages::actionParameterNotSupported( 706828252d5SJiaqing Zhao asyncResp->res, "CertificateCollection", "GenerateCSR"); 707828252d5SJiaqing Zhao return; 708828252d5SJiaqing Zhao } 709828252d5SJiaqing Zhao 710828252d5SJiaqing Zhao // supporting only EC and RSA algorithm 711828252d5SJiaqing Zhao if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 712828252d5SJiaqing Zhao { 713828252d5SJiaqing Zhao messages::actionParameterNotSupported( 714828252d5SJiaqing Zhao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 715828252d5SJiaqing Zhao return; 716828252d5SJiaqing Zhao } 717828252d5SJiaqing Zhao 718828252d5SJiaqing Zhao // supporting only 2048 key bit length for RSA algorithm due to 719828252d5SJiaqing Zhao // time consumed in generating private key 720828252d5SJiaqing Zhao if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength) 721828252d5SJiaqing Zhao { 722*e2616cc5SEd Tanous messages::propertyValueNotInList(asyncResp->res, *optKeyBitLength, 723*e2616cc5SEd Tanous "KeyBitLength"); 724828252d5SJiaqing Zhao return; 725828252d5SJiaqing Zhao } 726828252d5SJiaqing Zhao 727828252d5SJiaqing Zhao // validate KeyUsage supporting only 1 type based on URL 728828252d5SJiaqing Zhao if (certURI.starts_with( 729828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 730828252d5SJiaqing Zhao { 731828252d5SJiaqing Zhao if (optKeyUsage->empty()) 732828252d5SJiaqing Zhao { 733b2ba3072SPatrick Williams optKeyUsage->emplace_back("ServerAuthentication"); 734828252d5SJiaqing Zhao } 735828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 736828252d5SJiaqing Zhao { 737828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ServerAuthentication") 738828252d5SJiaqing Zhao { 739828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 740828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 741828252d5SJiaqing Zhao return; 742828252d5SJiaqing Zhao } 743828252d5SJiaqing Zhao } 744828252d5SJiaqing Zhao else 745828252d5SJiaqing Zhao { 746828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 747828252d5SJiaqing Zhao "GenerateCSR"); 748828252d5SJiaqing Zhao return; 749828252d5SJiaqing Zhao } 750828252d5SJiaqing Zhao } 751828252d5SJiaqing Zhao else if (certURI.starts_with( 752828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 753828252d5SJiaqing Zhao { 754828252d5SJiaqing Zhao if (optKeyUsage->empty()) 755828252d5SJiaqing Zhao { 756b2ba3072SPatrick Williams optKeyUsage->emplace_back("ClientAuthentication"); 757828252d5SJiaqing Zhao } 758828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 759828252d5SJiaqing Zhao { 760828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ClientAuthentication") 761828252d5SJiaqing Zhao { 762828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 763828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 764828252d5SJiaqing Zhao return; 765828252d5SJiaqing Zhao } 766828252d5SJiaqing Zhao } 767828252d5SJiaqing Zhao else 768828252d5SJiaqing Zhao { 769828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 770828252d5SJiaqing Zhao "GenerateCSR"); 771828252d5SJiaqing Zhao return; 772828252d5SJiaqing Zhao } 773828252d5SJiaqing Zhao } 774828252d5SJiaqing Zhao 775828252d5SJiaqing Zhao // Only allow one CSR matcher at a time so setting retry 776828252d5SJiaqing Zhao // time-out and timer expiry to 10 seconds for now. 777828252d5SJiaqing Zhao static const int timeOut = 10; 778828252d5SJiaqing Zhao if (csrMatcher) 779828252d5SJiaqing Zhao { 780828252d5SJiaqing Zhao messages::serviceTemporarilyUnavailable(asyncResp->res, 781828252d5SJiaqing Zhao std::to_string(timeOut)); 782828252d5SJiaqing Zhao return; 783828252d5SJiaqing Zhao } 784828252d5SJiaqing Zhao 785828252d5SJiaqing Zhao // Make this static so it survives outside this method 786828252d5SJiaqing Zhao static boost::asio::steady_timer timeout(*req.ioService); 787828252d5SJiaqing Zhao timeout.expires_after(std::chrono::seconds(timeOut)); 788828252d5SJiaqing Zhao timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 789828252d5SJiaqing Zhao csrMatcher = nullptr; 790828252d5SJiaqing Zhao if (ec) 791828252d5SJiaqing Zhao { 792828252d5SJiaqing Zhao // operation_aborted is expected if timer is canceled 793828252d5SJiaqing Zhao // before completion. 794828252d5SJiaqing Zhao if (ec != boost::asio::error::operation_aborted) 795828252d5SJiaqing Zhao { 796828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Async_wait failed " << ec; 797828252d5SJiaqing Zhao } 798828252d5SJiaqing Zhao return; 799828252d5SJiaqing Zhao } 800828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; 801828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 802828252d5SJiaqing Zhao }); 803828252d5SJiaqing Zhao 804828252d5SJiaqing Zhao // create a matcher to wait on CSR object 805828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; 806828252d5SJiaqing Zhao std::string match("type='signal'," 807828252d5SJiaqing Zhao "interface='org.freedesktop.DBus.ObjectManager'," 808828252d5SJiaqing Zhao "path='" + 809828252d5SJiaqing Zhao objectPath + 810828252d5SJiaqing Zhao "'," 811828252d5SJiaqing Zhao "member='InterfacesAdded'"); 812828252d5SJiaqing Zhao csrMatcher = std::make_unique<sdbusplus::bus::match_t>( 813828252d5SJiaqing Zhao *crow::connections::systemBus, match, 814828252d5SJiaqing Zhao [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { 815828252d5SJiaqing Zhao timeout.cancel(); 816828252d5SJiaqing Zhao if (m.is_method_error()) 817828252d5SJiaqing Zhao { 818828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Dbus method error!!!"; 819828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 820828252d5SJiaqing Zhao return; 821828252d5SJiaqing Zhao } 822828252d5SJiaqing Zhao 823828252d5SJiaqing Zhao dbus::utility::DBusInteracesMap interfacesProperties; 824828252d5SJiaqing Zhao 825828252d5SJiaqing Zhao sdbusplus::message::object_path csrObjectPath; 826828252d5SJiaqing Zhao m.read(csrObjectPath, interfacesProperties); 827828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; 828828252d5SJiaqing Zhao for (const auto& interface : interfacesProperties) 829828252d5SJiaqing Zhao { 830828252d5SJiaqing Zhao if (interface.first == "xyz.openbmc_project.Certs.CSR") 831828252d5SJiaqing Zhao { 832828252d5SJiaqing Zhao getCSR(asyncResp, certURI, service, objectPath, 833828252d5SJiaqing Zhao csrObjectPath.str); 834828252d5SJiaqing Zhao break; 835828252d5SJiaqing Zhao } 836828252d5SJiaqing Zhao } 837828252d5SJiaqing Zhao }); 838828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 8395e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, const std::string&) { 840828252d5SJiaqing Zhao if (ec) 841828252d5SJiaqing Zhao { 842828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message(); 843828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 844828252d5SJiaqing Zhao return; 845828252d5SJiaqing Zhao } 846828252d5SJiaqing Zhao }, 847828252d5SJiaqing Zhao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 848828252d5SJiaqing Zhao "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 849828252d5SJiaqing Zhao commonName, *optContactPerson, country, *optEmail, *optGivenName, 850828252d5SJiaqing Zhao *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm, 851828252d5SJiaqing Zhao *optKeyUsage, organization, organizationalUnit, state, *optSurname, 852828252d5SJiaqing Zhao *optUnstructuredName); 853828252d5SJiaqing Zhao } 854828252d5SJiaqing Zhao 855828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app) 856828252d5SJiaqing Zhao { 857828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") 858828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateService) 859002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 860828252d5SJiaqing Zhao std::bind_front(handleCertificateServiceGet, std::ref(app))); 861828252d5SJiaqing Zhao 862828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 863828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateLocations) 864828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 865828252d5SJiaqing Zhao std::bind_front(handleCertificateLocationsGet, std::ref(app))); 866828252d5SJiaqing Zhao 867828252d5SJiaqing Zhao BMCWEB_ROUTE( 868828252d5SJiaqing Zhao app, 869828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 870828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 871828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 872828252d5SJiaqing Zhao std::bind_front(handleReplaceCertificateAction, std::ref(app))); 873828252d5SJiaqing Zhao 874828252d5SJiaqing Zhao BMCWEB_ROUTE( 875828252d5SJiaqing Zhao app, 876828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 877828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 878828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 879828252d5SJiaqing Zhao std::bind_front(handleGenerateCSRAction, std::ref(app))); 880828252d5SJiaqing Zhao } // requestRoutesCertificateService 881828252d5SJiaqing Zhao 882828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet( 883828252d5SJiaqing Zhao App& app, const crow::Request& req, 884828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 885828252d5SJiaqing Zhao { 8863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 88745ca1b86SEd Tanous { 88845ca1b86SEd Tanous return; 88945ca1b86SEd Tanous } 8901476687dSEd Tanous 8911476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 8921476687dSEd Tanous "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"; 8931476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 8941476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 8951476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; 8961476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 8971476687dSEd Tanous "A Collection of HTTPS certificate instances"; 8988d1b46d7Szhanghch05 899d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::httpsObjectPath, 900d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 901d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 902828252d5SJiaqing Zhao } 9035968caeeSMarri Devender Rao 904828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost( 905828252d5SJiaqing Zhao App& app, const crow::Request& req, 906828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 907828252d5SJiaqing Zhao { 9083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 90945ca1b86SEd Tanous { 91045ca1b86SEd Tanous return; 91145ca1b86SEd Tanous } 9125968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; 9138d1b46d7Szhanghch05 9141476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; 9151476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; 9165968caeeSMarri Devender Rao 917002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 91858eb238fSKowalski, Kamil 91958eb238fSKowalski, Kamil if (certFileBody.empty()) 92058eb238fSKowalski, Kamil { 9210fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 922a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 92358eb238fSKowalski, Kamil return; 92458eb238fSKowalski, Kamil } 92558eb238fSKowalski, Kamil 9265968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 92758eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 9285968caeeSMarri Devender Rao 9295968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 9305e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 931656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 9325968caeeSMarri Devender Rao if (ec) 9335968caeeSMarri Devender Rao { 9345968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 9355968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 9365968caeeSMarri Devender Rao return; 9375968caeeSMarri Devender Rao } 938717b9802SJiaqing Zhao 939717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 940717b9802SJiaqing Zhao std::string certId = path.filename(); 941ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 942ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}", 943ef4c65b7SEd Tanous certId); 944828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName, 945828252d5SJiaqing Zhao certId, certURL, "HTTPS Certificate"); 9465968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 9475968caeeSMarri Devender Rao << certFile->getCertFilePath(); 9485968caeeSMarri Devender Rao }, 949828252d5SJiaqing Zhao certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf, 950828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 951828252d5SJiaqing Zhao } 9525968caeeSMarri Devender Rao 953828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet( 954828252d5SJiaqing Zhao App& app, const crow::Request& req, 955828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 9567e860f15SJohn Edward Broadbent { 9573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 95845ca1b86SEd Tanous { 95945ca1b86SEd Tanous return; 96045ca1b86SEd Tanous } 9617e860f15SJohn Edward Broadbent 962828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id; 963ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 964ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/{}", id); 965828252d5SJiaqing Zhao std::string objPath = 966828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::httpsObjectPath) / id; 967828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id, 968828252d5SJiaqing Zhao certURL, "HTTPS Certificate"); 9697e860f15SJohn Edward Broadbent } 97037cce918SMarri Devender Rao 971828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app) 97237cce918SMarri Devender Rao { 973828252d5SJiaqing Zhao BMCWEB_ROUTE(app, 974828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 975ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 976828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 977828252d5SJiaqing Zhao handleHTTPSCertificateCollectionGet, std::ref(app))); 978828252d5SJiaqing Zhao 979828252d5SJiaqing Zhao BMCWEB_ROUTE(app, 980828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 981828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 982828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 983828252d5SJiaqing Zhao handleHTTPSCertificateCollectionPost, std::ref(app))); 984828252d5SJiaqing Zhao 985828252d5SJiaqing Zhao BMCWEB_ROUTE( 986828252d5SJiaqing Zhao app, 987828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/") 988828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 989002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 990828252d5SJiaqing Zhao std::bind_front(handleHTTPSCertificateGet, std::ref(app))); 991828252d5SJiaqing Zhao } 992828252d5SJiaqing Zhao 993828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet( 994828252d5SJiaqing Zhao App& app, const crow::Request& req, 995828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 996828252d5SJiaqing Zhao { 9973ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 99845ca1b86SEd Tanous { 99945ca1b86SEd Tanous return; 100045ca1b86SEd Tanous } 10011476687dSEd Tanous 10021476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 10031476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 10041476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 10051476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 10061476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; 10071476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 10081476687dSEd Tanous "A Collection of LDAP certificate instances"; 10098d1b46d7Szhanghch05 1010d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::ldapObjectPath, 1011d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1012d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1013828252d5SJiaqing Zhao } 101437cce918SMarri Devender Rao 1015828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost( 1016828252d5SJiaqing Zhao App& app, const crow::Request& req, 1017828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1018828252d5SJiaqing Zhao { 10193ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 102045ca1b86SEd Tanous { 102145ca1b86SEd Tanous return; 102245ca1b86SEd Tanous } 1023002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 102458eb238fSKowalski, Kamil 102558eb238fSKowalski, Kamil if (certFileBody.empty()) 102658eb238fSKowalski, Kamil { 1027002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1028a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 102958eb238fSKowalski, Kamil return; 103058eb238fSKowalski, Kamil } 103158eb238fSKowalski, Kamil 103258eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 103358eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 103458eb238fSKowalski, Kamil 103537cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 10365e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 1037656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 103837cce918SMarri Devender Rao if (ec) 103937cce918SMarri Devender Rao { 104037cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 104137cce918SMarri Devender Rao messages::internalError(asyncResp->res); 104237cce918SMarri Devender Rao return; 104337cce918SMarri Devender Rao } 1044717b9802SJiaqing Zhao 1045717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1046717b9802SJiaqing Zhao std::string certId = path.filename(); 1047ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1048ef4c65b7SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/{}", certId); 1049828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName, 1050828252d5SJiaqing Zhao certId, certURL, "LDAP Certificate"); 105137cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "LDAP certificate install file=" 105237cce918SMarri Devender Rao << certFile->getCertFilePath(); 105337cce918SMarri Devender Rao }, 1054828252d5SJiaqing Zhao certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf, 1055828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 1056828252d5SJiaqing Zhao } 105737cce918SMarri Devender Rao 1058828252d5SJiaqing Zhao inline void handleLDAPCertificateGet( 1059828252d5SJiaqing Zhao App& app, const crow::Request& req, 1060828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 106137cce918SMarri Devender Rao { 10623ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 106345ca1b86SEd Tanous { 106445ca1b86SEd Tanous return; 106545ca1b86SEd Tanous } 1066717b9802SJiaqing Zhao 1067717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id; 1068ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1069ef4c65b7SEd Tanous "/redfish/v1/AccountService/LDAP/Certificates/{}", id); 1070717b9802SJiaqing Zhao std::string objPath = 1071717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 1072717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, 1073717b9802SJiaqing Zhao certURL, "LDAP Certificate"); 1074828252d5SJiaqing Zhao } 1075828252d5SJiaqing Zhao 107699612247SJiaqing Zhao inline void handleLDAPCertificateDelete( 107799612247SJiaqing Zhao App& app, const crow::Request& req, 107899612247SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 107999612247SJiaqing Zhao { 108099612247SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 108199612247SJiaqing Zhao { 108299612247SJiaqing Zhao return; 108399612247SJiaqing Zhao } 108499612247SJiaqing Zhao 108599612247SJiaqing Zhao BMCWEB_LOG_DEBUG << "Delete LDAP Certificate ID=" << id; 108699612247SJiaqing Zhao std::string objPath = 108799612247SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 108899612247SJiaqing Zhao 108999612247SJiaqing Zhao deleteCertificate(asyncResp, certs::ldapServiceName, objPath); 109099612247SJiaqing Zhao } 109199612247SJiaqing Zhao 1092828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app) 1093cfcd5f6bSMarri Devender Rao { 1094828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1095828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateCollection) 1096828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1097828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app))); 1098828252d5SJiaqing Zhao 1099828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1100828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1101828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1102828252d5SJiaqing Zhao handleLDAPCertificateCollectionPost, std::ref(app))); 1103828252d5SJiaqing Zhao 1104828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1105ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 1106002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1107828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateGet, std::ref(app))); 110899612247SJiaqing Zhao 110999612247SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 111099612247SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 111199612247SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 111299612247SJiaqing Zhao std::bind_front(handleLDAPCertificateDelete, std::ref(app))); 1113828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate 1114828252d5SJiaqing Zhao 1115828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet( 1116828252d5SJiaqing Zhao App& app, const crow::Request& req, 1117828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1118828252d5SJiaqing Zhao { 11193ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 112045ca1b86SEd Tanous { 112145ca1b86SEd Tanous return; 112245ca1b86SEd Tanous } 11231476687dSEd Tanous 11241476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 11251476687dSEd Tanous "/redfish/v1/Managers/bmc/Truststore/Certificates/"; 11261476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 11271476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 1128002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; 11291476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 11301476687dSEd Tanous "A Collection of TrustStore certificate instances"; 11318d1b46d7Szhanghch05 1132d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::authorityObjectPath, 1133d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1134d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1135828252d5SJiaqing Zhao } 1136cfcd5f6bSMarri Devender Rao 1137828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost( 1138828252d5SJiaqing Zhao App& app, const crow::Request& req, 1139828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1140828252d5SJiaqing Zhao { 11413ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 114245ca1b86SEd Tanous { 114345ca1b86SEd Tanous return; 114445ca1b86SEd Tanous } 1145002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 1146a08752f5SZbigniew Kurzynski 1147a08752f5SZbigniew Kurzynski if (certFileBody.empty()) 1148a08752f5SZbigniew Kurzynski { 11490fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1150a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1151a08752f5SZbigniew Kurzynski return; 1152a08752f5SZbigniew Kurzynski } 1153a08752f5SZbigniew Kurzynski 1154a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1155a08752f5SZbigniew Kurzynski std::make_shared<CertificateFile>(certFileBody); 1156cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 11575e7e2dc5SEd Tanous [asyncResp, certFile](const boost::system::error_code& ec, 1158656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1159cfcd5f6bSMarri Devender Rao if (ec) 1160cfcd5f6bSMarri Devender Rao { 1161cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1162cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1163cfcd5f6bSMarri Devender Rao return; 1164cfcd5f6bSMarri Devender Rao } 1165656ec7e3SZbigniew Kurzynski 1166717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1167717b9802SJiaqing Zhao std::string certId = path.filename(); 1168ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1169ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", certId); 1170717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, 1171828252d5SJiaqing Zhao certs::authorityServiceName, certId, certURL, 1172828252d5SJiaqing Zhao "TrustStore Certificate"); 11730fda0f12SGeorge Liu BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" 1174cfcd5f6bSMarri Devender Rao << certFile->getCertFilePath(); 1175cfcd5f6bSMarri Devender Rao }, 1176cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 11770fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 1178828252d5SJiaqing Zhao } 1179cfcd5f6bSMarri Devender Rao 1180828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet( 1181828252d5SJiaqing Zhao App& app, const crow::Request& req, 1182828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1183cfcd5f6bSMarri Devender Rao { 11843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 118545ca1b86SEd Tanous { 118645ca1b86SEd Tanous return; 118745ca1b86SEd Tanous } 1188717b9802SJiaqing Zhao 1189717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id; 1190ef4c65b7SEd Tanous const boost::urls::url certURL = boost::urls::format( 1191ef4c65b7SEd Tanous "/redfish/v1/Managers/bmc/Truststore/Certificates/{}", id); 1192717b9802SJiaqing Zhao std::string objPath = 1193717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 1194828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::authorityServiceName, 1195828252d5SJiaqing Zhao id, certURL, "TrustStore Certificate"); 1196828252d5SJiaqing Zhao } 119707a60299SZbigniew Kurzynski 1198828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete( 1199828252d5SJiaqing Zhao App& app, const crow::Request& req, 1200828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1201828252d5SJiaqing Zhao { 12023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 120345ca1b86SEd Tanous { 120445ca1b86SEd Tanous return; 120545ca1b86SEd Tanous } 120607a60299SZbigniew Kurzynski 1207717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id; 1208717b9802SJiaqing Zhao std::string objPath = 1209717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 121007a60299SZbigniew Kurzynski 12117a3a8f7aSJiaqing Zhao deleteCertificate(asyncResp, certs::authorityServiceName, objPath); 1212828252d5SJiaqing Zhao } 1213828252d5SJiaqing Zhao 1214828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app) 1215828252d5SJiaqing Zhao { 1216828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1217828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1218828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 1219828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionGet, std::ref(app))); 1220828252d5SJiaqing Zhao 1221828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1222828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1223828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1224828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionPost, std::ref(app))); 1225828252d5SJiaqing Zhao 1226828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1227828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1228828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1229828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateGet, std::ref(app))); 1230828252d5SJiaqing Zhao 1231828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1232828252d5SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 1233828252d5SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 1234828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateDelete, std::ref(app))); 12357e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate 12365968caeeSMarri Devender Rao } // namespace redfish 1237