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