15968caeeSMarri Devender Rao #pragma once 25968caeeSMarri Devender Rao 39b12d1f9SKrzysztof Grobelny #include "utils/dbus_utils.hpp" 49b12d1f9SKrzysztof Grobelny 57e860f15SJohn Edward Broadbent #include <app.hpp> 6d9f6c621SEd Tanous #include <async_resp.hpp> 790d2d1e8SJiaqing Zhao #include <boost/system/linux_error.hpp> 8168e20c1SEd Tanous #include <dbus_utility.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 155968caeeSMarri Devender Rao namespace redfish 165968caeeSMarri Devender Rao { 175968caeeSMarri Devender Rao namespace certs 185968caeeSMarri Devender Rao { 195968caeeSMarri Devender Rao constexpr char const* certInstallIntf = "xyz.openbmc_project.Certs.Install"; 205968caeeSMarri Devender Rao constexpr char const* certReplaceIntf = "xyz.openbmc_project.Certs.Replace"; 2107a60299SZbigniew Kurzynski constexpr char const* objDeleteIntf = "xyz.openbmc_project.Object.Delete"; 225968caeeSMarri Devender Rao constexpr char const* certPropIntf = "xyz.openbmc_project.Certs.Certificate"; 235968caeeSMarri Devender Rao constexpr char const* dbusPropIntf = "org.freedesktop.DBus.Properties"; 245968caeeSMarri Devender Rao constexpr char const* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 2537cce918SMarri Devender Rao constexpr char const* httpsServiceName = 2637cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Server.Https"; 2737cce918SMarri Devender Rao constexpr char const* ldapServiceName = 2837cce918SMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Client.Ldap"; 29cfcd5f6bSMarri Devender Rao constexpr char const* authorityServiceName = 30cfcd5f6bSMarri Devender Rao "xyz.openbmc_project.Certs.Manager.Authority.Ldap"; 31c6a8dfb1SJiaqing Zhao constexpr char const* baseObjectPath = "/xyz/openbmc_project/certs"; 32c6a8dfb1SJiaqing Zhao constexpr char const* httpsObjectPath = 33c6a8dfb1SJiaqing Zhao "/xyz/openbmc_project/certs/server/https"; 34c6a8dfb1SJiaqing Zhao constexpr char const* ldapObjectPath = "/xyz/openbmc_project/certs/client/ldap"; 35cfcd5f6bSMarri Devender Rao constexpr char const* authorityObjectPath = 36cfcd5f6bSMarri Devender Rao "/xyz/openbmc_project/certs/authority/ldap"; 375968caeeSMarri Devender Rao } // namespace certs 385968caeeSMarri Devender Rao 395968caeeSMarri Devender Rao /** 405968caeeSMarri Devender Rao * The Certificate schema defines a Certificate Service which represents the 415968caeeSMarri Devender Rao * actions available to manage certificates and links to where certificates 425968caeeSMarri Devender Rao * are installed. 435968caeeSMarri Devender Rao */ 447e860f15SJohn Edward Broadbent 455968caeeSMarri Devender Rao // TODO: Issue#61 No entries are available for Certificate 464e0453b1SGunnar Mills // service at https://www.dmtf.org/standards/redfish 475968caeeSMarri Devender Rao // "redfish standard registries". Need to modify after DMTF 485968caeeSMarri Devender Rao // publish Privilege details for certificate service 495968caeeSMarri Devender Rao 508d1b46d7Szhanghch05 inline std::string getCertificateFromReqBody( 518d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5258eb238fSKowalski, Kamil const crow::Request& req) 5358eb238fSKowalski, Kamil { 5458eb238fSKowalski, Kamil nlohmann::json reqJson = nlohmann::json::parse(req.body, nullptr, false); 5558eb238fSKowalski, Kamil 5658eb238fSKowalski, Kamil if (reqJson.is_discarded()) 5758eb238fSKowalski, Kamil { 5858eb238fSKowalski, Kamil // We did not receive JSON request, proceed as it is RAW data 5958eb238fSKowalski, Kamil return req.body; 6058eb238fSKowalski, Kamil } 6158eb238fSKowalski, Kamil 6258eb238fSKowalski, Kamil std::string certificate; 6358eb238fSKowalski, Kamil std::optional<std::string> certificateType = "PEM"; 6458eb238fSKowalski, Kamil 6515ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, "CertificateString", 6615ed6780SWilly Tu certificate, "CertificateType", 6715ed6780SWilly Tu certificateType)) 6858eb238fSKowalski, Kamil { 6958eb238fSKowalski, Kamil BMCWEB_LOG_ERROR << "Required parameters are missing"; 7058eb238fSKowalski, Kamil messages::internalError(asyncResp->res); 71abb93cddSEd Tanous return {}; 7258eb238fSKowalski, Kamil } 7358eb238fSKowalski, Kamil 7458eb238fSKowalski, Kamil if (*certificateType != "PEM") 7558eb238fSKowalski, Kamil { 7658eb238fSKowalski, Kamil messages::propertyValueNotInList(asyncResp->res, *certificateType, 7758eb238fSKowalski, Kamil "CertificateType"); 78abb93cddSEd Tanous return {}; 7958eb238fSKowalski, Kamil } 8058eb238fSKowalski, Kamil 8158eb238fSKowalski, Kamil return certificate; 8258eb238fSKowalski, Kamil } 8358eb238fSKowalski, Kamil 845968caeeSMarri Devender Rao /** 855968caeeSMarri Devender Rao * Class to create a temporary certificate file for uploading to system 865968caeeSMarri Devender Rao */ 875968caeeSMarri Devender Rao class CertificateFile 885968caeeSMarri Devender Rao { 895968caeeSMarri Devender Rao public: 905968caeeSMarri Devender Rao CertificateFile() = delete; 915968caeeSMarri Devender Rao CertificateFile(const CertificateFile&) = delete; 925968caeeSMarri Devender Rao CertificateFile& operator=(const CertificateFile&) = delete; 935968caeeSMarri Devender Rao CertificateFile(CertificateFile&&) = delete; 945968caeeSMarri Devender Rao CertificateFile& operator=(CertificateFile&&) = delete; 954e23a444SEd Tanous explicit CertificateFile(const std::string& certString) 965968caeeSMarri Devender Rao { 9772d52d25SEd Tanous std::array<char, 18> dirTemplate = {'/', 't', 'm', 'p', '/', 'C', 985207438cSEd Tanous 'e', 'r', 't', 's', '.', 'X', 995207438cSEd Tanous 'X', 'X', 'X', 'X', 'X', '\0'}; 1005207438cSEd Tanous char* tempDirectory = mkdtemp(dirTemplate.data()); 101e662eae8SEd Tanous if (tempDirectory != nullptr) 1025968caeeSMarri Devender Rao { 1035968caeeSMarri Devender Rao certDirectory = tempDirectory; 1045968caeeSMarri Devender Rao certificateFile = certDirectory / "cert.pem"; 1055968caeeSMarri Devender Rao std::ofstream out(certificateFile, std::ofstream::out | 1065968caeeSMarri Devender Rao std::ofstream::binary | 1075968caeeSMarri Devender Rao std::ofstream::trunc); 1085968caeeSMarri Devender Rao out << certString; 1095968caeeSMarri Devender Rao out.close(); 1108cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Creating certificate file" 1118cc8edecSEd Tanous << certificateFile.string(); 1125968caeeSMarri Devender Rao } 1135968caeeSMarri Devender Rao } 1145968caeeSMarri Devender Rao ~CertificateFile() 1155968caeeSMarri Devender Rao { 1165968caeeSMarri Devender Rao if (std::filesystem::exists(certDirectory)) 1175968caeeSMarri Devender Rao { 1188cc8edecSEd Tanous BMCWEB_LOG_DEBUG << "Removing certificate file" 1198cc8edecSEd Tanous << certificateFile.string(); 12023a21a1cSEd Tanous std::error_code ec; 12123a21a1cSEd Tanous std::filesystem::remove_all(certDirectory, ec); 12223a21a1cSEd Tanous if (ec) 1235968caeeSMarri Devender Rao { 1245968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Failed to remove temp directory" 1258cc8edecSEd Tanous << certDirectory.string(); 1265968caeeSMarri Devender Rao } 1275968caeeSMarri Devender Rao } 1285968caeeSMarri Devender Rao } 1295968caeeSMarri Devender Rao std::string getCertFilePath() 1305968caeeSMarri Devender Rao { 1315968caeeSMarri Devender Rao return certificateFile; 1325968caeeSMarri Devender Rao } 1335968caeeSMarri Devender Rao 1345968caeeSMarri Devender Rao private: 1355968caeeSMarri Devender Rao std::filesystem::path certificateFile; 1365968caeeSMarri Devender Rao std::filesystem::path certDirectory; 1375968caeeSMarri Devender Rao }; 1385968caeeSMarri Devender Rao 1395968caeeSMarri Devender Rao /** 1404e0453b1SGunnar Mills * @brief Parse and update Certificate Issue/Subject property 1415968caeeSMarri Devender Rao * 1425968caeeSMarri Devender Rao * @param[in] asyncResp Shared pointer to the response message 1435968caeeSMarri Devender Rao * @param[in] str Issuer/Subject value in key=value pairs 1445968caeeSMarri Devender Rao * @param[in] type Issuer/Subject 1455968caeeSMarri Devender Rao * @return None 1465968caeeSMarri Devender Rao */ 1475968caeeSMarri Devender Rao static void updateCertIssuerOrSubject(nlohmann::json& out, 1485968caeeSMarri Devender Rao const std::string_view value) 1495968caeeSMarri Devender Rao { 1505968caeeSMarri Devender Rao // example: O=openbmc-project.xyz,CN=localhost 1515968caeeSMarri Devender Rao std::string_view::iterator i = value.begin(); 1525968caeeSMarri Devender Rao while (i != value.end()) 1535968caeeSMarri Devender Rao { 1545968caeeSMarri Devender Rao std::string_view::iterator tokenBegin = i; 1555968caeeSMarri Devender Rao while (i != value.end() && *i != '=') 1565968caeeSMarri Devender Rao { 15717a897dfSManojkiran Eda ++i; 1585968caeeSMarri Devender Rao } 1595968caeeSMarri Devender Rao if (i == value.end()) 1605968caeeSMarri Devender Rao { 1615968caeeSMarri Devender Rao break; 1625968caeeSMarri Devender Rao } 163271584abSEd Tanous const std::string_view key(tokenBegin, 164271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 16517a897dfSManojkiran Eda ++i; 1665968caeeSMarri Devender Rao tokenBegin = i; 1675968caeeSMarri Devender Rao while (i != value.end() && *i != ',') 1685968caeeSMarri Devender Rao { 16917a897dfSManojkiran Eda ++i; 1705968caeeSMarri Devender Rao } 171271584abSEd Tanous const std::string_view val(tokenBegin, 172271584abSEd Tanous static_cast<size_t>(i - tokenBegin)); 1735968caeeSMarri Devender Rao if (key == "L") 1745968caeeSMarri Devender Rao { 1755968caeeSMarri Devender Rao out["City"] = val; 1765968caeeSMarri Devender Rao } 1775968caeeSMarri Devender Rao else if (key == "CN") 1785968caeeSMarri Devender Rao { 1795968caeeSMarri Devender Rao out["CommonName"] = val; 1805968caeeSMarri Devender Rao } 1815968caeeSMarri Devender Rao else if (key == "C") 1825968caeeSMarri Devender Rao { 1835968caeeSMarri Devender Rao out["Country"] = val; 1845968caeeSMarri Devender Rao } 1855968caeeSMarri Devender Rao else if (key == "O") 1865968caeeSMarri Devender Rao { 1875968caeeSMarri Devender Rao out["Organization"] = val; 1885968caeeSMarri Devender Rao } 1895968caeeSMarri Devender Rao else if (key == "OU") 1905968caeeSMarri Devender Rao { 1915968caeeSMarri Devender Rao out["OrganizationalUnit"] = val; 1925968caeeSMarri Devender Rao } 1935968caeeSMarri Devender Rao else if (key == "ST") 1945968caeeSMarri Devender Rao { 1955968caeeSMarri Devender Rao out["State"] = val; 1965968caeeSMarri Devender Rao } 1975968caeeSMarri Devender Rao // skip comma character 1985968caeeSMarri Devender Rao if (i != value.end()) 1995968caeeSMarri Devender Rao { 20017a897dfSManojkiran Eda ++i; 2015968caeeSMarri Devender Rao } 2025968caeeSMarri Devender Rao } 2035968caeeSMarri Devender Rao } 2045968caeeSMarri Devender Rao 2055968caeeSMarri Devender Rao /** 206d3f92ce7SJiaqing Zhao * @brief Retrieve the installed certificate list 207d3f92ce7SJiaqing Zhao * 208d3f92ce7SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 209d3f92ce7SJiaqing Zhao * @param[in] basePath DBus object path to search 210d3f92ce7SJiaqing Zhao * @param[in] listPtr Json pointer to the list in asyncResp 211d3f92ce7SJiaqing Zhao * @param[in] countPtr Json pointer to the count in asyncResp 212d3f92ce7SJiaqing Zhao * @return None 213d3f92ce7SJiaqing Zhao */ 214d3f92ce7SJiaqing Zhao static void 215d3f92ce7SJiaqing Zhao getCertificateList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 216d3f92ce7SJiaqing Zhao const std::string& basePath, 217d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& listPtr, 218d3f92ce7SJiaqing Zhao const nlohmann::json::json_pointer& countPtr) 219d3f92ce7SJiaqing Zhao { 220d3f92ce7SJiaqing Zhao crow::connections::systemBus->async_method_call( 221d3f92ce7SJiaqing Zhao [asyncResp, listPtr, countPtr]( 222d3f92ce7SJiaqing Zhao const boost::system::error_code ec, 223d3f92ce7SJiaqing Zhao const dbus::utility::MapperGetSubTreePathsResponse& certPaths) { 224d3f92ce7SJiaqing Zhao if (ec) 225d3f92ce7SJiaqing Zhao { 226d3f92ce7SJiaqing Zhao BMCWEB_LOG_ERROR << "Certificate collection query failed: " << ec; 227d3f92ce7SJiaqing Zhao messages::internalError(asyncResp->res); 228d3f92ce7SJiaqing Zhao return; 229d3f92ce7SJiaqing Zhao } 230d3f92ce7SJiaqing Zhao 231d3f92ce7SJiaqing Zhao nlohmann::json& links = asyncResp->res.jsonValue[listPtr]; 232d3f92ce7SJiaqing Zhao links = nlohmann::json::array(); 233d3f92ce7SJiaqing Zhao for (const auto& certPath : certPaths) 234d3f92ce7SJiaqing Zhao { 235d3f92ce7SJiaqing Zhao sdbusplus::message::object_path objPath(certPath); 236d3f92ce7SJiaqing Zhao std::string certId = objPath.filename(); 237d3f92ce7SJiaqing Zhao if (certId.empty()) 238d3f92ce7SJiaqing Zhao { 239d3f92ce7SJiaqing Zhao BMCWEB_LOG_ERROR << "Invalid certificate objPath " << certPath; 240d3f92ce7SJiaqing Zhao continue; 241d3f92ce7SJiaqing Zhao } 242d3f92ce7SJiaqing Zhao 243d3f92ce7SJiaqing Zhao boost::urls::url certURL; 244d3f92ce7SJiaqing Zhao if (objPath.parent_path() == certs::httpsObjectPath) 245d3f92ce7SJiaqing Zhao { 246d3f92ce7SJiaqing Zhao certURL = crow::utility::urlFromPieces( 247d3f92ce7SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "NetworkProtocol", 248d3f92ce7SJiaqing Zhao "HTTPS", "Certificates", certId); 249d3f92ce7SJiaqing Zhao } 250d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::ldapObjectPath) 251d3f92ce7SJiaqing Zhao { 252d3f92ce7SJiaqing Zhao certURL = crow::utility::urlFromPieces("redfish", "v1", 253d3f92ce7SJiaqing Zhao "AccountService", "LDAP", 254d3f92ce7SJiaqing Zhao "Certificates", certId); 255d3f92ce7SJiaqing Zhao } 256d3f92ce7SJiaqing Zhao else if (objPath.parent_path() == certs::authorityObjectPath) 257d3f92ce7SJiaqing Zhao { 258d3f92ce7SJiaqing Zhao certURL = crow::utility::urlFromPieces( 259d3f92ce7SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "Truststore", 260d3f92ce7SJiaqing Zhao "Certificates", certId); 261d3f92ce7SJiaqing Zhao } 262d3f92ce7SJiaqing Zhao else 263d3f92ce7SJiaqing Zhao { 264d3f92ce7SJiaqing Zhao continue; 265d3f92ce7SJiaqing Zhao } 266d3f92ce7SJiaqing Zhao 267d3f92ce7SJiaqing Zhao nlohmann::json::object_t link; 268d3f92ce7SJiaqing Zhao link["@odata.id"] = certURL; 269d3f92ce7SJiaqing Zhao links.emplace_back(std::move(link)); 270d3f92ce7SJiaqing Zhao } 271d3f92ce7SJiaqing Zhao 272d3f92ce7SJiaqing Zhao asyncResp->res.jsonValue[countPtr] = links.size(); 273d3f92ce7SJiaqing Zhao }, 274d3f92ce7SJiaqing Zhao "xyz.openbmc_project.ObjectMapper", 275d3f92ce7SJiaqing Zhao "/xyz/openbmc_project/object_mapper", 276d3f92ce7SJiaqing Zhao "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", basePath, 0, 277d3f92ce7SJiaqing Zhao std::array<const char*, 1>{certs::certPropIntf}); 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, 302b9d36b47SEd 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 379*7a3a8f7aSJiaqing Zhao static void 380*7a3a8f7aSJiaqing Zhao deleteCertificate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 381*7a3a8f7aSJiaqing Zhao const std::string& service, 382*7a3a8f7aSJiaqing Zhao const sdbusplus::message::object_path& objectPath) 383*7a3a8f7aSJiaqing Zhao { 384*7a3a8f7aSJiaqing Zhao crow::connections::systemBus->async_method_call( 385*7a3a8f7aSJiaqing Zhao [asyncResp, 386*7a3a8f7aSJiaqing Zhao id{objectPath.filename()}](const boost::system::error_code ec) { 387*7a3a8f7aSJiaqing Zhao if (ec) 388*7a3a8f7aSJiaqing Zhao { 389*7a3a8f7aSJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 390*7a3a8f7aSJiaqing Zhao return; 391*7a3a8f7aSJiaqing Zhao } 392*7a3a8f7aSJiaqing Zhao BMCWEB_LOG_INFO << "Certificate deleted"; 393*7a3a8f7aSJiaqing Zhao asyncResp->res.result(boost::beast::http::status::no_content); 394*7a3a8f7aSJiaqing Zhao }, 395*7a3a8f7aSJiaqing Zhao service, objectPath, certs::objDeleteIntf, "Delete"); 396*7a3a8f7aSJiaqing Zhao } 397*7a3a8f7aSJiaqing 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 407828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 408828252d5SJiaqing Zhao "#CertificateService.v1_0_0.CertificateService"; 409828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/CertificateService"; 410828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateService"; 411828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Service"; 412828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 413828252d5SJiaqing Zhao "Actions available to manage certificates"; 414828252d5SJiaqing Zhao // /redfish/v1/CertificateService/CertificateLocations is something 415828252d5SJiaqing Zhao // only ConfigureManager can access then only display when the user 416828252d5SJiaqing Zhao // has permissions ConfigureManager 417828252d5SJiaqing Zhao Privileges effectiveUserPrivileges = 418828252d5SJiaqing Zhao redfish::getUserPrivileges(req.userRole); 419828252d5SJiaqing Zhao if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 420828252d5SJiaqing Zhao effectiveUserPrivileges)) 421828252d5SJiaqing Zhao { 422828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateLocations"]["@odata.id"] = 423828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 424828252d5SJiaqing Zhao } 425828252d5SJiaqing Zhao nlohmann::json& actions = asyncResp->res.jsonValue["Actions"]; 426828252d5SJiaqing Zhao nlohmann::json& replace = actions["#CertificateService.ReplaceCertificate"]; 427828252d5SJiaqing Zhao replace["target"] = 428828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"; 429828252d5SJiaqing Zhao nlohmann::json::array_t allowed; 430828252d5SJiaqing Zhao allowed.push_back("PEM"); 431828252d5SJiaqing Zhao replace["CertificateType@Redfish.AllowableValues"] = std::move(allowed); 432828252d5SJiaqing Zhao actions["#CertificateService.GenerateCSR"]["target"] = 433828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"; 434828252d5SJiaqing Zhao } 435828252d5SJiaqing Zhao 436828252d5SJiaqing Zhao inline void handleCertificateLocationsGet( 437828252d5SJiaqing Zhao App& app, const crow::Request& req, 438828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 439828252d5SJiaqing Zhao { 440828252d5SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 441828252d5SJiaqing Zhao { 442828252d5SJiaqing Zhao return; 443828252d5SJiaqing Zhao } 444828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.id"] = 445828252d5SJiaqing Zhao "/redfish/v1/CertificateService/CertificateLocations"; 446828252d5SJiaqing Zhao asyncResp->res.jsonValue["@odata.type"] = 447828252d5SJiaqing Zhao "#CertificateLocations.v1_0_0.CertificateLocations"; 448828252d5SJiaqing Zhao asyncResp->res.jsonValue["Name"] = "Certificate Locations"; 449828252d5SJiaqing Zhao asyncResp->res.jsonValue["Id"] = "CertificateLocations"; 450828252d5SJiaqing Zhao asyncResp->res.jsonValue["Description"] = 451828252d5SJiaqing Zhao "Defines a resource that an administrator can use in order to " 452828252d5SJiaqing Zhao "locate all certificates installed on a given service"; 453828252d5SJiaqing Zhao 454828252d5SJiaqing Zhao getCertificateList(asyncResp, certs::baseObjectPath, 455828252d5SJiaqing Zhao "/Links/Certificates"_json_pointer, 456828252d5SJiaqing Zhao "/Links/Certificates@odata.count"_json_pointer); 457828252d5SJiaqing Zhao } 458828252d5SJiaqing Zhao 459828252d5SJiaqing Zhao inline void handleReplaceCertificateAction( 460828252d5SJiaqing Zhao App& app, const crow::Request& req, 461828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 462828252d5SJiaqing Zhao { 4633ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 46445ca1b86SEd Tanous { 46545ca1b86SEd Tanous return; 46645ca1b86SEd Tanous } 4675968caeeSMarri Devender Rao std::string certificate; 4685968caeeSMarri Devender Rao nlohmann::json certificateUri; 4695968caeeSMarri Devender Rao std::optional<std::string> certificateType = "PEM"; 4708d1b46d7Szhanghch05 471002d39b4SEd Tanous if (!json_util::readJsonAction(req, asyncResp->res, "CertificateString", 472002d39b4SEd Tanous certificate, "CertificateUri", 473002d39b4SEd Tanous certificateUri, "CertificateType", 474002d39b4SEd Tanous certificateType)) 4755968caeeSMarri Devender Rao { 4765968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "Required parameters are missing"; 4775968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 4785968caeeSMarri Devender Rao return; 4795968caeeSMarri Devender Rao } 4805968caeeSMarri Devender Rao 4815968caeeSMarri Devender Rao if (!certificateType) 4825968caeeSMarri Devender Rao { 4835968caeeSMarri Devender Rao // should never happen, but it never hurts to be paranoid. 4845968caeeSMarri Devender Rao return; 4855968caeeSMarri Devender Rao } 4865968caeeSMarri Devender Rao if (certificateType != "PEM") 4875968caeeSMarri Devender Rao { 488828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateType", 489828252d5SJiaqing Zhao "ReplaceCertificate"); 4905968caeeSMarri Devender Rao return; 4915968caeeSMarri Devender Rao } 4925968caeeSMarri Devender Rao 4935968caeeSMarri Devender Rao std::string certURI; 4945968caeeSMarri Devender Rao if (!redfish::json_util::readJson(certificateUri, asyncResp->res, 4955968caeeSMarri Devender Rao "@odata.id", certURI)) 4965968caeeSMarri Devender Rao { 497828252d5SJiaqing Zhao messages::actionParameterMissing(asyncResp->res, "ReplaceCertificate", 498828252d5SJiaqing Zhao "CertificateUri"); 4995968caeeSMarri Devender Rao return; 5005968caeeSMarri Devender Rao } 50175b63a2cSJiaqing Zhao BMCWEB_LOG_INFO << "Certificate URI to replace: " << certURI; 5025968caeeSMarri Devender Rao 50375b63a2cSJiaqing Zhao boost::urls::result<boost::urls::url_view> parsedUrl = 50475b63a2cSJiaqing Zhao boost::urls::parse_relative_ref(certURI); 50575b63a2cSJiaqing Zhao if (!parsedUrl) 5065968caeeSMarri Devender Rao { 507828252d5SJiaqing Zhao messages::actionParameterValueFormatError( 508828252d5SJiaqing Zhao asyncResp->res, certURI, "CertificateUri", "ReplaceCertificate"); 5095968caeeSMarri Devender Rao return; 5105968caeeSMarri Devender Rao } 51175b63a2cSJiaqing Zhao 51275b63a2cSJiaqing Zhao std::string id; 51375b63a2cSJiaqing Zhao sdbusplus::message::object_path objectPath; 5145968caeeSMarri Devender Rao std::string name; 51537cce918SMarri Devender Rao std::string service; 516828252d5SJiaqing Zhao if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", "Managers", 517828252d5SJiaqing Zhao "bmc", "NetworkProtocol", "HTTPS", 518828252d5SJiaqing Zhao "Certificates", std::ref(id))) 5195968caeeSMarri Devender Rao { 520002d39b4SEd Tanous objectPath = 52175b63a2cSJiaqing Zhao sdbusplus::message::object_path(certs::httpsObjectPath) / id; 5225968caeeSMarri Devender Rao name = "HTTPS certificate"; 52337cce918SMarri Devender Rao service = certs::httpsServiceName; 52437cce918SMarri Devender Rao } 52575b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 52675b63a2cSJiaqing Zhao "AccountService", "LDAP", 52775b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 52837cce918SMarri Devender Rao { 529002d39b4SEd Tanous objectPath = 53075b63a2cSJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 53137cce918SMarri Devender Rao name = "LDAP certificate"; 53237cce918SMarri Devender Rao service = certs::ldapServiceName; 5335968caeeSMarri Devender Rao } 53475b63a2cSJiaqing Zhao else if (crow::utility::readUrlSegments(*parsedUrl, "redfish", "v1", 53575b63a2cSJiaqing Zhao "Managers", "bmc", "Truststore", 53675b63a2cSJiaqing Zhao "Certificates", std::ref(id))) 537cfcd5f6bSMarri Devender Rao { 53875b63a2cSJiaqing Zhao objectPath = 539828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 540cfcd5f6bSMarri Devender Rao name = "TrustStore certificate"; 541cfcd5f6bSMarri Devender Rao service = certs::authorityServiceName; 542cfcd5f6bSMarri Devender Rao } 5435968caeeSMarri Devender Rao else 5445968caeeSMarri Devender Rao { 545828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "CertificateUri", 546828252d5SJiaqing Zhao "ReplaceCertificate"); 5475968caeeSMarri Devender Rao return; 5485968caeeSMarri Devender Rao } 5495968caeeSMarri Devender Rao 5505968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 5515968caeeSMarri Devender Rao std::make_shared<CertificateFile>(certificate); 5525968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 5531e312598SJiaqing Zhao [asyncResp, certFile, objectPath, service, url{*parsedUrl}, id, 5545968caeeSMarri Devender Rao name](const boost::system::error_code ec) { 5555968caeeSMarri Devender Rao if (ec) 5565968caeeSMarri Devender Rao { 5575968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 55890d2d1e8SJiaqing Zhao if (ec.value() == 55990d2d1e8SJiaqing Zhao boost::system::linux_error::bad_request_descriptor) 56090d2d1e8SJiaqing Zhao { 561828252d5SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Certificate", id); 5625968caeeSMarri Devender Rao return; 5635968caeeSMarri Devender Rao } 56490d2d1e8SJiaqing Zhao messages::internalError(asyncResp->res); 56590d2d1e8SJiaqing Zhao return; 56690d2d1e8SJiaqing Zhao } 567828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, service, id, url, name); 5685968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 5695968caeeSMarri Devender Rao << certFile->getCertFilePath(); 5705968caeeSMarri Devender Rao }, 5715968caeeSMarri Devender Rao service, objectPath, certs::certReplaceIntf, "Replace", 5725968caeeSMarri Devender Rao certFile->getCertFilePath()); 573828252d5SJiaqing Zhao } 5745968caeeSMarri Devender Rao 575828252d5SJiaqing Zhao static std::unique_ptr<sdbusplus::bus::match_t> csrMatcher; 5765968caeeSMarri Devender Rao /** 577828252d5SJiaqing Zhao * @brief Read data from CSR D-bus object and set to response 578828252d5SJiaqing Zhao * 579828252d5SJiaqing Zhao * @param[in] asyncResp Shared pointer to the response message 580828252d5SJiaqing Zhao * @param[in] certURI Link to certifiate collection URI 581828252d5SJiaqing Zhao * @param[in] service D-Bus service name 582828252d5SJiaqing Zhao * @param[in] certObjPath certificate D-Bus object path 583828252d5SJiaqing Zhao * @param[in] csrObjPath CSR D-Bus object path 584828252d5SJiaqing Zhao * @return None 5855968caeeSMarri Devender Rao */ 586828252d5SJiaqing Zhao static void getCSR(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 587828252d5SJiaqing Zhao const std::string& certURI, const std::string& service, 588828252d5SJiaqing Zhao const std::string& certObjPath, 589828252d5SJiaqing Zhao const std::string& csrObjPath) 5905968caeeSMarri Devender Rao { 591828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "getCSR CertObjectPath" << certObjPath 592828252d5SJiaqing Zhao << " CSRObjectPath=" << csrObjPath 593828252d5SJiaqing Zhao << " service=" << service; 594828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 595828252d5SJiaqing Zhao [asyncResp, certURI](const boost::system::error_code ec, 596828252d5SJiaqing Zhao const std::string& csr) { 597828252d5SJiaqing Zhao if (ec) 598828252d5SJiaqing Zhao { 599828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 600828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 601828252d5SJiaqing Zhao return; 602828252d5SJiaqing Zhao } 603828252d5SJiaqing Zhao if (csr.empty()) 604828252d5SJiaqing Zhao { 605828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "CSR read is empty"; 606828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 607828252d5SJiaqing Zhao return; 608828252d5SJiaqing Zhao } 609828252d5SJiaqing Zhao asyncResp->res.jsonValue["CSRString"] = csr; 610828252d5SJiaqing Zhao asyncResp->res.jsonValue["CertificateCollection"]["@odata.id"] = 611828252d5SJiaqing Zhao certURI; 612828252d5SJiaqing Zhao }, 613828252d5SJiaqing Zhao service, csrObjPath, "xyz.openbmc_project.Certs.CSR", "CSR"); 614828252d5SJiaqing Zhao } 615828252d5SJiaqing Zhao 616828252d5SJiaqing Zhao inline void 617828252d5SJiaqing Zhao handleGenerateCSRAction(App& app, const crow::Request& req, 618828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 619828252d5SJiaqing Zhao { 6203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 62145ca1b86SEd Tanous { 62245ca1b86SEd Tanous return; 62345ca1b86SEd Tanous } 624828252d5SJiaqing Zhao static const int rsaKeyBitLength = 2048; 6255968caeeSMarri Devender Rao 626828252d5SJiaqing Zhao // Required parameters 627828252d5SJiaqing Zhao std::string city; 628828252d5SJiaqing Zhao std::string commonName; 629828252d5SJiaqing Zhao std::string country; 630828252d5SJiaqing Zhao std::string organization; 631828252d5SJiaqing Zhao std::string organizationalUnit; 632828252d5SJiaqing Zhao std::string state; 633828252d5SJiaqing Zhao nlohmann::json certificateCollection; 634828252d5SJiaqing Zhao 635828252d5SJiaqing Zhao // Optional parameters 636828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optAlternativeNames = 637828252d5SJiaqing Zhao std::vector<std::string>(); 638828252d5SJiaqing Zhao std::optional<std::string> optContactPerson = ""; 639828252d5SJiaqing Zhao std::optional<std::string> optChallengePassword = ""; 640828252d5SJiaqing Zhao std::optional<std::string> optEmail = ""; 641828252d5SJiaqing Zhao std::optional<std::string> optGivenName = ""; 642828252d5SJiaqing Zhao std::optional<std::string> optInitials = ""; 643828252d5SJiaqing Zhao std::optional<int64_t> optKeyBitLength = rsaKeyBitLength; 644828252d5SJiaqing Zhao std::optional<std::string> optKeyCurveId = "secp384r1"; 645828252d5SJiaqing Zhao std::optional<std::string> optKeyPairAlgorithm = "EC"; 646828252d5SJiaqing Zhao std::optional<std::vector<std::string>> optKeyUsage = 647828252d5SJiaqing Zhao std::vector<std::string>(); 648828252d5SJiaqing Zhao std::optional<std::string> optSurname = ""; 649828252d5SJiaqing Zhao std::optional<std::string> optUnstructuredName = ""; 650828252d5SJiaqing Zhao if (!json_util::readJsonAction( 651828252d5SJiaqing Zhao req, asyncResp->res, "City", city, "CommonName", commonName, 652828252d5SJiaqing Zhao "ContactPerson", optContactPerson, "Country", country, 653828252d5SJiaqing Zhao "Organization", organization, "OrganizationalUnit", 654828252d5SJiaqing Zhao organizationalUnit, "State", state, "CertificateCollection", 655828252d5SJiaqing Zhao certificateCollection, "AlternativeNames", optAlternativeNames, 656828252d5SJiaqing Zhao "ChallengePassword", optChallengePassword, "Email", optEmail, 657828252d5SJiaqing Zhao "GivenName", optGivenName, "Initials", optInitials, "KeyBitLength", 658828252d5SJiaqing Zhao optKeyBitLength, "KeyCurveId", optKeyCurveId, "KeyPairAlgorithm", 659828252d5SJiaqing Zhao optKeyPairAlgorithm, "KeyUsage", optKeyUsage, "Surname", optSurname, 660828252d5SJiaqing Zhao "UnstructuredName", optUnstructuredName)) 661828252d5SJiaqing Zhao { 662828252d5SJiaqing Zhao return; 6635968caeeSMarri Devender Rao } 6645968caeeSMarri Devender Rao 665828252d5SJiaqing Zhao // bmcweb has no way to store or decode a private key challenge 666828252d5SJiaqing Zhao // password, which will likely cause bmcweb to crash on startup 667828252d5SJiaqing Zhao // if this is not set on a post so not allowing the user to set 668828252d5SJiaqing Zhao // value 669828252d5SJiaqing Zhao if (!optChallengePassword->empty()) 6705968caeeSMarri Devender Rao { 671828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "GenerateCSR", 672828252d5SJiaqing Zhao "ChallengePassword"); 673828252d5SJiaqing Zhao return; 674828252d5SJiaqing Zhao } 675828252d5SJiaqing Zhao 676828252d5SJiaqing Zhao std::string certURI; 677828252d5SJiaqing Zhao if (!redfish::json_util::readJson(certificateCollection, asyncResp->res, 678828252d5SJiaqing Zhao "@odata.id", certURI)) 679828252d5SJiaqing Zhao { 680828252d5SJiaqing Zhao return; 681828252d5SJiaqing Zhao } 682828252d5SJiaqing Zhao 683828252d5SJiaqing Zhao std::string objectPath; 684828252d5SJiaqing Zhao std::string service; 685828252d5SJiaqing Zhao if (certURI.starts_with( 686828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 687828252d5SJiaqing Zhao { 688828252d5SJiaqing Zhao objectPath = certs::httpsObjectPath; 689828252d5SJiaqing Zhao service = certs::httpsServiceName; 690828252d5SJiaqing Zhao } 691828252d5SJiaqing Zhao else if (certURI.starts_with( 692828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 693828252d5SJiaqing Zhao { 694828252d5SJiaqing Zhao objectPath = certs::ldapObjectPath; 695828252d5SJiaqing Zhao service = certs::ldapServiceName; 696828252d5SJiaqing Zhao } 697828252d5SJiaqing Zhao else 698828252d5SJiaqing Zhao { 699828252d5SJiaqing Zhao messages::actionParameterNotSupported( 700828252d5SJiaqing Zhao asyncResp->res, "CertificateCollection", "GenerateCSR"); 701828252d5SJiaqing Zhao return; 702828252d5SJiaqing Zhao } 703828252d5SJiaqing Zhao 704828252d5SJiaqing Zhao // supporting only EC and RSA algorithm 705828252d5SJiaqing Zhao if (*optKeyPairAlgorithm != "EC" && *optKeyPairAlgorithm != "RSA") 706828252d5SJiaqing Zhao { 707828252d5SJiaqing Zhao messages::actionParameterNotSupported( 708828252d5SJiaqing Zhao asyncResp->res, "KeyPairAlgorithm", "GenerateCSR"); 709828252d5SJiaqing Zhao return; 710828252d5SJiaqing Zhao } 711828252d5SJiaqing Zhao 712828252d5SJiaqing Zhao // supporting only 2048 key bit length for RSA algorithm due to 713828252d5SJiaqing Zhao // time consumed in generating private key 714828252d5SJiaqing Zhao if (*optKeyPairAlgorithm == "RSA" && *optKeyBitLength != rsaKeyBitLength) 715828252d5SJiaqing Zhao { 716828252d5SJiaqing Zhao messages::propertyValueNotInList( 717828252d5SJiaqing Zhao asyncResp->res, std::to_string(*optKeyBitLength), "KeyBitLength"); 718828252d5SJiaqing Zhao return; 719828252d5SJiaqing Zhao } 720828252d5SJiaqing Zhao 721828252d5SJiaqing Zhao // validate KeyUsage supporting only 1 type based on URL 722828252d5SJiaqing Zhao if (certURI.starts_with( 723828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates")) 724828252d5SJiaqing Zhao { 725828252d5SJiaqing Zhao if (optKeyUsage->empty()) 726828252d5SJiaqing Zhao { 727828252d5SJiaqing Zhao optKeyUsage->push_back("ServerAuthentication"); 728828252d5SJiaqing Zhao } 729828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 730828252d5SJiaqing Zhao { 731828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ServerAuthentication") 732828252d5SJiaqing Zhao { 733828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 734828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 735828252d5SJiaqing Zhao return; 736828252d5SJiaqing Zhao } 737828252d5SJiaqing Zhao } 738828252d5SJiaqing Zhao else 739828252d5SJiaqing Zhao { 740828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 741828252d5SJiaqing Zhao "GenerateCSR"); 742828252d5SJiaqing Zhao return; 743828252d5SJiaqing Zhao } 744828252d5SJiaqing Zhao } 745828252d5SJiaqing Zhao else if (certURI.starts_with( 746828252d5SJiaqing Zhao "/redfish/v1/AccountService/LDAP/Certificates")) 747828252d5SJiaqing Zhao { 748828252d5SJiaqing Zhao if (optKeyUsage->empty()) 749828252d5SJiaqing Zhao { 750828252d5SJiaqing Zhao optKeyUsage->push_back("ClientAuthentication"); 751828252d5SJiaqing Zhao } 752828252d5SJiaqing Zhao else if (optKeyUsage->size() == 1) 753828252d5SJiaqing Zhao { 754828252d5SJiaqing Zhao if ((*optKeyUsage)[0] != "ClientAuthentication") 755828252d5SJiaqing Zhao { 756828252d5SJiaqing Zhao messages::propertyValueNotInList(asyncResp->res, 757828252d5SJiaqing Zhao (*optKeyUsage)[0], "KeyUsage"); 758828252d5SJiaqing Zhao return; 759828252d5SJiaqing Zhao } 760828252d5SJiaqing Zhao } 761828252d5SJiaqing Zhao else 762828252d5SJiaqing Zhao { 763828252d5SJiaqing Zhao messages::actionParameterNotSupported(asyncResp->res, "KeyUsage", 764828252d5SJiaqing Zhao "GenerateCSR"); 765828252d5SJiaqing Zhao return; 766828252d5SJiaqing Zhao } 767828252d5SJiaqing Zhao } 768828252d5SJiaqing Zhao 769828252d5SJiaqing Zhao // Only allow one CSR matcher at a time so setting retry 770828252d5SJiaqing Zhao // time-out and timer expiry to 10 seconds for now. 771828252d5SJiaqing Zhao static const int timeOut = 10; 772828252d5SJiaqing Zhao if (csrMatcher) 773828252d5SJiaqing Zhao { 774828252d5SJiaqing Zhao messages::serviceTemporarilyUnavailable(asyncResp->res, 775828252d5SJiaqing Zhao std::to_string(timeOut)); 776828252d5SJiaqing Zhao return; 777828252d5SJiaqing Zhao } 778828252d5SJiaqing Zhao 779828252d5SJiaqing Zhao // Make this static so it survives outside this method 780828252d5SJiaqing Zhao static boost::asio::steady_timer timeout(*req.ioService); 781828252d5SJiaqing Zhao timeout.expires_after(std::chrono::seconds(timeOut)); 782828252d5SJiaqing Zhao timeout.async_wait([asyncResp](const boost::system::error_code& ec) { 783828252d5SJiaqing Zhao csrMatcher = nullptr; 784828252d5SJiaqing Zhao if (ec) 785828252d5SJiaqing Zhao { 786828252d5SJiaqing Zhao // operation_aborted is expected if timer is canceled 787828252d5SJiaqing Zhao // before completion. 788828252d5SJiaqing Zhao if (ec != boost::asio::error::operation_aborted) 789828252d5SJiaqing Zhao { 790828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Async_wait failed " << ec; 791828252d5SJiaqing Zhao } 792828252d5SJiaqing Zhao return; 793828252d5SJiaqing Zhao } 794828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Timed out waiting for Generating CSR"; 795828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 796828252d5SJiaqing Zhao }); 797828252d5SJiaqing Zhao 798828252d5SJiaqing Zhao // create a matcher to wait on CSR object 799828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "create matcher with path " << objectPath; 800828252d5SJiaqing Zhao std::string match("type='signal'," 801828252d5SJiaqing Zhao "interface='org.freedesktop.DBus.ObjectManager'," 802828252d5SJiaqing Zhao "path='" + 803828252d5SJiaqing Zhao objectPath + 804828252d5SJiaqing Zhao "'," 805828252d5SJiaqing Zhao "member='InterfacesAdded'"); 806828252d5SJiaqing Zhao csrMatcher = std::make_unique<sdbusplus::bus::match_t>( 807828252d5SJiaqing Zhao *crow::connections::systemBus, match, 808828252d5SJiaqing Zhao [asyncResp, service, objectPath, certURI](sdbusplus::message_t& m) { 809828252d5SJiaqing Zhao timeout.cancel(); 810828252d5SJiaqing Zhao if (m.is_method_error()) 811828252d5SJiaqing Zhao { 812828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "Dbus method error!!!"; 813828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 814828252d5SJiaqing Zhao return; 815828252d5SJiaqing Zhao } 816828252d5SJiaqing Zhao 817828252d5SJiaqing Zhao dbus::utility::DBusInteracesMap interfacesProperties; 818828252d5SJiaqing Zhao 819828252d5SJiaqing Zhao sdbusplus::message::object_path csrObjectPath; 820828252d5SJiaqing Zhao m.read(csrObjectPath, interfacesProperties); 821828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "CSR object added" << csrObjectPath.str; 822828252d5SJiaqing Zhao for (const auto& interface : interfacesProperties) 823828252d5SJiaqing Zhao { 824828252d5SJiaqing Zhao if (interface.first == "xyz.openbmc_project.Certs.CSR") 825828252d5SJiaqing Zhao { 826828252d5SJiaqing Zhao getCSR(asyncResp, certURI, service, objectPath, 827828252d5SJiaqing Zhao csrObjectPath.str); 828828252d5SJiaqing Zhao break; 829828252d5SJiaqing Zhao } 830828252d5SJiaqing Zhao } 831828252d5SJiaqing Zhao }); 832828252d5SJiaqing Zhao crow::connections::systemBus->async_method_call( 833828252d5SJiaqing Zhao [asyncResp](const boost::system::error_code ec, const std::string&) { 834828252d5SJiaqing Zhao if (ec) 835828252d5SJiaqing Zhao { 836828252d5SJiaqing Zhao BMCWEB_LOG_ERROR << "DBUS response error: " << ec.message(); 837828252d5SJiaqing Zhao messages::internalError(asyncResp->res); 838828252d5SJiaqing Zhao return; 839828252d5SJiaqing Zhao } 840828252d5SJiaqing Zhao }, 841828252d5SJiaqing Zhao service, objectPath, "xyz.openbmc_project.Certs.CSR.Create", 842828252d5SJiaqing Zhao "GenerateCSR", *optAlternativeNames, *optChallengePassword, city, 843828252d5SJiaqing Zhao commonName, *optContactPerson, country, *optEmail, *optGivenName, 844828252d5SJiaqing Zhao *optInitials, *optKeyBitLength, *optKeyCurveId, *optKeyPairAlgorithm, 845828252d5SJiaqing Zhao *optKeyUsage, organization, organizationalUnit, state, *optSurname, 846828252d5SJiaqing Zhao *optUnstructuredName); 847828252d5SJiaqing Zhao } 848828252d5SJiaqing Zhao 849828252d5SJiaqing Zhao inline void requestRoutesCertificateService(App& app) 850828252d5SJiaqing Zhao { 851828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/") 852828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateService) 853002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 854828252d5SJiaqing Zhao std::bind_front(handleCertificateServiceGet, std::ref(app))); 855828252d5SJiaqing Zhao 856828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/CertificateService/CertificateLocations/") 857828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateLocations) 858828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 859828252d5SJiaqing Zhao std::bind_front(handleCertificateLocationsGet, std::ref(app))); 860828252d5SJiaqing Zhao 861828252d5SJiaqing Zhao BMCWEB_ROUTE( 862828252d5SJiaqing Zhao app, 863828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate/") 864828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 865828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 866828252d5SJiaqing Zhao std::bind_front(handleReplaceCertificateAction, std::ref(app))); 867828252d5SJiaqing Zhao 868828252d5SJiaqing Zhao BMCWEB_ROUTE( 869828252d5SJiaqing Zhao app, 870828252d5SJiaqing Zhao "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/") 871828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateService) 872828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)( 873828252d5SJiaqing Zhao std::bind_front(handleGenerateCSRAction, std::ref(app))); 874828252d5SJiaqing Zhao } // requestRoutesCertificateService 875828252d5SJiaqing Zhao 876828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionGet( 877828252d5SJiaqing Zhao App& app, const crow::Request& req, 878828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 879828252d5SJiaqing Zhao { 8803ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 88145ca1b86SEd Tanous { 88245ca1b86SEd Tanous return; 88345ca1b86SEd Tanous } 8841476687dSEd Tanous 8851476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 8861476687dSEd Tanous "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"; 8871476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 8881476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 8891476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificates Collection"; 8901476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 8911476687dSEd Tanous "A Collection of HTTPS certificate instances"; 8928d1b46d7Szhanghch05 893d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::httpsObjectPath, 894d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 895d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 896828252d5SJiaqing Zhao } 8975968caeeSMarri Devender Rao 898828252d5SJiaqing Zhao inline void handleHTTPSCertificateCollectionPost( 899828252d5SJiaqing Zhao App& app, const crow::Request& req, 900828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 901828252d5SJiaqing Zhao { 9023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 90345ca1b86SEd Tanous { 90445ca1b86SEd Tanous return; 90545ca1b86SEd Tanous } 9065968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPSCertificateCollection::doPost"; 9078d1b46d7Szhanghch05 9081476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "HTTPS Certificate"; 9091476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "HTTPS Certificate"; 9105968caeeSMarri Devender Rao 911002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 91258eb238fSKowalski, Kamil 91358eb238fSKowalski, Kamil if (certFileBody.empty()) 91458eb238fSKowalski, Kamil { 9150fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 916a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 91758eb238fSKowalski, Kamil return; 91858eb238fSKowalski, Kamil } 91958eb238fSKowalski, Kamil 9205968caeeSMarri Devender Rao std::shared_ptr<CertificateFile> certFile = 92158eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 9225968caeeSMarri Devender Rao 9235968caeeSMarri Devender Rao crow::connections::systemBus->async_method_call( 924656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 925656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 9265968caeeSMarri Devender Rao if (ec) 9275968caeeSMarri Devender Rao { 9285968caeeSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 9295968caeeSMarri Devender Rao messages::internalError(asyncResp->res); 9305968caeeSMarri Devender Rao return; 9315968caeeSMarri Devender Rao } 932717b9802SJiaqing Zhao 933717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 934717b9802SJiaqing Zhao std::string certId = path.filename(); 9351e312598SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 9361e312598SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS", 9371e312598SJiaqing Zhao "Certificates", certId); 938828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, certs::httpsServiceName, 939828252d5SJiaqing Zhao certId, certURL, "HTTPS Certificate"); 9405968caeeSMarri Devender Rao BMCWEB_LOG_DEBUG << "HTTPS certificate install file=" 9415968caeeSMarri Devender Rao << certFile->getCertFilePath(); 9425968caeeSMarri Devender Rao }, 943828252d5SJiaqing Zhao certs::httpsServiceName, certs::httpsObjectPath, certs::certInstallIntf, 944828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 945828252d5SJiaqing Zhao } 9465968caeeSMarri Devender Rao 947828252d5SJiaqing Zhao inline void handleHTTPSCertificateGet( 948828252d5SJiaqing Zhao App& app, const crow::Request& req, 949828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 9507e860f15SJohn Edward Broadbent { 9513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 95245ca1b86SEd Tanous { 95345ca1b86SEd Tanous return; 95445ca1b86SEd Tanous } 9557e860f15SJohn Edward Broadbent 956828252d5SJiaqing Zhao BMCWEB_LOG_DEBUG << "HTTPS Certificate ID=" << id; 957828252d5SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 958828252d5SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "NetworkProtocol", "HTTPS", 959828252d5SJiaqing Zhao "Certificates", id); 960828252d5SJiaqing Zhao std::string objPath = 961828252d5SJiaqing Zhao sdbusplus::message::object_path(certs::httpsObjectPath) / id; 962828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::httpsServiceName, id, 963828252d5SJiaqing Zhao certURL, "HTTPS Certificate"); 9647e860f15SJohn Edward Broadbent } 96537cce918SMarri Devender Rao 966828252d5SJiaqing Zhao inline void requestRoutesHTTPSCertificate(App& app) 96737cce918SMarri Devender Rao { 968828252d5SJiaqing Zhao BMCWEB_ROUTE(app, 969828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 970ed398213SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 971828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 972828252d5SJiaqing Zhao handleHTTPSCertificateCollectionGet, std::ref(app))); 973828252d5SJiaqing Zhao 974828252d5SJiaqing Zhao BMCWEB_ROUTE(app, 975828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/") 976828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 977828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 978828252d5SJiaqing Zhao handleHTTPSCertificateCollectionPost, std::ref(app))); 979828252d5SJiaqing Zhao 980828252d5SJiaqing Zhao BMCWEB_ROUTE( 981828252d5SJiaqing Zhao app, 982828252d5SJiaqing Zhao "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/<str>/") 983828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 984002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 985828252d5SJiaqing Zhao std::bind_front(handleHTTPSCertificateGet, std::ref(app))); 986828252d5SJiaqing Zhao } 987828252d5SJiaqing Zhao 988828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionGet( 989828252d5SJiaqing Zhao App& app, const crow::Request& req, 990828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 991828252d5SJiaqing Zhao { 9923ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 99345ca1b86SEd Tanous { 99445ca1b86SEd Tanous return; 99545ca1b86SEd Tanous } 9961476687dSEd Tanous 9971476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 9981476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 9991476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 10001476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 10011476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "LDAP Certificates Collection"; 10021476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 10031476687dSEd Tanous "A Collection of LDAP certificate instances"; 10048d1b46d7Szhanghch05 1005d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::ldapObjectPath, 1006d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1007d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1008828252d5SJiaqing Zhao } 100937cce918SMarri Devender Rao 1010828252d5SJiaqing Zhao inline void handleLDAPCertificateCollectionPost( 1011828252d5SJiaqing Zhao App& app, const crow::Request& req, 1012828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1013828252d5SJiaqing Zhao { 10143ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 101545ca1b86SEd Tanous { 101645ca1b86SEd Tanous return; 101745ca1b86SEd Tanous } 1018002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 101958eb238fSKowalski, Kamil 102058eb238fSKowalski, Kamil if (certFileBody.empty()) 102158eb238fSKowalski, Kamil { 1022002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1023a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 102458eb238fSKowalski, Kamil return; 102558eb238fSKowalski, Kamil } 102658eb238fSKowalski, Kamil 102758eb238fSKowalski, Kamil std::shared_ptr<CertificateFile> certFile = 102858eb238fSKowalski, Kamil std::make_shared<CertificateFile>(certFileBody); 102958eb238fSKowalski, Kamil 103037cce918SMarri Devender Rao crow::connections::systemBus->async_method_call( 1031656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1032656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 103337cce918SMarri Devender Rao if (ec) 103437cce918SMarri Devender Rao { 103537cce918SMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 103637cce918SMarri Devender Rao messages::internalError(asyncResp->res); 103737cce918SMarri Devender Rao return; 103837cce918SMarri Devender Rao } 1039717b9802SJiaqing Zhao 1040717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1041717b9802SJiaqing Zhao std::string certId = path.filename(); 1042828252d5SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 1043828252d5SJiaqing Zhao "redfish", "v1", "AccountService", "LDAP", "Certificates", certId); 1044828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, certs::ldapServiceName, 1045828252d5SJiaqing Zhao certId, certURL, "LDAP Certificate"); 104637cce918SMarri Devender Rao BMCWEB_LOG_DEBUG << "LDAP certificate install file=" 104737cce918SMarri Devender Rao << certFile->getCertFilePath(); 104837cce918SMarri Devender Rao }, 1049828252d5SJiaqing Zhao certs::ldapServiceName, certs::ldapObjectPath, certs::certInstallIntf, 1050828252d5SJiaqing Zhao "Install", certFile->getCertFilePath()); 1051828252d5SJiaqing Zhao } 105237cce918SMarri Devender Rao 1053828252d5SJiaqing Zhao inline void handleLDAPCertificateGet( 1054828252d5SJiaqing Zhao App& app, const crow::Request& req, 1055828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 105637cce918SMarri Devender Rao { 10573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 105845ca1b86SEd Tanous { 105945ca1b86SEd Tanous return; 106045ca1b86SEd Tanous } 1061717b9802SJiaqing Zhao 1062717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "LDAP Certificate ID=" << id; 10631e312598SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 10641e312598SJiaqing Zhao "redfish", "v1", "AccountService", "LDAP", "Certificates", id); 1065717b9802SJiaqing Zhao std::string objPath = 1066717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::ldapObjectPath) / id; 1067717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::ldapServiceName, id, 1068717b9802SJiaqing Zhao certURL, "LDAP Certificate"); 1069828252d5SJiaqing Zhao } 1070828252d5SJiaqing Zhao 1071828252d5SJiaqing Zhao inline void requestRoutesLDAPCertificate(App& app) 1072cfcd5f6bSMarri Devender Rao { 1073828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1074828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificateCollection) 1075828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1076828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateCollectionGet, std::ref(app))); 1077828252d5SJiaqing Zhao 1078828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/") 1079828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1080828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1081828252d5SJiaqing Zhao handleLDAPCertificateCollectionPost, std::ref(app))); 1082828252d5SJiaqing Zhao 1083828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/AccountService/LDAP/Certificates/<str>/") 1084ed398213SEd Tanous .privileges(redfish::privileges::getCertificate) 1085002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1086828252d5SJiaqing Zhao std::bind_front(handleLDAPCertificateGet, std::ref(app))); 1087828252d5SJiaqing Zhao } // requestRoutesLDAPCertificate 1088828252d5SJiaqing Zhao 1089828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionGet( 1090828252d5SJiaqing Zhao App& app, const crow::Request& req, 1091828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1092828252d5SJiaqing Zhao { 10933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 109445ca1b86SEd Tanous { 109545ca1b86SEd Tanous return; 109645ca1b86SEd Tanous } 10971476687dSEd Tanous 10981476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 10991476687dSEd Tanous "/redfish/v1/Managers/bmc/Truststore/Certificates/"; 11001476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 11011476687dSEd Tanous "#CertificateCollection.CertificateCollection"; 1102002d39b4SEd Tanous asyncResp->res.jsonValue["Name"] = "TrustStore Certificates Collection"; 11031476687dSEd Tanous asyncResp->res.jsonValue["Description"] = 11041476687dSEd Tanous "A Collection of TrustStore certificate instances"; 11058d1b46d7Szhanghch05 1106d3f92ce7SJiaqing Zhao getCertificateList(asyncResp, certs::authorityObjectPath, 1107d3f92ce7SJiaqing Zhao "/Members"_json_pointer, 1108d3f92ce7SJiaqing Zhao "/Members@odata.count"_json_pointer); 1109828252d5SJiaqing Zhao } 1110cfcd5f6bSMarri Devender Rao 1111828252d5SJiaqing Zhao inline void handleTrustStoreCertificateCollectionPost( 1112828252d5SJiaqing Zhao App& app, const crow::Request& req, 1113828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1114828252d5SJiaqing Zhao { 11153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 111645ca1b86SEd Tanous { 111745ca1b86SEd Tanous return; 111845ca1b86SEd Tanous } 1119002d39b4SEd Tanous std::string certFileBody = getCertificateFromReqBody(asyncResp, req); 1120a08752f5SZbigniew Kurzynski 1121a08752f5SZbigniew Kurzynski if (certFileBody.empty()) 1122a08752f5SZbigniew Kurzynski { 11230fda0f12SGeorge Liu BMCWEB_LOG_ERROR << "Cannot get certificate from request body."; 1124a08752f5SZbigniew Kurzynski messages::unrecognizedRequestBody(asyncResp->res); 1125a08752f5SZbigniew Kurzynski return; 1126a08752f5SZbigniew Kurzynski } 1127a08752f5SZbigniew Kurzynski 1128a08752f5SZbigniew Kurzynski std::shared_ptr<CertificateFile> certFile = 1129a08752f5SZbigniew Kurzynski std::make_shared<CertificateFile>(certFileBody); 1130cfcd5f6bSMarri Devender Rao crow::connections::systemBus->async_method_call( 1131656ec7e3SZbigniew Kurzynski [asyncResp, certFile](const boost::system::error_code ec, 1132656ec7e3SZbigniew Kurzynski const std::string& objectPath) { 1133cfcd5f6bSMarri Devender Rao if (ec) 1134cfcd5f6bSMarri Devender Rao { 1135cfcd5f6bSMarri Devender Rao BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 1136cfcd5f6bSMarri Devender Rao messages::internalError(asyncResp->res); 1137cfcd5f6bSMarri Devender Rao return; 1138cfcd5f6bSMarri Devender Rao } 1139656ec7e3SZbigniew Kurzynski 1140717b9802SJiaqing Zhao sdbusplus::message::object_path path(objectPath); 1141717b9802SJiaqing Zhao std::string certId = path.filename(); 1142828252d5SJiaqing Zhao const boost::urls::url certURL = 1143828252d5SJiaqing Zhao crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc", 1144828252d5SJiaqing Zhao "Truststore", "Certificates", certId); 1145717b9802SJiaqing Zhao getCertificateProperties(asyncResp, objectPath, 1146828252d5SJiaqing Zhao certs::authorityServiceName, certId, certURL, 1147828252d5SJiaqing Zhao "TrustStore Certificate"); 11480fda0f12SGeorge Liu BMCWEB_LOG_DEBUG << "TrustStore certificate install file=" 1149cfcd5f6bSMarri Devender Rao << certFile->getCertFilePath(); 1150cfcd5f6bSMarri Devender Rao }, 1151cfcd5f6bSMarri Devender Rao certs::authorityServiceName, certs::authorityObjectPath, 11520fda0f12SGeorge Liu certs::certInstallIntf, "Install", certFile->getCertFilePath()); 1153828252d5SJiaqing Zhao } 1154cfcd5f6bSMarri Devender Rao 1155828252d5SJiaqing Zhao inline void handleTrustStoreCertificateGet( 1156828252d5SJiaqing Zhao App& app, const crow::Request& req, 1157828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1158cfcd5f6bSMarri Devender Rao { 11593ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 116045ca1b86SEd Tanous { 116145ca1b86SEd Tanous return; 116245ca1b86SEd Tanous } 1163717b9802SJiaqing Zhao 1164717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "Truststore Certificate ID=" << id; 1165828252d5SJiaqing Zhao const boost::urls::url certURL = crow::utility::urlFromPieces( 1166828252d5SJiaqing Zhao "redfish", "v1", "Managers", "bmc", "Truststore", "Certificates", id); 1167717b9802SJiaqing Zhao std::string objPath = 1168717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 1169828252d5SJiaqing Zhao getCertificateProperties(asyncResp, objPath, certs::authorityServiceName, 1170828252d5SJiaqing Zhao id, certURL, "TrustStore Certificate"); 1171828252d5SJiaqing Zhao } 117207a60299SZbigniew Kurzynski 1173828252d5SJiaqing Zhao inline void handleTrustStoreCertificateDelete( 1174828252d5SJiaqing Zhao App& app, const crow::Request& req, 1175828252d5SJiaqing Zhao const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1176828252d5SJiaqing Zhao { 11773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117845ca1b86SEd Tanous { 117945ca1b86SEd Tanous return; 118045ca1b86SEd Tanous } 118107a60299SZbigniew Kurzynski 1182717b9802SJiaqing Zhao BMCWEB_LOG_DEBUG << "Delete TrustStore Certificate ID=" << id; 1183717b9802SJiaqing Zhao std::string objPath = 1184717b9802SJiaqing Zhao sdbusplus::message::object_path(certs::authorityObjectPath) / id; 118507a60299SZbigniew Kurzynski 1186*7a3a8f7aSJiaqing Zhao deleteCertificate(asyncResp, certs::authorityServiceName, objPath); 1187828252d5SJiaqing Zhao } 1188828252d5SJiaqing Zhao 1189828252d5SJiaqing Zhao inline void requestRoutesTrustStoreCertificate(App& app) 1190828252d5SJiaqing Zhao { 1191828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1192828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1193828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)(std::bind_front( 1194828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionGet, std::ref(app))); 1195828252d5SJiaqing Zhao 1196828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/") 1197828252d5SJiaqing Zhao .privileges(redfish::privileges::postCertificateCollection) 1198828252d5SJiaqing Zhao .methods(boost::beast::http::verb::post)(std::bind_front( 1199828252d5SJiaqing Zhao handleTrustStoreCertificateCollectionPost, std::ref(app))); 1200828252d5SJiaqing Zhao 1201828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1202828252d5SJiaqing Zhao .privileges(redfish::privileges::getCertificate) 1203828252d5SJiaqing Zhao .methods(boost::beast::http::verb::get)( 1204828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateGet, std::ref(app))); 1205828252d5SJiaqing Zhao 1206828252d5SJiaqing Zhao BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/Truststore/Certificates/<str>/") 1207828252d5SJiaqing Zhao .privileges(redfish::privileges::deleteCertificate) 1208828252d5SJiaqing Zhao .methods(boost::beast::http::verb::delete_)( 1209828252d5SJiaqing Zhao std::bind_front(handleTrustStoreCertificateDelete, std::ref(app))); 12107e860f15SJohn Edward Broadbent } // requestRoutesTrustStoreCertificate 12115968caeeSMarri Devender Rao } // namespace redfish 1212