1 #pragma once
2 
3 #include "watch.hpp"
4 
5 #include <openssl/ossl_typ.h>
6 #include <openssl/x509.h>
7 
8 #include <functional>
9 #include <memory>
10 #include <sdbusplus/server/object.hpp>
11 #include <string>
12 #include <string_view>
13 #include <unordered_map>
14 #include <xyz/openbmc_project/Certs/Certificate/server.hpp>
15 #include <xyz/openbmc_project/Certs/Replace/server.hpp>
16 #include <xyz/openbmc_project/Object/Delete/server.hpp>
17 
18 namespace phosphor::certs
19 {
20 
21 // Certificate types
22 enum class CertificateType
23 {
24     authority,
25     server,
26     client,
27     unsupported,
28 };
29 
30 inline constexpr const char* certificateTypeToString(CertificateType type)
31 {
32     switch (type)
33     {
34         case CertificateType::authority:
35             return "authority";
36         case CertificateType::server:
37             return "server";
38         case CertificateType::client:
39             return "client";
40         default:
41             return "unsupported";
42     }
43 }
44 
45 inline constexpr CertificateType stringToCertificateType(std::string_view type)
46 {
47     if (type == "authority")
48     {
49         return CertificateType::authority;
50     }
51     if (type == "server")
52     {
53         return CertificateType::server;
54     }
55     if (type == "client")
56     {
57         return CertificateType::client;
58     }
59     return CertificateType::unsupported;
60 }
61 
62 namespace internal
63 {
64 using CertificateInterface = sdbusplus::server::object_t<
65     sdbusplus::xyz::openbmc_project::Certs::server::Certificate,
66     sdbusplus::xyz::openbmc_project::Certs::server::Replace,
67     sdbusplus::xyz::openbmc_project::Object::server::Delete>;
68 using InstallFunc = std::function<void(const std::string&)>;
69 using AppendPrivKeyFunc = std::function<void(const std::string&)>;
70 using X509Ptr = std::unique_ptr<X509, decltype(&::X509_free)>;
71 } // namespace internal
72 
73 class Manager; // Forward declaration for Certificate Manager.
74 
75 /** @class Certificate
76  *  @brief OpenBMC Certificate entry implementation.
77  *  @details A concrete implementation for the
78  *  xyz.openbmc_project.Certs.Certificate DBus API
79  *  xyz.openbmc_project.Certs.Install DBus API
80  */
81 class Certificate : public internal::CertificateInterface
82 {
83   public:
84     Certificate() = delete;
85     Certificate(const Certificate&) = delete;
86     Certificate& operator=(const Certificate&) = delete;
87     Certificate(Certificate&&) = delete;
88     Certificate& operator=(Certificate&&) = delete;
89     virtual ~Certificate();
90 
91     /** @brief Constructor for the Certificate Object
92      *  @param[in] bus - Bus to attach to.
93      *  @param[in] objPath - Object path to attach to
94      *  @param[in] type - Type of the certificate
95      *  @param[in] installPath - Path of the certificate to install
96      *  @param[in] uploadPath - Path of the certificate file to upload
97      *  @param[in] watchPtr - watch on self signed certificate
98      *  @param[in] parent - the manager that owns the certificate
99      *  @param[in] restore - the certificate is created in the restore path
100      */
101     Certificate(sdbusplus::bus_t& bus, const std::string& objPath,
102                 CertificateType type, const std::string& installPath,
103                 const std::string& uploadPath, Watch* watch, Manager& parent,
104                 bool restore);
105 
106     /** @brief Constructor for the Certificate Object; a variant for authorities
107      * list install
108      *  @param[in] bus - Bus to attach to.
109      *  @param[in] objPath - Object path to attach to
110      *  @param[in] type - Type of the certificate
111      *  @param[in] installPath - Path of the certificate to install
112      *  @param[in] x509Store - an initialized X509 store used for certificate
113      * validation; Certificate object doesn't own it
114      *  @param[in] pem - Content of the certificate file to upload; it shall be
115      * a single PEM encoded x509 certificate
116      *  @param[in] watchPtr - watch on self signed certificate
117      *  @param[in] parent - Pointer to the manager which owns the constructed
118      * Certificate object
119      *  @param[in] restore - the certificate is created in the restore path
120      */
121     Certificate(sdbusplus::bus_t& bus, const std::string& objPath,
122                 const CertificateType& type, const std::string& installPath,
123                 X509_STORE& x509Store, const std::string& pem, Watch* watchPtr,
124                 Manager& parent, bool restore);
125 
126     /** @brief Validate and Replace/Install the certificate file
127      *  Install/Replace the existing certificate file with another
128      *  (possibly CA signed) Certificate file.
129      *  @param[in] filePath - Certificate file path.
130      *  @param[in] restore - the certificate is created in the restore path
131      */
132     void install(const std::string& filePath, bool restore);
133 
134     /** @brief Validate and Replace/Install the certificate file
135      *  Install/Replace the existing certificate file with another
136      *  (possibly CA signed) Certificate file.
137      *  @param[in] x509Store - an initialized X509 store used for certificate
138      * validation; Certificate object doesn't own it
139      *  @param[in] pem - a string buffer which stores a PEM encoded certificate.
140      *  @param[in] restore - the certificate is created in the restore path
141      */
142     void install(X509_STORE& x509Store, const std::string& pem, bool restore);
143 
144     /** @brief Validate certificate and replace the existing certificate
145      *  @param[in] filePath - Certificate file path.
146      */
147     void replace(const std::string filePath) override;
148 
149     /** @brief Populate certificate properties by parsing certificate file
150      */
151     void populateProperties();
152 
153     /**
154      * @brief Obtain certificate ID.
155      *
156      * @return Certificate ID.
157      */
158     std::string getCertId() const;
159 
160     /**
161      * @brief Check if provided certificate is the same as the current one.
162      *
163      * @param[in] certPath - File path for certificate to check.
164      *
165      * @return Checking result. Return true if certificates are the same,
166      *         false if not.
167      */
168     bool isSame(const std::string& certPath);
169 
170     /**
171      * @brief Update certificate storage.
172      */
173     void storageUpdate();
174 
175     /**
176      * @brief Delete the certificate
177      */
178     void delete_() override;
179 
180     /**
181      * @brief Generate file name which is unique in the provided directory.
182      *
183      * @param[in] directoryPath - Directory path.
184      *
185      * @return File path.
186      */
187     static std::string generateUniqueFilePath(const std::string& directoryPath);
188 
189     /**
190      * @brief Copies the certificate from sourceFilePath to installFilePath
191      *
192      * @param[in] sourceFilePath - Path to the source file.
193      * @param[in] certFilePath - Path to the destination file.
194      *
195      * @return void
196      */
197     static void copyCertificate(const std::string& certSrcFilePath,
198                                 const std::string& certFilePath);
199 
200     /**
201      * @brief Returns the associated dbus object path.
202      */
203     std::string getObjectPath();
204 
205     /**
206      * @brief Returns the associated cert file path.
207      */
208     std::string getCertFilePath();
209 
210     /** @brief: Set the data member |certFilePath| to |path|
211      */
212     void setCertFilePath(const std::string& path);
213 
214     /** @brief: Set the data member |certInstallPath| to |path|
215      */
216     void setCertInstallPath(const std::string& path);
217 
218   private:
219     /**
220      * @brief Populate certificate properties by parsing given certificate
221      * object
222      *
223      * @param[in] cert The given certificate object
224      *
225      * @return void
226      */
227     void populateProperties(X509& cert);
228 
229     /** @brief Check and append private key to the certificate file
230      *         If private key is not present in the certificate file append the
231      *         certificate file with private key existing in the system.
232      *  @param[in] filePath - Certificate and key full file path.
233      *  @return void.
234      */
235     void checkAndAppendPrivateKey(const std::string& filePath);
236 
237     /** @brief Public/Private key compare function.
238      *         Comparing private key against certificate public key
239      *         from input .pem file.
240      *  @param[in] filePath - Certificate and key full file path.
241      *  @return Return true if Key compare is successful,
242      *          false if not
243      */
244     bool compareKeys(const std::string& filePath);
245 
246     /**
247      * @brief Generate authority certificate file path corresponding with
248      * OpenSSL requirements.
249      *
250      * Prepare authority certificate file path for provided certificate.
251      * OpenSSL puts some restrictions on the certificate file name pattern.
252      * Certificate full file name needs to consists of basic file name which
253      * is certificate subject name hash and file name extension which is an
254      * integer. More over, certificates files names extensions must be
255      * consecutive integer numbers in case many certificates with the same
256      * subject name.
257      * https://www.boost.org/doc/libs/1_69_0/doc/html/boost_asio/reference/ssl__context/add_verify_path.html
258      * https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_load_verify_locations.html
259      *
260      * @param[in] certSrcFilePath - Certificate source file path.
261      * @param[in] certDstDirPath - Certificate destination directory path.
262      *
263      * @return Authority certificate file path.
264      */
265     std::string generateAuthCertFileX509Path(const std::string& certSrcFilePath,
266                                              const std::string& certDstDirPath);
267 
268     /**
269      * @brief Generate authority certificate file path based on provided
270      * certificate source file path.
271      *
272      * @param[in] certSrcFilePath - Certificate source file path.
273      *
274      * @return Authority certificate file path.
275      */
276     std::string generateAuthCertFilePath(const std::string& certSrcFilePath);
277 
278     /**
279      * @brief Generate certificate file path based on provided certificate
280      * source file path.
281      *
282      * @param[in] certSrcFilePath - Certificate source file path.
283      *
284      * @return Certificate file path.
285      */
286     std::string generateCertFilePath(const std::string& certSrcFilePath);
287 
288     /** @brief Type specific function pointer map */
289     std::unordered_map<CertificateType, internal::InstallFunc> typeFuncMap;
290 
291     /** @brief object path */
292     std::string objectPath;
293 
294     /** @brief Type of the certificate */
295     CertificateType certType;
296 
297     /** @brief Stores certificate ID */
298     std::string certId;
299 
300     /** @brief Stores certificate file path */
301     std::string certFilePath;
302 
303     /** @brief Certificate file installation path */
304     std::string certInstallPath;
305 
306     /** @brief Type specific function pointer map for appending private key */
307     std::unordered_map<CertificateType, internal::AppendPrivKeyFunc>
308         appendKeyMap;
309 
310     /** @brief Certificate file create/update watch
311      * Note that Certificate object doesn't own the pointer
312      */
313     Watch* certWatch;
314 
315     /** @brief Reference to Certificate Manager */
316     Manager& manager;
317 };
318 
319 } // namespace phosphor::certs
320