1 #pragma once
2 
3 #include "watch.hpp"
4 
5 #include <openssl/x509.h>
6 
7 #include <filesystem>
8 #include <phosphor-logging/elog.hpp>
9 #include <xyz/openbmc_project/Certs/Certificate/server.hpp>
10 #include <xyz/openbmc_project/Certs/Replace/server.hpp>
11 #include <xyz/openbmc_project/Object/Delete/server.hpp>
12 
13 namespace phosphor
14 {
15 namespace certs
16 {
17 using DeleteIface = sdbusplus::xyz::openbmc_project::Object::server::Delete;
18 using CertificateIface =
19     sdbusplus::xyz::openbmc_project::Certs::server::Certificate;
20 using ReplaceIface = sdbusplus::xyz::openbmc_project::Certs::server::Replace;
21 using CertIfaces = sdbusplus::server::object::object<CertificateIface,
22                                                      ReplaceIface, DeleteIface>;
23 
24 using CertificateType = std::string;
25 using CertInstallPath = std::string;
26 using CertUploadPath = std::string;
27 using InputType = std::string;
28 using InstallFunc = std::function<void(const std::string&)>;
29 using AppendPrivKeyFunc = std::function<void(const std::string&)>;
30 using CertWatchPtr = std::unique_ptr<Watch>;
31 using namespace phosphor::logging;
32 
33 // for placeholders
34 using namespace std::placeholders;
35 namespace fs = std::filesystem;
36 
37 class Manager; // Forward declaration for Certificate Manager.
38 
39 // Supported Types.
40 static constexpr auto SERVER = "server";
41 static constexpr auto CLIENT = "client";
42 static constexpr auto AUTHORITY = "authority";
43 
44 // RAII support for openSSL functions.
45 using X509_Ptr = std::unique_ptr<X509, decltype(&::X509_free)>;
46 using X509_STORE_CTX_Ptr =
47     std::unique_ptr<X509_STORE_CTX, decltype(&::X509_STORE_CTX_free)>;
48 
49 /** @class Certificate
50  *  @brief OpenBMC Certificate entry implementation.
51  *  @details A concrete implementation for the
52  *  xyz.openbmc_project.Certs.Certificate DBus API
53  *  xyz.openbmc_project.Certs.Instal DBus API
54  */
55 class Certificate : public CertIfaces
56 {
57   public:
58     Certificate() = delete;
59     Certificate(const Certificate&) = delete;
60     Certificate& operator=(const Certificate&) = delete;
61     Certificate(Certificate&&) = delete;
62     Certificate& operator=(Certificate&&) = delete;
63     virtual ~Certificate();
64 
65     /** @brief Constructor for the Certificate Object
66      *  @param[in] bus - Bus to attach to.
67      *  @param[in] objPath - Object path to attach to
68      *  @param[in] type - Type of the certificate
69      *  @param[in] installPath - Path of the certificate to install
70      *  @param[in] uploadPath - Path of the certificate file to upload
71      *  @param[in] watchPtr - watch on self signed certificate pointer
72      */
73     Certificate(sdbusplus::bus::bus& bus, const std::string& objPath,
74                 const CertificateType& type, const CertInstallPath& installPath,
75                 const CertUploadPath& uploadPath, const CertWatchPtr& watchPtr,
76                 Manager& parent);
77 
78     /** @brief Validate and Replace/Install the certificate file
79      *  Install/Replace the existing certificate file with another
80      *  (possibly CA signed) Certificate file.
81      *  @param[in] filePath - Certificate file path.
82      */
83     void install(const std::string& filePath);
84 
85     /** @brief Validate certificate and replace the existing certificate
86      *  @param[in] filePath - Certificate file path.
87      */
88     void replace(const std::string filePath) override;
89 
90     /** @brief Populate certificate properties by parsing certificate file
91      */
92     void populateProperties();
93 
94     /**
95      * @brief Obtain certificate ID.
96      *
97      * @return Certificate ID.
98      */
99     std::string getCertId() const;
100 
101     /**
102      * @brief Check if provied certificate is the same as the current one.
103      *
104      * @param[in] certPath - File path for certificate to check.
105      *
106      * @return Checking result. Return true if certificates are the same,
107      *         false if not.
108      */
109     bool isSame(const std::string& certPath);
110 
111     /**
112      * @brief Update certificate storage.
113      */
114     void storageUpdate();
115 
116     /**
117      * @brief Delete the certificate
118      */
119     void delete_() override;
120 
121   private:
122     /**
123      * @brief Return error if ceritificate expiry date is gt 2038
124      *
125      * Parse the certificate and return error if certificate expiry date
126      * is gt 2038.
127      *
128      * @param[in] cert  Reference to certificate object uploaded
129      *
130      * @return void
131      */
132     void validateCertificateExpiryDate(const X509_Ptr& cert);
133 
134     /**
135      * @brief Populate certificate properties by parsing given certificate file
136      *
137      * @param[in] certPath   Path to certificate that should be parsed
138      *
139      * @return void
140      */
141     void populateProperties(const std::string& certPath);
142 
143     /** @brief Load Certificate file into the X509 structure.
144      *  @param[in] filePath - Certificate and key full file path.
145      *  @return pointer to the X509 structure.
146      */
147     X509_Ptr loadCert(const std::string& filePath);
148 
149     /** @brief Check and append private key to the certificate file
150      *         If private key is not present in the certificate file append the
151      *         certificate file with private key existing in the system.
152      *  @param[in] filePath - Certificate and key full file path.
153      *  @return void.
154      */
155     void checkAndAppendPrivateKey(const std::string& filePath);
156 
157     /** @brief Public/Private key compare function.
158      *         Comparing private key against certificate public key
159      *         from input .pem file.
160      *  @param[in] filePath - Certificate and key full file path.
161      *  @return Return true if Key compare is successful,
162      *          false if not
163      */
164     bool compareKeys(const std::string& filePath);
165 
166     /**
167      * @brief Generate certificate ID based on provided certificate file.
168      *
169      * @param[in] certPath - Certificate file path.
170      *
171      * @return Certificate ID as formatted string.
172      */
173     std::string generateCertId(const std::string& certPath);
174 
175     /**
176      * @brief Generate file name which is unique in the provided directory.
177      *
178      * @param[in] directoryPath - Directory path.
179      *
180      * @return File path.
181      */
182     std::string generateUniqueFilePath(const std::string& directoryPath);
183 
184     /**
185      * @brief Generate authority certificate file path corresponding with
186      * OpenSSL requirements.
187      *
188      * Prepare authority certificate file path for provied certificate.
189      * OpenSSL puts some restrictions on the certificate file name pattern.
190      * Certificate full file name needs to consists of basic file name which
191      * is certificate subject name hash and file name extension which is an
192      * integer. More over, certificates files names extensions must be
193      * consecutive integer numbers in case many certificates with the same
194      * subject name.
195      * https://www.boost.org/doc/libs/1_69_0/doc/html/boost_asio/reference/ssl__context/add_verify_path.html
196      * https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_load_verify_locations.html
197      *
198      * @param[in] certSrcFilePath - Certificate source file path.
199      * @param[in] certDstDirPath - Certificate destination directory path.
200      *
201      * @return Authority certificate file path.
202      */
203     std::string generateAuthCertFileX509Path(const std::string& certSrcFilePath,
204                                              const std::string& certDstDirPath);
205 
206     /**
207      * @brief Generate authority certificate file path based on provided
208      * certificate source file path.
209      *
210      * @param[in] certSrcFilePath - Certificate source file path.
211      *
212      * @return Authority certificate file path.
213      */
214     std::string generateAuthCertFilePath(const std::string& certSrcFilePath);
215 
216     /**
217      * @brief Generate certificate file path based on provided certificate
218      * source file path.
219      *
220      * @param[in] certSrcFilePath - Certificate source file path.
221      *
222      * @return Certificate file path.
223      */
224     std::string generateCertFilePath(const std::string& certSrcFilePath);
225 
226     /** @brief Type specific function pointer map */
227     std::unordered_map<InputType, InstallFunc> typeFuncMap;
228 
229     /** @brief sdbusplus handler */
230     sdbusplus::bus::bus& bus;
231 
232     /** @brief object path */
233     std::string objectPath;
234 
235     /** @brief Type of the certificate */
236     CertificateType certType;
237 
238     /** @brief Stores certificate ID */
239     std::string certId;
240 
241     /** @brief Stores certificate file path */
242     std::string certFilePath;
243 
244     /** @brief Certificate file installation path */
245     CertInstallPath certInstallPath;
246 
247     /** @brief Type specific function pointer map for appending private key */
248     std::unordered_map<InputType, AppendPrivKeyFunc> appendKeyMap;
249 
250     /** @brief Certificate file create/update watch */
251     const CertWatchPtr& certWatchPtr;
252 
253     /** @brief Reference to Certificate Manager */
254     Manager& manager;
255 };
256 
257 } // namespace certs
258 } // namespace phosphor
259