#pragma once #include "watch.hpp" #include <openssl/ossl_typ.h> #include <openssl/x509.h> #include <sdbusplus/server/object.hpp> #include <xyz/openbmc_project/Certs/Certificate/server.hpp> #include <xyz/openbmc_project/Certs/Replace/server.hpp> #include <xyz/openbmc_project/Object/Delete/server.hpp> #include <functional> #include <memory> #include <string> #include <string_view> #include <unordered_map> namespace phosphor::certs { // Certificate types enum class CertificateType { authority, server, client, unsupported, }; inline constexpr const char* certificateTypeToString(CertificateType type) { switch (type) { case CertificateType::authority: return "authority"; case CertificateType::server: return "server"; case CertificateType::client: return "client"; default: return "unsupported"; } } inline constexpr CertificateType stringToCertificateType(std::string_view type) { if (type == "authority") { return CertificateType::authority; } if (type == "server") { return CertificateType::server; } if (type == "client") { return CertificateType::client; } return CertificateType::unsupported; } namespace internal { using CertificateInterface = sdbusplus::server::object_t< sdbusplus::xyz::openbmc_project::Certs::server::Certificate, sdbusplus::xyz::openbmc_project::Certs::server::Replace, sdbusplus::xyz::openbmc_project::Object::server::Delete>; using InstallFunc = std::function<void(const std::string&)>; using AppendPrivKeyFunc = std::function<void(const std::string&)>; using X509Ptr = std::unique_ptr<X509, decltype(&::X509_free)>; } // namespace internal class Manager; // Forward declaration for Certificate Manager. /** @class Certificate * @brief OpenBMC Certificate entry implementation. * @details A concrete implementation for the * xyz.openbmc_project.Certs.Certificate DBus API * xyz.openbmc_project.Certs.Install DBus API */ class Certificate : public internal::CertificateInterface { public: Certificate() = delete; Certificate(const Certificate&) = delete; Certificate& operator=(const Certificate&) = delete; Certificate(Certificate&&) = delete; Certificate& operator=(Certificate&&) = delete; virtual ~Certificate(); /** @brief Constructor for the Certificate Object * @param[in] bus - Bus to attach to. * @param[in] objPath - Object path to attach to * @param[in] type - Type of the certificate * @param[in] installPath - Path of the certificate to install * @param[in] uploadPath - Path of the certificate file to upload * @param[in] watchPtr - watch on self signed certificate * @param[in] parent - the manager that owns the certificate * @param[in] restore - the certificate is created in the restore path */ Certificate(sdbusplus::bus_t& bus, const std::string& objPath, CertificateType type, const std::string& installPath, const std::string& uploadPath, Watch* watch, Manager& parent, bool restore); /** @brief Constructor for the Certificate Object; a variant for authorities * list install * @param[in] bus - Bus to attach to. * @param[in] objPath - Object path to attach to * @param[in] type - Type of the certificate * @param[in] installPath - Path of the certificate to install * @param[in] x509Store - an initialized X509 store used for certificate * validation; Certificate object doesn't own it * @param[in] pem - Content of the certificate file to upload; it shall be * a single PEM encoded x509 certificate * @param[in] watchPtr - watch on self signed certificate * @param[in] parent - Pointer to the manager which owns the constructed * Certificate object * @param[in] restore - the certificate is created in the restore path */ Certificate(sdbusplus::bus_t& bus, const std::string& objPath, const CertificateType& type, const std::string& installPath, X509_STORE& x509Store, const std::string& pem, Watch* watchPtr, Manager& parent, bool restore); /** @brief Validate and Replace/Install the certificate file * Install/Replace the existing certificate file with another * (possibly CA signed) Certificate file. * @param[in] filePath - Certificate file path. * @param[in] restore - the certificate is created in the restore path */ void install(const std::string& filePath, bool restore); /** @brief Validate and Replace/Install the certificate file * Install/Replace the existing certificate file with another * (possibly CA signed) Certificate file. * @param[in] x509Store - an initialized X509 store used for certificate * validation; Certificate object doesn't own it * @param[in] pem - a string buffer which stores a PEM encoded certificate. * @param[in] restore - the certificate is created in the restore path */ void install(X509_STORE& x509Store, const std::string& pem, bool restore); /** @brief Validate certificate and replace the existing certificate * @param[in] filePath - Certificate file path. */ void replace(const std::string filePath) override; /** @brief Populate certificate properties by parsing certificate file */ void populateProperties(); /** * @brief Obtain certificate ID. * * @return Certificate ID. */ std::string getCertId() const; /** * @brief Check if provided certificate is the same as the current one. * * @param[in] certPath - File path for certificate to check. * * @return Checking result. Return true if certificates are the same, * false if not. */ bool isSame(const std::string& certPath); /** * @brief Update certificate storage. */ void storageUpdate(); /** * @brief Delete the certificate */ void delete_() override; /** * @brief Generate file name which is unique in the provided directory. * * @param[in] directoryPath - Directory path. * * @return File path. */ static std::string generateUniqueFilePath(const std::string& directoryPath); /** * @brief Copies the certificate from sourceFilePath to installFilePath * * @param[in] sourceFilePath - Path to the source file. * @param[in] certFilePath - Path to the destination file. * * @return void */ static void copyCertificate(const std::string& certSrcFilePath, const std::string& certFilePath); /** * @brief Returns the associated dbus object path. */ std::string getObjectPath(); /** * @brief Returns the associated cert file path. */ std::string getCertFilePath(); /** @brief: Set the data member |certFilePath| to |path| */ void setCertFilePath(const std::string& path); /** @brief: Set the data member |certInstallPath| to |path| */ void setCertInstallPath(const std::string& path); private: /** * @brief Populate certificate properties by parsing given certificate * object * * @param[in] cert The given certificate object * * @return void */ void populateProperties(X509& cert); /** @brief Check and append private key to the certificate file * If private key is not present in the certificate file append the * certificate file with private key existing in the system. * @param[in] filePath - Certificate and key full file path. * @return void. */ void checkAndAppendPrivateKey(const std::string& filePath); /** @brief Public/Private key compare function. * Comparing private key against certificate public key * from input .pem file. * @param[in] filePath - Certificate and key full file path. * @return Return true if Key compare is successful, * false if not */ bool compareKeys(const std::string& filePath); /** * @brief Generate authority certificate file path corresponding with * OpenSSL requirements. * * Prepare authority certificate file path for provided certificate. * OpenSSL puts some restrictions on the certificate file name pattern. * Certificate full file name needs to consists of basic file name which * is certificate subject name hash and file name extension which is an * integer. More over, certificates files names extensions must be * consecutive integer numbers in case many certificates with the same * subject name. * https://www.boost.org/doc/libs/1_69_0/doc/html/boost_asio/reference/ssl__context/add_verify_path.html * https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_load_verify_locations.html * * @param[in] certSrcFilePath - Certificate source file path. * @param[in] certDstDirPath - Certificate destination directory path. * * @return Authority certificate file path. */ std::string generateAuthCertFileX509Path(const std::string& certSrcFilePath, const std::string& certDstDirPath); /** * @brief Generate authority certificate file path based on provided * certificate source file path. * * @param[in] certSrcFilePath - Certificate source file path. * * @return Authority certificate file path. */ std::string generateAuthCertFilePath(const std::string& certSrcFilePath); /** * @brief Generate certificate file path based on provided certificate * source file path. * * @param[in] certSrcFilePath - Certificate source file path. * * @return Certificate file path. */ std::string generateCertFilePath(const std::string& certSrcFilePath); /** @brief Type specific function pointer map */ std::unordered_map<CertificateType, internal::InstallFunc> typeFuncMap; /** @brief object path */ std::string objectPath; /** @brief Type of the certificate */ CertificateType certType; /** @brief Stores certificate ID */ std::string certId; /** @brief Stores certificate file path */ std::string certFilePath; /** @brief Certificate file installation path */ std::string certInstallPath; /** @brief Type specific function pointer map for appending private key */ std::unordered_map<CertificateType, internal::AppendPrivKeyFunc> appendKeyMap; /** @brief Certificate file create/update watch * Note that Certificate object doesn't own the pointer */ Watch* certWatch; /** @brief Reference to Certificate Manager */ Manager& manager; }; } // namespace phosphor::certs