15968caeeSMarri Devender Rao #pragma once 25968caeeSMarri Devender Rao 3*7a1dbc48SGeorge Liu #include "dbus_utility.hpp" 49b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp" 59b12d1f9SKrzysztof Grobelny 67e860f15SJohn Edward Broadbent #include <app.hpp> 7d9f6c621SEd Tanous #include <async_resp.hpp> 890d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp> 9d9f6c621SEd Tanous #include <http_response.hpp> 1045ca1b86SEd Tanous #include <query.hpp> 11ed398213SEd Tanous #include <registries/privilege_registry.hpp> 129b12d1f9SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 139b12d1f9SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 141214b7e7SGunnar Mills 15*7a1dbc48SGeorge Liu #include <array> 16*7a1dbc48SGeorge Liu #include <string_view> 17*7a1dbc48SGeorge Liu 185968caeeSMarri Devender Rao namespace redfish 195968caeeSMarri Devender Rao { 205968caeeSMarri Devender Rao namespace certs 215968caeeSMarri Devender Rao { 225968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 235968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 2407a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 255968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 265968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties"; 275968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 2837cce918SMarri Devender Rao constexpr char const* httpsServiceName = 2937cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Server.Https"; 3037cce918SMarri Devender Rao constexpr char const* ldapServiceName = 3137cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 32cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName = 33cfcd5f6bSMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Authority.Ldap"; 34c6a8dfb1SJiaqing Zhao constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs"; 35c6a8dfb1SJiaqing Zhao constexpr char const* httpsObjectPath = 36c6a8dfb1SJiaqing Zhao "/xyz/openbmc_project/certs/server/https"; 37c6a8dfb1SJiaqing Zhao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 38cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath = 39cfcd5f6bSMarri Devender Rao "/xyz/openbmc_project/certs/authority/ldap"; 405968caeeSMarri Devender Rao } // namespace certs 415968caeeSMarri Devender Rao 425968caeeSMarri Devender Rao /** 435968caeeSMarri Devender Rao * The Certificate schema defines a Certificate Service which represents the 445968caeeSMarri Devender Rao * actions available to manage certificates and links to where certificates 455968caeeSMarri Devender Rao * are installed. 465968caeeSMarri Devender Rao */ 477e860f15SJohn Edward Broadbent 488d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody( 498d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5058eb238fSKowalski, Kamil const crow::Request& req) 5158eb238fSKowalski, Kamil { 5258eb238fSKowalski, Kamil nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false); 5358eb238fSKowalski, Kamil 5458eb238fSKowalski, Kamil if (reqJson.is_discarded()) 5558eb238fSKowalski, Kamil { 5658eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 5758eb238fSKowalski, Kamil return req.body; 5858eb238fSKowalski, Kamil } 5958eb238fSKowalski, Kamil 6058eb238fSKowalski, Kamil std::string certificate; 6158eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 6258eb238fSKowalski, Kamil 6315ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString", 6415ed6780SWilly Tu certificate, "CertificateType", 6515ed6780SWilly Tu certificateType)) 6658eb238fSKowalski, Kamil { 6758eb238fSKowalski, Kamil BMCWEB_LOG_ERROR << "Required parameters are missing"; 6858eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 69abb93cddSEd Tanous return {}; 7058eb238fSKowalski, Kamil } 7158eb238fSKowalski, Kamil 7258eb238fSKowalski, Kamil if (*certificateType != "PEM") 7358eb238fSKowalski, Kamil { 7458eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 7558eb238fSKowalski, Kamil "CertificateType"); 76abb93cddSEd Tanous return {}; 7758eb238fSKowalski, Kamil } 7858eb238fSKowalski, Kamil 7958eb238fSKowalski, Kamil return certificate; 8058eb238fSKowalski, Kamil } 8158eb238fSKowalski, Kamil 825968caeeSMarri Devender Rao /** 835968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 845968caeeSMarri Devender Rao */ 855968caeeSMarri Devender Rao class CertificateFile 865968caeeSMarri Devender Rao { 875968caeeSMarri Devender Rao public: 885968caeeSMarri Devender Rao CertificateFile() = delete; 895968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 905968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 915968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 925968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 934e23a444SEd Tanous explicit CertificateFile(const std::string& certString) 945968caeeSMarri Devender Rao { 9572d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 965207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 975207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 985207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 99e662eae8SEd Tanous if (tempDirectory != nullptr) 1005968caeeSMarri Devender Rao { 1015968caeeSMarri Devender Rao certDirectory = tempDirectory; 1025968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 1035968caeeSMarri Devender Rao std::ofstream out(certificateFile, std::ofstream::out | 1045968caeeSMarri Devender Rao std::ofstream::binary | 1055968caeeSMarri Devender Rao std::ofstream::trunc); 1065968caeeSMarri Devender Rao out << certString; 1075968caeeSMarri Devender Rao out.close(); 1088cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Creating certificate file" 1098cc8edecSEd Tanous << certificateFile.string(); 1105968caeeSMarri Devender Rao } 1115968caeeSMarri Devender Rao } 1125968caeeSMarri Devender Rao ~CertificateFile() 1135968caeeSMarri Devender Rao { 1145968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1155968caeeSMarri Devender Rao { 1168cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Removing certificate file" 1178cc8edecSEd Tanous << certificateFile.string(); 11823a21a1cSEd Tanous std::error_code ec; 11923a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 12023a21a1cSEd Tanous if (ec) 1215968caeeSMarri Devender Rao { 1225968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Failed to remove temp directory" 1238cc8edecSEd Tanous << certDirectory.string(); 1245968caeeSMarri Devender Rao } 1255968caeeSMarri Devender Rao } 1265968caeeSMarri Devender Rao } 1275968caeeSMarri Devender Rao std::string getCertFilePath() 1285968caeeSMarri Devender Rao { 1295968caeeSMarri Devender Rao return certificateFile; 1305968caeeSMarri Devender Rao } 1315968caeeSMarri Devender Rao 1325968caeeSMarri Devender Rao private: 1335968caeeSMarri Devender Rao std::filesystem::path certificateFile; 1345968caeeSMarri Devender Rao std::filesystem::path certDirectory; 1355968caeeSMarri Devender Rao }; 1365968caeeSMarri Devender Rao 1375968caeeSMarri Devender Rao /** 1384e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 1395968caeeSMarri Devender Rao * 1405968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 1415968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 1425968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 1435968caeeSMarri Devender Rao * @return None 1445968caeeSMarri Devender Rao */ 1455968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out, 1465968caeeSMarri Devender Rao const std::string_view value) 1475968caeeSMarri Devender Rao { 1485968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 1495968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 1505968caeeSMarri Devender Rao while (i != value.end()) 1515968caeeSMarri Devender Rao { 1525968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 1535968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 1545968caeeSMarri Devender Rao { 15517a897dfSManojkiran Eda ++i; 1565968caeeSMarri Devender Rao } 1575968caeeSMarri Devender Rao if (i == value.end()) 1585968caeeSMarri Devender Rao { 1595968caeeSMarri Devender Rao break; 1605968caeeSMarri Devender Rao } 161271584abSEd Tanous const std::string_view key(tokenBegin, 162271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 16317a897dfSManojkiran Eda ++i; 1645968caeeSMarri Devender Rao tokenBegin = i; 1655968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 1665968caeeSMarri Devender Rao { 16717a897dfSManojkiran Eda ++i; 1685968caeeSMarri Devender Rao } 169271584abSEd Tanous const std::string_view val(tokenBegin, 170271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 1715968caeeSMarri Devender Rao if (key == "L") 1725968caeeSMarri Devender Rao { 1735968caeeSMarri Devender Rao out["City"] = val; 1745968caeeSMarri Devender Rao } 1755968caeeSMarri Devender Rao else if (key == "CN") 1765968caeeSMarri Devender Rao { 1775968caeeSMarri Devender Rao out["CommonName"] = val; 1785968caeeSMarri Devender Rao } 1795968caeeSMarri Devender Rao else if (key == "C") 1805968caeeSMarri Devender Rao { 1815968caeeSMarri Devender Rao out["Country"] = val; 1825968caeeSMarri Devender Rao } 1835968caeeSMarri Devender Rao else if (key == "O") 1845968caeeSMarri Devender Rao { 1855968caeeSMarri Devender Rao out["Organization"] = val; 1865968caeeSMarri Devender Rao } 1875968caeeSMarri Devender Rao else if (key == "OU") 1885968caeeSMarri Devender Rao { 1895968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 1905968caeeSMarri Devender Rao } 1915968caeeSMarri Devender Rao else if (key == "ST") 1925968caeeSMarri Devender Rao { 1935968caeeSMarri Devender Rao out["State"] = val; 1945968caeeSMarri Devender Rao } 1955968caeeSMarri Devender Rao // skip comma character 1965968caeeSMarri Devender Rao if (i != value.end()) 1975968caeeSMarri Devender Rao { 19817a897dfSManojkiran Eda ++i; 1995968caeeSMarri Devender Rao } 2005968caeeSMarri Devender Rao } 2015968caeeSMarri Devender Rao } 2025968caeeSMarri Devender Rao 2035968caeeSMarri Devender Rao /** 204d3f92ce7SJiaqing Zhao * @brief Retrieve the installed certificate list 205d3f92ce7SJiaqing Zhao * 206d3f92ce7SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 207d3f92ce7SJiaqing Zhao * @param[in] basePath DBus object path to search 208d3f92ce7SJiaqing Zhao * @param[in] listPtr Json pointer to the list in asyncResp 209d3f92ce7SJiaqing Zhao * @param[in] countPtr Json pointer to the count in asyncResp 210d3f92ce7SJiaqing Zhao * @return None 211d3f92ce7SJiaqing Zhao */ 212d3f92ce7SJiaqing Zhao static void 213d3f92ce7SJiaqing Zhao getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 214d3f92ce7SJiaqing Zhao const std::string& basePath, 215d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& listPtr, 216d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& countPtr) 217d3f92ce7SJiaqing Zhao { 218*7a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 219*7a1dbc48SGeorge Liu certs::certPropIntf}; 220*7a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 221*7a1dbc48SGeorge Liu basePath, 0, interfaces, 222d3f92ce7SJiaqing Zhao [asyncResp, listPtr, countPtr]( 223*7a1dbc48SGeorge Liu const boost::system::error_code& ec, 224d3f92ce7SJiaqing Zhao const dbus::utility::MapperGetSubTreePathsResponse& certPaths) { 225d3f92ce7SJiaqing Zhao if (ec) 226d3f92ce7SJiaqing Zhao { 227d3f92ce7SJiaqing Zhao BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec; 228d3f92ce7SJiaqing Zhao messages::internalError(asyncResp->res); 229d3f92ce7SJiaqing Zhao return; 230d3f92ce7SJiaqing Zhao } 231d3f92ce7SJiaqing Zhao 232d3f92ce7SJiaqing Zhao nlohmann::json& links = asyncResp->res.jsonValue[listPtr]; 233d3f92ce7SJiaqing Zhao links = nlohmann::json::array(); 234d3f92ce7SJiaqing Zhao for (const auto& certPath : certPaths) 235d3f92ce7SJiaqing Zhao { 236d3f92ce7SJiaqing Zhao sdbusplus::message::object_path objPath(certPath); 237d3f92ce7SJiaqing Zhao std::string certId = objPath.filename(); 238d3f92ce7SJiaqing Zhao if (certId.empty()) 239d3f92ce7SJiaqing Zhao { 240d3f92ce7SJiaqing Zhao BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath; 241d3f92ce7SJiaqing Zhao continue; 242d3f92ce7SJiaqing Zhao } 243d3f92ce7SJiaqing Zhao 244d3f92ce7SJiaqing Zhao boost::urls::url certURL; 245d3f92ce7SJiaqing Zhao if (objPath.parent_path() == certs::httpsObjectPath) 246d3f92ce7SJiaqing Zhao { 247d3f92ce7SJiaqing Zhao certURL = crow::utility::urlFromPieces( 248d3f92ce7SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "NetworkProtocol", 249d3f92ce7SJiaqing Zhao "HTTPS", "Certificates", certId); 250d3f92ce7SJiaqing Zhao } 251d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::ldapObjectPath) 252d3f92ce7SJiaqing Zhao { 253d3f92ce7SJiaqing Zhao certURL = crow::utility::urlFromPieces("redfish", "v1", 254d3f92ce7SJiaqing Zhao "AccountService", "LDAP", 255d3f92ce7SJiaqing Zhao "Certificates", certId); 256d3f92ce7SJiaqing Zhao } 257d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::authorityObjectPath) 258d3f92ce7SJiaqing Zhao { 259d3f92ce7SJiaqing Zhao certURL = crow::utility::urlFromPieces( 260d3f92ce7SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "Truststore", 261d3f92ce7SJiaqing Zhao "Certificates", certId); 262d3f92ce7SJiaqing Zhao } 263d3f92ce7SJiaqing Zhao else 264d3f92ce7SJiaqing Zhao { 265d3f92ce7SJiaqing Zhao continue; 266d3f92ce7SJiaqing Zhao } 267d3f92ce7SJiaqing Zhao 268d3f92ce7SJiaqing Zhao nlohmann::json::object_t link; 269d3f92ce7SJiaqing Zhao link["@odata.id"] = certURL; 270d3f92ce7SJiaqing Zhao links.emplace_back(std::move(link)); 271d3f92ce7SJiaqing Zhao } 272d3f92ce7SJiaqing Zhao 273d3f92ce7SJiaqing Zhao asyncResp->res.jsonValue[countPtr] = links.size(); 274*7a1dbc48SGeorge Liu }); 275d3f92ce7SJiaqing Zhao } 276d3f92ce7SJiaqing Zhao 277d3f92ce7SJiaqing Zhao /** 2785968caeeSMarri Devender Rao * @brief Retrieve the certificates properties and append to the response 2795968caeeSMarri Devender Rao * message 2805968caeeSMarri Devender Rao * 2815968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 2825968caeeSMarri Devender Rao * @param[in] objectPath Path of the D-Bus service object 2835968caeeSMarri Devender Rao * @param[in] certId Id of the certificate 2845968caeeSMarri Devender Rao * @param[in] certURL URL of the certificate object 2855968caeeSMarri Devender Rao * @param[in] name name of the certificate 2865968caeeSMarri Devender Rao * @return None 2875968caeeSMarri Devender Rao */ 2885968caeeSMarri Devender Rao static void getCertificateProperties( 2898d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 290e19e97e2SJiaqing Zhao const std::string& objectPath, const std::string& service, 2911e312598SJiaqing Zhao const std::string& certId, const boost::urls::url& certURL, 292e19e97e2SJiaqing Zhao const std::string& name) 2935968caeeSMarri Devender Rao { 2945968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "getCertificateProperties Path=" << objectPath 2955968caeeSMarri Devender Rao << " certId=" << certId << " certURl=" << certURL; 2969b12d1f9SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 2979b12d1f9SKrzysztof Grobelny *crow::connections::systemBus, service, objectPath, certs::certPropIntf, 298b9d36b47SEd Tanous [asyncResp, certURL, certId, 299b9d36b47SEd Tanous name](const boost::system::error_code ec, 300b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& properties) { 3015968caeeSMarri Devender Rao if (ec) 3025968caeeSMarri Devender Rao { 3035968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 304d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", certId); 3055968caeeSMarri Devender Rao return; 3065968caeeSMarri Devender Rao } 3079b12d1f9SKrzysztof Grobelny 3089b12d1f9SKrzysztof Grobelny const std::string* certificateString = nullptr; 3099b12d1f9SKrzysztof Grobelny const std::vector<std::string>* keyUsage = nullptr; 3109b12d1f9SKrzysztof Grobelny const std::string* issuer = nullptr; 3119b12d1f9SKrzysztof Grobelny const std::string* subject = nullptr; 3129b12d1f9SKrzysztof Grobelny const uint64_t* validNotAfter = nullptr; 3139b12d1f9SKrzysztof Grobelny const uint64_t* validNotBefore = nullptr; 3149b12d1f9SKrzysztof Grobelny 3159b12d1f9SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 3169b12d1f9SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "CertificateString", 3179b12d1f9SKrzysztof Grobelny certificateString, "KeyUsage", keyUsage, "Issuer", issuer, 3189b12d1f9SKrzysztof Grobelny "Subject", subject, "ValidNotAfter", validNotAfter, 3199b12d1f9SKrzysztof Grobelny "ValidNotBefore", validNotBefore); 3209b12d1f9SKrzysztof Grobelny 3219b12d1f9SKrzysztof Grobelny if (!success) 3229b12d1f9SKrzysztof Grobelny { 3239b12d1f9SKrzysztof Grobelny messages::internalError(asyncResp->res); 3249b12d1f9SKrzysztof Grobelny return; 3259b12d1f9SKrzysztof Grobelny } 3269b12d1f9SKrzysztof Grobelny 3271476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = certURL; 3281476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 3291476687dSEd Tanous "#Certificate.v1_0_0.Certificate"; 330e19e97e2SJiaqing Zhao asyncResp->res.jsonValue["Id"] = certId; 3311476687dSEd Tanous asyncResp->res.jsonValue["Name"] = name; 3321476687dSEd Tanous asyncResp->res.jsonValue["Description"] = name; 3335968caeeSMarri Devender Rao asyncResp->res.jsonValue["CertificateString"] = ""; 3349b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = nlohmann::json::array(); 3359b12d1f9SKrzysztof Grobelny 3369b12d1f9SKrzysztof Grobelny if (certificateString != nullptr) 3375968caeeSMarri Devender Rao { 3389b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["CertificateString"] = *certificateString; 3395968caeeSMarri Devender Rao } 3409b12d1f9SKrzysztof Grobelny 3419b12d1f9SKrzysztof Grobelny if (keyUsage != nullptr) 3425968caeeSMarri Devender Rao { 3439b12d1f9SKrzysztof Grobelny asyncResp->res.jsonValue["KeyUsage"] = *keyUsage; 3445968caeeSMarri Devender Rao } 3459b12d1f9SKrzysztof Grobelny 3469b12d1f9SKrzysztof Grobelny if (issuer != nullptr) 3475968caeeSMarri Devender Rao { 3489b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Issuer"], 3499b12d1f9SKrzysztof Grobelny *issuer); 3505968caeeSMarri Devender Rao } 3519b12d1f9SKrzysztof Grobelny 3529b12d1f9SKrzysztof Grobelny if (subject != nullptr) 3535968caeeSMarri Devender Rao { 3549b12d1f9SKrzysztof Grobelny updateCertIssuerOrSubject(asyncResp->res.jsonValue["Subject"], 3559b12d1f9SKrzysztof Grobelny *subject); 3565968caeeSMarri Devender Rao } 3579b12d1f9SKrzysztof Grobelny 3589b12d1f9SKrzysztof Grobelny if (validNotAfter != nullptr) 3595968caeeSMarri Devender Rao { 3605968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotAfter"] = 3619b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotAfter); 3625968caeeSMarri Devender Rao } 3639b12d1f9SKrzysztof Grobelny 3649b12d1f9SKrzysztof Grobelny if (validNotBefore != nullptr) 3655968caeeSMarri Devender Rao { 3665968caeeSMarri Devender Rao asyncResp->res.jsonValue["ValidNotBefore"] = 3679b12d1f9SKrzysztof Grobelny redfish::time_utils::getDateTimeUint(*validNotBefore); 3685968caeeSMarri Devender Rao } 3699b12d1f9SKrzysztof Grobelny 3701e312598SJiaqing Zhao asyncResp->res.addHeader( 371d9f6c621SEd Tanous boost::beast::http::field::location, 372d9f6c621SEd Tanous std::string_view(certURL.data(), certURL.size())); 3739b12d1f9SKrzysztof Grobelny }); 3745968caeeSMarri Devender Rao } 3755968caeeSMarri Devender Rao 3767a3a8f7aSJiaqing Zhao static void 3777a3a8f7aSJiaqing Zhao deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3787a3a8f7aSJiaqing Zhao const std::string& service, 3797a3a8f7aSJiaqing Zhao const sdbusplus::message::object_path& objectPath) 3807a3a8f7aSJiaqing Zhao { 3817a3a8f7aSJiaqing Zhao crow::connections::systemBus->async_method_call( 3827a3a8f7aSJiaqing Zhao [asyncResp, 3837a3a8f7aSJiaqing Zhao id{objectPath.filename()}](const boost::system::error_code ec) { 3847a3a8f7aSJiaqing Zhao if (ec) 3857a3a8f7aSJiaqing Zhao { 3867a3a8f7aSJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 3877a3a8f7aSJiaqing Zhao return; 3887a3a8f7aSJiaqing Zhao } 3897a3a8f7aSJiaqing Zhao BMCWEB_LOG_INFO << "Certificate deleted"; 3907a3a8f7aSJiaqing Zhao asyncResp->res.result(boost::beast::http::status::no_content); 3917a3a8f7aSJiaqing Zhao }, 3927a3a8f7aSJiaqing Zhao service, objectPath, certs::objDeleteIntf, "Delete"); 3937a3a8f7aSJiaqing Zhao } 3947a3a8f7aSJiaqing Zhao 395828252d5SJiaqing Zhao inline void handleCertificateServiceGet( 396828252d5SJiaqing Zhao App& app, const crow::Request& req, 397828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3985968caeeSMarri Devender Rao { 399828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 400828252d5SJiaqing Zhao { 401828252d5SJiaqing Zhao return; 402828252d5SJiaqing Zhao } 403828252d5SJiaqing Zhao 404828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 405828252d5SJiaqing Zhao "#CertificateService.v1_0_0.CertificateService"; 406828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService"; 407828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateService"; 408828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Service"; 409828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 410828252d5SJiaqing Zhao "Actions available to manage certificates"; 411828252d5SJiaqing Zhao // /redfish/v1/CertificateService/CertificateLocations is something 412828252d5SJiaqing Zhao // only ConfigureManager can access then only display when the user 413828252d5SJiaqing Zhao // has permissions ConfigureManager 414828252d5SJiaqing Zhao Privileges effectiveUserPrivileges = 415828252d5SJiaqing Zhao redfish::getUserPrivileges(req.userRole); 416828252d5SJiaqing Zhao if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 417828252d5SJiaqing Zhao effectiveUserPrivileges)) 418828252d5SJiaqing Zhao { 419828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = 420828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 421828252d5SJiaqing Zhao } 422828252d5SJiaqing Zhao nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; 423828252d5SJiaqing Zhao nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"]; 424828252d5SJiaqing Zhao replace["target"] = 425828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; 426828252d5SJiaqing Zhao nlohmann::json::array_t allowed; 427828252d5SJiaqing Zhao allowed.push_back("PEM"); 428828252d5SJiaqing Zhao replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); 429828252d5SJiaqing Zhao actions["#CertificateService.GenerateCSR"]["target"] = 430828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; 431828252d5SJiaqing Zhao } 432828252d5SJiaqing Zhao 433828252d5SJiaqing Zhao inline void handleCertificateLocationsGet( 434828252d5SJiaqing Zhao App& app, const crow::Request& req, 435828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 436828252d5SJiaqing Zhao { 437828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 438828252d5SJiaqing Zhao { 439828252d5SJiaqing Zhao return; 440828252d5SJiaqing Zhao } 441828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = 442828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 443828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 444828252d5SJiaqing Zhao "#CertificateLocations.v1_0_0.CertificateLocations"; 445828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Locations"; 446828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateLocations"; 447828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 448828252d5SJiaqing Zhao "Defines a resource that an administrator can use in order to " 449828252d5SJiaqing Zhao "locate all certificates installed on a given service"; 450828252d5SJiaqing Zhao 451828252d5SJiaqing Zhao getCertificateList(asyncResp, certs::baseObjectPath, 452828252d5SJiaqing Zhao "/Links/Certificates"_json_pointer, 453828252d5SJiaqing Zhao "/Links/Certificates@odata.count"_json_pointer); 454828252d5SJiaqing Zhao } 455828252d5SJiaqing Zhao 456828252d5SJiaqing Zhao inline void handleReplaceCertificateAction( 457828252d5SJiaqing Zhao App& app, const crow::Request& req, 458828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 459828252d5SJiaqing Zhao { 4603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 46145ca1b86SEd Tanous { 46245ca1b86SEd Tanous return; 46345ca1b86SEd Tanous } 4645968caeeSMarri Devender Rao std::string certificate; 4655968caeeSMarri Devender Rao nlohmann::json certificateUri; 4665968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 4678d1b46d7Szhanghch05 468002d39b4SEd Tanous if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString", 469002d39b4SEd Tanous certificate, "CertificateUri", 470002d39b4SEd Tanous certificateUri, "CertificateType", 471002d39b4SEd Tanous certificateType)) 4725968caeeSMarri Devender Rao { 4735968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Required parameters are missing"; 4745968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 4755968caeeSMarri Devender Rao return; 4765968caeeSMarri Devender Rao } 4775968caeeSMarri Devender Rao 4785968caeeSMarri Devender Rao if (!certificateType) 4795968caeeSMarri Devender Rao { 4805968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 4815968caeeSMarri Devender Rao return; 4825968caeeSMarri Devender Rao } 4835968caeeSMarri Devender Rao if (certificateType != "PEM") 4845968caeeSMarri Devender Rao { 485828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateType", 486828252d5SJiaqing Zhao "ReplaceCertificate"); 4875968caeeSMarri Devender Rao return; 4885968caeeSMarri Devender Rao } 4895968caeeSMarri Devender Rao 4905968caeeSMarri Devender Rao std::string certURI; 4915968caeeSMarri Devender Rao if (!redfish::json_util::readJson(certificateUri, asyncResp->res, 4925968caeeSMarri Devender Rao "@odata.id", certURI)) 4935968caeeSMarri Devender Rao { 494828252d5SJiaqing Zhao messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate", 495828252d5SJiaqing Zhao "CertificateUri"); 4965968caeeSMarri Devender Rao return; 4975968caeeSMarri Devender Rao } 49875b63a2cSJiaqing Zhao BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI; 4995968caeeSMarri Devender Rao 50075b63a2cSJiaqing Zhao boost::urls::result<boost::urls::url_view> parsedUrl = 50175b63a2cSJiaqing Zhao boost::urls::parse_relative_ref(certURI); 50275b63a2cSJiaqing Zhao if (!parsedUrl) 5035968caeeSMarri Devender Rao { 504828252d5SJiaqing Zhao messages::actionParameterValueFormatError( 505828252d5SJiaqing Zhao asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate"); 5065968caeeSMarri Devender Rao return; 5075968caeeSMarri Devender Rao } 50875b63a2cSJiaqing Zhao 50975b63a2cSJiaqing Zhao std::string id; 51075b63a2cSJiaqing Zhao sdbusplus::message::object_path objectPath; 5115968caeeSMarri Devender Rao std::string name; 51237cce918SMarri Devender Rao std::string service; 513828252d5SJiaqing Zhao if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers", 514828252d5SJiaqing Zhao "bmc", "NetworkProtocol", "HTTPS", 515828252d5SJiaqing Zhao "Certificates", std::ref(id))) 5165968caeeSMarri Devender Rao { 517002d39b4SEd Tanous objectPath = 51875b63a2cSJiaqing Zhao sdbusplus::message::object_path(certs::httpsObjectPath) / id; 5195968caeeSMarri Devender Rao name = "HTTPS certificate"; 52037cce918SMarri Devender Rao service = certs::httpsServiceName; 52137cce918SMarri Devender Rao } 52275b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 52375b63a2cSJiaqing Zhao "AccountService", "LDAP", 52475b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 52537cce918SMarri Devender Rao { 526002d39b4SEd Tanous objectPath = 52775b63a2cSJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 52837cce918SMarri Devender Rao name = "LDAP certificate"; 52937cce918SMarri Devender Rao service = certs::ldapServiceName; 5305968caeeSMarri Devender Rao } 53175b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 53275b63a2cSJiaqing Zhao "Managers", "bmc", "Truststore", 53375b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 534cfcd5f6bSMarri Devender Rao { 53575b63a2cSJiaqing Zhao objectPath = 536828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 537cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 538cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 539cfcd5f6bSMarri Devender Rao } 5405968caeeSMarri Devender Rao else 5415968caeeSMarri Devender Rao { 542828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateUri", 543828252d5SJiaqing Zhao "ReplaceCertificate"); 5445968caeeSMarri Devender Rao return; 5455968caeeSMarri Devender Rao } 5465968caeeSMarri Devender Rao 5475968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 5485968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 5495968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 5501e312598SJiaqing Zhao [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, 5515968caeeSMarri Devender Rao name](const boost::system::error_code ec) { 5525968caeeSMarri Devender Rao if (ec) 5535968caeeSMarri Devender Rao { 5545968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 55590d2d1e8SJiaqing Zhao if (ec.value() == 55690d2d1e8SJiaqing Zhao boost::system::linux_error::bad_request_descriptor) 55790d2d1e8SJiaqing Zhao { 558828252d5SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 5595968caeeSMarri Devender Rao return; 5605968caeeSMarri Devender Rao } 56190d2d1e8SJiaqing Zhao messages::internalError(asyncResp->res); 56290d2d1e8SJiaqing Zhao return; 56390d2d1e8SJiaqing Zhao } 564828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, service, id, url, name); 5655968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 5665968caeeSMarri Devender Rao << certFile->getCertFilePath(); 5675968caeeSMarri Devender Rao }, 5685968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 5695968caeeSMarri Devender Rao certFile->getCertFilePath()); 570828252d5SJiaqing Zhao } 5715968caeeSMarri Devender Rao 572828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher; 5735968caeeSMarri Devender Rao /** 574828252d5SJiaqing Zhao * @brief Read data from CSR D-bus object and set to response 575828252d5SJiaqing Zhao * 576828252d5SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 577828252d5SJiaqing Zhao * @param[in] certURI Link to certifiate collection URI 578828252d5SJiaqing Zhao * @param[in] service D-Bus service name 579828252d5SJiaqing Zhao * @param[in] certObjPath certificate D-Bus object path 580828252d5SJiaqing Zhao * @param[in] csrObjPath CSR D-Bus object path 581828252d5SJiaqing Zhao * @return None 5825968caeeSMarri Devender Rao */ 583828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 584828252d5SJiaqing Zhao const std::string& certURI, const std::string& service, 585828252d5SJiaqing Zhao const std::string& certObjPath, 586828252d5SJiaqing Zhao const std::string& csrObjPath) 5875968caeeSMarri Devender Rao { 588828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath 589828252d5SJiaqing Zhao << " CSRObjectPath=" << csrObjPath 590828252d5SJiaqing Zhao << " service=" << service; 591828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 592828252d5SJiaqing Zhao [asyncResp, certURI](const boost::system::error_code ec, 593828252d5SJiaqing Zhao const std::string& csr) { 594828252d5SJiaqing Zhao if (ec) 595828252d5SJiaqing Zhao { 596828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 597828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 598828252d5SJiaqing Zhao return; 599828252d5SJiaqing Zhao } 600828252d5SJiaqing Zhao if (csr.empty()) 601828252d5SJiaqing Zhao { 602828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "CSR read is empty"; 603828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 604828252d5SJiaqing Zhao return; 605828252d5SJiaqing Zhao } 606828252d5SJiaqing Zhao asyncResp->res.jsonValue["CSRString"] = csr; 607828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = 608828252d5SJiaqing Zhao certURI; 609828252d5SJiaqing Zhao }, 610828252d5SJiaqing Zhao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 611828252d5SJiaqing Zhao } 612828252d5SJiaqing Zhao 613828252d5SJiaqing Zhao inline void 614828252d5SJiaqing Zhao handleGenerateCSRAction(App& app, const crow::Request& req, 615828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 616828252d5SJiaqing Zhao { 6173ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 61845ca1b86SEd Tanous { 61945ca1b86SEd Tanous return; 62045ca1b86SEd Tanous } 621828252d5SJiaqing Zhao static const int rsaKeyBitLength = 2048; 6225968caeeSMarri Devender Rao 623828252d5SJiaqing Zhao // Required parameters 624828252d5SJiaqing Zhao std::string city; 625828252d5SJiaqing Zhao std::string commonName; 626828252d5SJiaqing Zhao std::string country; 627828252d5SJiaqing Zhao std::string organization; 628828252d5SJiaqing Zhao std::string organizationalUnit; 629828252d5SJiaqing Zhao std::string state; 630828252d5SJiaqing Zhao nlohmann::json certificateCollection; 631828252d5SJiaqing Zhao 632828252d5SJiaqing Zhao // Optional parameters 633828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optAlternativeNames = 634828252d5SJiaqing Zhao std::vector<std::string>(); 635828252d5SJiaqing Zhao std::optional<std::string> optContactPerson = ""; 636828252d5SJiaqing Zhao std::optional<std::string> optChallengePassword = ""; 637828252d5SJiaqing Zhao std::optional<std::string> optEmail = ""; 638828252d5SJiaqing Zhao std::optional<std::string> optGivenName = ""; 639828252d5SJiaqing Zhao std::optional<std::string> optInitials = ""; 640828252d5SJiaqing Zhao std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 641828252d5SJiaqing Zhao std::optional<std::string> optKeyCurveId = "secp384r1"; 642828252d5SJiaqing Zhao std::optional<std::string> optKeyPairAlgorithm = "EC"; 643828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optKeyUsage = 644828252d5SJiaqing Zhao std::vector<std::string>(); 645828252d5SJiaqing Zhao std::optional<std::string> optSurname = ""; 646828252d5SJiaqing Zhao std::optional<std::string> optUnstructuredName = ""; 647828252d5SJiaqing Zhao if (!json_util::readJsonAction( 648828252d5SJiaqing Zhao req, asyncResp->res, "City", city, "CommonName", commonName, 649828252d5SJiaqing Zhao "ContactPerson", optContactPerson, "Country", country, 650828252d5SJiaqing Zhao "Organization", organization, "OrganizationalUnit", 651828252d5SJiaqing Zhao organizationalUnit, "State", state, "CertificateCollection", 652828252d5SJiaqing Zhao certificateCollection, "AlternativeNames", optAlternativeNames, 653828252d5SJiaqing Zhao "ChallengePassword", optChallengePassword, "Email", optEmail, 654828252d5SJiaqing Zhao "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength", 655828252d5SJiaqing Zhao optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm", 656828252d5SJiaqing Zhao optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname, 657828252d5SJiaqing Zhao "UnstructuredName", optUnstructuredName)) 658828252d5SJiaqing Zhao { 659828252d5SJiaqing Zhao return; 6605968caeeSMarri Devender Rao } 6615968caeeSMarri Devender Rao 662828252d5SJiaqing Zhao // bmcweb has no way to store or decode a private key challenge 663828252d5SJiaqing Zhao // password, which will likely cause bmcweb to crash on startup 664828252d5SJiaqing Zhao // if this is not set on a post so not allowing the user to set 665828252d5SJiaqing Zhao // value 666828252d5SJiaqing Zhao if (!optChallengePassword->empty()) 6675968caeeSMarri Devender Rao { 668828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 669828252d5SJiaqing Zhao "ChallengePassword"); 670828252d5SJiaqing Zhao return; 671828252d5SJiaqing Zhao } 672828252d5SJiaqing Zhao 673828252d5SJiaqing Zhao std::string certURI; 674828252d5SJiaqing Zhao if (!redfish::json_util::readJson(certificateCollection, asyncResp->res, 675828252d5SJiaqing Zhao "@odata.id", certURI)) 676828252d5SJiaqing Zhao { 677828252d5SJiaqing Zhao return; 678828252d5SJiaqing Zhao } 679828252d5SJiaqing Zhao 680828252d5SJiaqing Zhao std::string objectPath; 681828252d5SJiaqing Zhao std::string service; 682828252d5SJiaqing Zhao if (certURI.starts_with( 683828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 684828252d5SJiaqing Zhao { 685828252d5SJiaqing Zhao objectPath = certs::httpsObjectPath; 686828252d5SJiaqing Zhao service = certs::httpsServiceName; 687828252d5SJiaqing Zhao } 688828252d5SJiaqing Zhao else if (certURI.starts_with( 689828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 690828252d5SJiaqing Zhao { 691828252d5SJiaqing Zhao objectPath = certs::ldapObjectPath; 692828252d5SJiaqing Zhao service = certs::ldapServiceName; 693828252d5SJiaqing Zhao } 694828252d5SJiaqing Zhao else 695828252d5SJiaqing Zhao { 696828252d5SJiaqing Zhao messages::actionParameterNotSupported( 697828252d5SJiaqing Zhao asyncResp->res, "CertificateCollection", "GenerateCSR"); 698828252d5SJiaqing Zhao return; 699828252d5SJiaqing Zhao } 700828252d5SJiaqing Zhao 701828252d5SJiaqing Zhao // supporting only EC and RSA algorithm 702828252d5SJiaqing Zhao if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 703828252d5SJiaqing Zhao { 704828252d5SJiaqing Zhao messages::actionParameterNotSupported( 705828252d5SJiaqing Zhao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 706828252d5SJiaqing Zhao return; 707828252d5SJiaqing Zhao } 708828252d5SJiaqing Zhao 709828252d5SJiaqing Zhao // supporting only 2048 key bit length for RSA algorithm due to 710828252d5SJiaqing Zhao // time consumed in generating private key 711828252d5SJiaqing Zhao if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength) 712828252d5SJiaqing Zhao { 713828252d5SJiaqing Zhao messages::propertyValueNotInList( 714828252d5SJiaqing Zhao asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength"); 715828252d5SJiaqing Zhao return; 716828252d5SJiaqing Zhao } 717828252d5SJiaqing Zhao 718828252d5SJiaqing Zhao // validate KeyUsage supporting only 1 type based on URL 719828252d5SJiaqing Zhao if (certURI.starts_with( 720828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 721828252d5SJiaqing Zhao { 722828252d5SJiaqing Zhao if (optKeyUsage->empty()) 723828252d5SJiaqing Zhao { 724828252d5SJiaqing Zhao optKeyUsage->push_back("ServerAuthentication"); 725828252d5SJiaqing Zhao } 726828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 727828252d5SJiaqing Zhao { 728828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ServerAuthentication") 729828252d5SJiaqing Zhao { 730828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 731828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 732828252d5SJiaqing Zhao return; 733828252d5SJiaqing Zhao } 734828252d5SJiaqing Zhao } 735828252d5SJiaqing Zhao else 736828252d5SJiaqing Zhao { 737828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 738828252d5SJiaqing Zhao "GenerateCSR"); 739828252d5SJiaqing Zhao return; 740828252d5SJiaqing Zhao } 741828252d5SJiaqing Zhao } 742828252d5SJiaqing Zhao else if (certURI.starts_with( 743828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 744828252d5SJiaqing Zhao { 745828252d5SJiaqing Zhao if (optKeyUsage->empty()) 746828252d5SJiaqing Zhao { 747828252d5SJiaqing Zhao optKeyUsage->push_back("ClientAuthentication"); 748828252d5SJiaqing Zhao } 749828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 750828252d5SJiaqing Zhao { 751828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ClientAuthentication") 752828252d5SJiaqing Zhao { 753828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 754828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 755828252d5SJiaqing Zhao return; 756828252d5SJiaqing Zhao } 757828252d5SJiaqing Zhao } 758828252d5SJiaqing Zhao else 759828252d5SJiaqing Zhao { 760828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 761828252d5SJiaqing Zhao "GenerateCSR"); 762828252d5SJiaqing Zhao return; 763828252d5SJiaqing Zhao } 764828252d5SJiaqing Zhao } 765828252d5SJiaqing Zhao 766828252d5SJiaqing Zhao // Only allow one CSR matcher at a time so setting retry 767828252d5SJiaqing Zhao // time-out and timer expiry to 10 seconds for now. 768828252d5SJiaqing Zhao static const int timeOut = 10; 769828252d5SJiaqing Zhao if (csrMatcher) 770828252d5SJiaqing Zhao { 771828252d5SJiaqing Zhao messages::serviceTemporarilyUnavailable(asyncResp->res, 772828252d5SJiaqing Zhao std::to_string(timeOut)); 773828252d5SJiaqing Zhao return; 774828252d5SJiaqing Zhao } 775828252d5SJiaqing Zhao 776828252d5SJiaqing Zhao // Make this static so it survives outside this method 777828252d5SJiaqing Zhao static boost::asio::steady_timer timeout(*req.ioService); 778828252d5SJiaqing Zhao timeout.expires_after(std::chrono::seconds(timeOut)); 779828252d5SJiaqing Zhao timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 780828252d5SJiaqing Zhao csrMatcher = nullptr; 781828252d5SJiaqing Zhao if (ec) 782828252d5SJiaqing Zhao { 783828252d5SJiaqing Zhao // operation_aborted is expected if timer is canceled 784828252d5SJiaqing Zhao // before completion. 785828252d5SJiaqing Zhao if (ec != boost::asio::error::operation_aborted) 786828252d5SJiaqing Zhao { 787828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Async_wait failed " << ec; 788828252d5SJiaqing Zhao } 789828252d5SJiaqing Zhao return; 790828252d5SJiaqing Zhao } 791828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; 792828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 793828252d5SJiaqing Zhao }); 794828252d5SJiaqing Zhao 795828252d5SJiaqing Zhao // create a matcher to wait on CSR object 796828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; 797828252d5SJiaqing Zhao std::string match("type='signal'," 798828252d5SJiaqing Zhao "interface='org.freedesktop.DBus.ObjectManager'," 799828252d5SJiaqing Zhao "path='" + 800828252d5SJiaqing Zhao objectPath + 801828252d5SJiaqing Zhao "'," 802828252d5SJiaqing Zhao "member='InterfacesAdded'"); 803828252d5SJiaqing Zhao csrMatcher = std::make_unique<sdbusplus::bus::match_t>( 804828252d5SJiaqing Zhao *crow::connections::systemBus, match, 805828252d5SJiaqing Zhao [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { 806828252d5SJiaqing Zhao timeout.cancel(); 807828252d5SJiaqing Zhao if (m.is_method_error()) 808828252d5SJiaqing Zhao { 809828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Dbus method error!!!"; 810828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 811828252d5SJiaqing Zhao return; 812828252d5SJiaqing Zhao } 813828252d5SJiaqing Zhao 814828252d5SJiaqing Zhao dbus::utility::DBusInteracesMap interfacesProperties; 815828252d5SJiaqing Zhao 816828252d5SJiaqing Zhao sdbusplus::message::object_path csrObjectPath; 817828252d5SJiaqing Zhao m.read(csrObjectPath, interfacesProperties); 818828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; 819828252d5SJiaqing Zhao for (const auto& interface : interfacesProperties) 820828252d5SJiaqing Zhao { 821828252d5SJiaqing Zhao if (interface.first == "xyz.openbmc_project.Certs.CSR") 822828252d5SJiaqing Zhao { 823828252d5SJiaqing Zhao getCSR(asyncResp, certURI, service, objectPath, 824828252d5SJiaqing Zhao csrObjectPath.str); 825828252d5SJiaqing Zhao break; 826828252d5SJiaqing Zhao } 827828252d5SJiaqing Zhao } 828828252d5SJiaqing Zhao }); 829828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 830828252d5SJiaqing Zhao [asyncResp](const boost::system::error_code ec, const std::string&) { 831828252d5SJiaqing Zhao if (ec) 832828252d5SJiaqing Zhao { 833828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message(); 834828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 835828252d5SJiaqing Zhao return; 836828252d5SJiaqing Zhao } 837828252d5SJiaqing Zhao }, 838828252d5SJiaqing Zhao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 839828252d5SJiaqing Zhao "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 840828252d5SJiaqing Zhao commonName, *optContactPerson, country, *optEmail, *optGivenName, 841828252d5SJiaqing Zhao *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm, 842828252d5SJiaqing Zhao *optKeyUsage, organization, organizationalUnit, state, *optSurname, 843828252d5SJiaqing Zhao *optUnstructuredName); 844828252d5SJiaqing Zhao } 845828252d5SJiaqing Zhao 846828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app) 847828252d5SJiaqing Zhao { 848828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") 849828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateService) 850002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 851828252d5SJiaqing Zhao std::bind_front(handleCertificateServiceGet, std::ref(app))); 852828252d5SJiaqing Zhao 853828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 854828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateLocations) 855828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 856828252d5SJiaqing Zhao std::bind_front(handleCertificateLocationsGet, std::ref(app))); 857828252d5SJiaqing Zhao 858828252d5SJiaqing Zhao BMCWEB_ROUTE( 859828252d5SJiaqing Zhao app, 860828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 861828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 862828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 863828252d5SJiaqing Zhao std::bind_front(handleReplaceCertificateAction, std::ref(app))); 864828252d5SJiaqing Zhao 865828252d5SJiaqing Zhao BMCWEB_ROUTE( 866828252d5SJiaqing Zhao app, 867828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 868828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 869828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 870828252d5SJiaqing Zhao std::bind_front(handleGenerateCSRAction, std::ref(app))); 871828252d5SJiaqing Zhao } // requestRoutesCertificateService 872828252d5SJiaqing Zhao 873828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet( 874828252d5SJiaqing Zhao App& app, const crow::Request& req, 875828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 876828252d5SJiaqing Zhao { 8773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 87845ca1b86SEd Tanous { 87945ca1b86SEd Tanous return; 88045ca1b86SEd Tanous } 8811476687dSEd Tanous 8821476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 8831476687dSEd Tanous "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"; 8841476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 8851476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 8861476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; 8871476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 8881476687dSEd Tanous "A Collection of HTTPS certificate instances"; 8898d1b46d7Szhanghch05 890d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::httpsObjectPath, 891d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 892d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 893828252d5SJiaqing Zhao } 8945968caeeSMarri Devender Rao 895828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost( 896828252d5SJiaqing Zhao App& app, const crow::Request& req, 897828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 898828252d5SJiaqing Zhao { 8993ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 90045ca1b86SEd Tanous { 90145ca1b86SEd Tanous return; 90245ca1b86SEd Tanous } 9035968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; 9048d1b46d7Szhanghch05 9051476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; 9061476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; 9075968caeeSMarri Devender Rao 908002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 90958eb238fSKowalski, Kamil 91058eb238fSKowalski, Kamil if (certFileBody.empty()) 91158eb238fSKowalski, Kamil { 9120fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 913a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 91458eb238fSKowalski, Kamil return; 91558eb238fSKowalski, Kamil } 91658eb238fSKowalski, Kamil 9175968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 91858eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 9195968caeeSMarri Devender Rao 9205968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 921656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 922656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 9235968caeeSMarri Devender Rao if (ec) 9245968caeeSMarri Devender Rao { 9255968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 9265968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 9275968caeeSMarri Devender Rao return; 9285968caeeSMarri Devender Rao } 929717b9802SJiaqing Zhao 930717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 931717b9802SJiaqing Zhao std::string certId = path.filename(); 9321e312598SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 9331e312598SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS", 9341e312598SJiaqing Zhao "Certificates", certId); 935828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName, 936828252d5SJiaqing Zhao certId, certURL, "HTTPS Certificate"); 9375968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 9385968caeeSMarri Devender Rao << certFile->getCertFilePath(); 9395968caeeSMarri Devender Rao }, 940828252d5SJiaqing Zhao certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf, 941828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 942828252d5SJiaqing Zhao } 9435968caeeSMarri Devender Rao 944828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet( 945828252d5SJiaqing Zhao App& app, const crow::Request& req, 946828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 9477e860f15SJohn Edward Broadbent { 9483ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 94945ca1b86SEd Tanous { 95045ca1b86SEd Tanous return; 95145ca1b86SEd Tanous } 9527e860f15SJohn Edward Broadbent 953828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id; 954828252d5SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 955828252d5SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS", 956828252d5SJiaqing Zhao "Certificates", id); 957828252d5SJiaqing Zhao std::string objPath = 958828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::httpsObjectPath) / id; 959828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id, 960828252d5SJiaqing Zhao certURL, "HTTPS Certificate"); 9617e860f15SJohn Edward Broadbent } 96237cce918SMarri Devender Rao 963828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app) 96437cce918SMarri Devender Rao { 965828252d5SJiaqing Zhao BMCWEB_ROUTE(app, 966828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 967ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 968828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 969828252d5SJiaqing Zhao handleHTTPSCertificateCollectionGet, std::ref(app))); 970828252d5SJiaqing Zhao 971828252d5SJiaqing Zhao BMCWEB_ROUTE(app, 972828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 973828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 974828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 975828252d5SJiaqing Zhao handleHTTPSCertificateCollectionPost, std::ref(app))); 976828252d5SJiaqing Zhao 977828252d5SJiaqing Zhao BMCWEB_ROUTE( 978828252d5SJiaqing Zhao app, 979828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/") 980828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 981002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 982828252d5SJiaqing Zhao std::bind_front(handleHTTPSCertificateGet, std::ref(app))); 983828252d5SJiaqing Zhao } 984828252d5SJiaqing Zhao 985828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet( 986828252d5SJiaqing Zhao App& app, const crow::Request& req, 987828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 988828252d5SJiaqing Zhao { 9893ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 99045ca1b86SEd Tanous { 99145ca1b86SEd Tanous return; 99245ca1b86SEd Tanous } 9931476687dSEd Tanous 9941476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 9951476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 9961476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 9971476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 9981476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; 9991476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 10001476687dSEd Tanous "A Collection of LDAP certificate instances"; 10018d1b46d7Szhanghch05 1002d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::ldapObjectPath, 1003d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1004d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1005828252d5SJiaqing Zhao } 100637cce918SMarri Devender Rao 1007828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost( 1008828252d5SJiaqing Zhao App& app, const crow::Request& req, 1009828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1010828252d5SJiaqing Zhao { 10113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 101245ca1b86SEd Tanous { 101345ca1b86SEd Tanous return; 101445ca1b86SEd Tanous } 1015002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 101658eb238fSKowalski, Kamil 101758eb238fSKowalski, Kamil if (certFileBody.empty()) 101858eb238fSKowalski, Kamil { 1019002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1020a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 102158eb238fSKowalski, Kamil return; 102258eb238fSKowalski, Kamil } 102358eb238fSKowalski, Kamil 102458eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 102558eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 102658eb238fSKowalski, Kamil 102737cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 1028656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1029656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 103037cce918SMarri Devender Rao if (ec) 103137cce918SMarri Devender Rao { 103237cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 103337cce918SMarri Devender Rao messages::internalError(asyncResp->res); 103437cce918SMarri Devender Rao return; 103537cce918SMarri Devender Rao } 1036717b9802SJiaqing Zhao 1037717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1038717b9802SJiaqing Zhao std::string certId = path.filename(); 1039828252d5SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 1040828252d5SJiaqing Zhao "redfish", "v1", "AccountService", "LDAP", "Certificates", certId); 1041828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName, 1042828252d5SJiaqing Zhao certId, certURL, "LDAP Certificate"); 104337cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "LDAP certificate install file=" 104437cce918SMarri Devender Rao << certFile->getCertFilePath(); 104537cce918SMarri Devender Rao }, 1046828252d5SJiaqing Zhao certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf, 1047828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 1048828252d5SJiaqing Zhao } 104937cce918SMarri Devender Rao 1050828252d5SJiaqing Zhao inline void handleLDAPCertificateGet( 1051828252d5SJiaqing Zhao App& app, const crow::Request& req, 1052828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 105337cce918SMarri Devender Rao { 10543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 105545ca1b86SEd Tanous { 105645ca1b86SEd Tanous return; 105745ca1b86SEd Tanous } 1058717b9802SJiaqing Zhao 1059717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id; 10601e312598SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 10611e312598SJiaqing Zhao "redfish", "v1", "AccountService", "LDAP", "Certificates", id); 1062717b9802SJiaqing Zhao std::string objPath = 1063717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 1064717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, 1065717b9802SJiaqing Zhao certURL, "LDAP Certificate"); 1066828252d5SJiaqing Zhao } 1067828252d5SJiaqing Zhao 106899612247SJiaqing Zhao inline void handleLDAPCertificateDelete( 106999612247SJiaqing Zhao App& app, const crow::Request& req, 107099612247SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 107199612247SJiaqing Zhao { 107299612247SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 107399612247SJiaqing Zhao { 107499612247SJiaqing Zhao return; 107599612247SJiaqing Zhao } 107699612247SJiaqing Zhao 107799612247SJiaqing Zhao BMCWEB_LOG_DEBUG << "Delete LDAP Certificate ID=" << id; 107899612247SJiaqing Zhao std::string objPath = 107999612247SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 108099612247SJiaqing Zhao 108199612247SJiaqing Zhao deleteCertificate(asyncResp, certs::ldapServiceName, objPath); 108299612247SJiaqing Zhao } 108399612247SJiaqing Zhao 1084828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app) 1085cfcd5f6bSMarri Devender Rao { 1086828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1087828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateCollection) 1088828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1089828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app))); 1090828252d5SJiaqing Zhao 1091828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1092828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1093828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1094828252d5SJiaqing Zhao handleLDAPCertificateCollectionPost, std::ref(app))); 1095828252d5SJiaqing Zhao 1096828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1097ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 1098002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1099828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateGet, std::ref(app))); 110099612247SJiaqing Zhao 110199612247SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 110299612247SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 110399612247SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 110499612247SJiaqing Zhao std::bind_front(handleLDAPCertificateDelete, std::ref(app))); 1105828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate 1106828252d5SJiaqing Zhao 1107828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet( 1108828252d5SJiaqing Zhao App& app, const crow::Request& req, 1109828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1110828252d5SJiaqing Zhao { 11113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 111245ca1b86SEd Tanous { 111345ca1b86SEd Tanous return; 111445ca1b86SEd Tanous } 11151476687dSEd Tanous 11161476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 11171476687dSEd Tanous "/redfish/v1/Managers/bmc/Truststore/Certificates/"; 11181476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 11191476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 1120002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; 11211476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 11221476687dSEd Tanous "A Collection of TrustStore certificate instances"; 11238d1b46d7Szhanghch05 1124d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::authorityObjectPath, 1125d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1126d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1127828252d5SJiaqing Zhao } 1128cfcd5f6bSMarri Devender Rao 1129828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost( 1130828252d5SJiaqing Zhao App& app, const crow::Request& req, 1131828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1132828252d5SJiaqing Zhao { 11333ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 113445ca1b86SEd Tanous { 113545ca1b86SEd Tanous return; 113645ca1b86SEd Tanous } 1137002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 1138a08752f5SZbigniew Kurzynski 1139a08752f5SZbigniew Kurzynski if (certFileBody.empty()) 1140a08752f5SZbigniew Kurzynski { 11410fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1142a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1143a08752f5SZbigniew Kurzynski return; 1144a08752f5SZbigniew Kurzynski } 1145a08752f5SZbigniew Kurzynski 1146a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1147a08752f5SZbigniew Kurzynski std::make_shared<CertificateFile>(certFileBody); 1148cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1149656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1150656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1151cfcd5f6bSMarri Devender Rao if (ec) 1152cfcd5f6bSMarri Devender Rao { 1153cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1154cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1155cfcd5f6bSMarri Devender Rao return; 1156cfcd5f6bSMarri Devender Rao } 1157656ec7e3SZbigniew Kurzynski 1158717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1159717b9802SJiaqing Zhao std::string certId = path.filename(); 1160828252d5SJiaqing Zhao const boost::urls::url certURL = 1161828252d5SJiaqing Zhao crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc", 1162828252d5SJiaqing Zhao "Truststore", "Certificates", certId); 1163717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, 1164828252d5SJiaqing Zhao certs::authorityServiceName, certId, certURL, 1165828252d5SJiaqing Zhao "TrustStore Certificate"); 11660fda0f12SGeorge Liu BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" 1167cfcd5f6bSMarri Devender Rao << certFile->getCertFilePath(); 1168cfcd5f6bSMarri Devender Rao }, 1169cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 11700fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 1171828252d5SJiaqing Zhao } 1172cfcd5f6bSMarri Devender Rao 1173828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet( 1174828252d5SJiaqing Zhao App& app, const crow::Request& req, 1175828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1176cfcd5f6bSMarri Devender Rao { 11773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117845ca1b86SEd Tanous { 117945ca1b86SEd Tanous return; 118045ca1b86SEd Tanous } 1181717b9802SJiaqing Zhao 1182717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id; 1183828252d5SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 1184828252d5SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id); 1185717b9802SJiaqing Zhao std::string objPath = 1186717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 1187828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::authorityServiceName, 1188828252d5SJiaqing Zhao id, certURL, "TrustStore Certificate"); 1189828252d5SJiaqing Zhao } 119007a60299SZbigniew Kurzynski 1191828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete( 1192828252d5SJiaqing Zhao App& app, const crow::Request& req, 1193828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1194828252d5SJiaqing Zhao { 11953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 119645ca1b86SEd Tanous { 119745ca1b86SEd Tanous return; 119845ca1b86SEd Tanous } 119907a60299SZbigniew Kurzynski 1200717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id; 1201717b9802SJiaqing Zhao std::string objPath = 1202717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 120307a60299SZbigniew Kurzynski 12047a3a8f7aSJiaqing Zhao deleteCertificate(asyncResp, certs::authorityServiceName, objPath); 1205828252d5SJiaqing Zhao } 1206828252d5SJiaqing Zhao 1207828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app) 1208828252d5SJiaqing Zhao { 1209828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1210828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1211828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 1212828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionGet, std::ref(app))); 1213828252d5SJiaqing Zhao 1214828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1215828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1216828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1217828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionPost, std::ref(app))); 1218828252d5SJiaqing Zhao 1219828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1220828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1221828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1222828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateGet, std::ref(app))); 1223828252d5SJiaqing Zhao 1224828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1225828252d5SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 1226828252d5SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 1227828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateDelete, std::ref(app))); 12287e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate 12295968caeeSMarri Devender Rao } // namespace redfish 1230