1 #pragma once
2 
3 #include <libcryptsetup.h>
4 
5 #include <phosphor-logging/lg2.hpp>
6 #include <stdplus/handle/managed.hpp>
7 #include <xyz/openbmc_project/Common/error.hpp>
8 
9 #include <string>
10 #include <string_view>
11 
12 namespace estoraged
13 {
14 
15 using sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound;
16 
17 /** @class CryptsetupInterface
18  *  @brief Interface to the cryptsetup functions used to manage a LUKS device.
19  *  @details This class is used to mock out the cryptsetup functions.
20  */
21 class CryptsetupInterface
22 {
23   public:
24     virtual ~CryptsetupInterface() = default;
25     CryptsetupInterface() = default;
26     CryptsetupInterface(const CryptsetupInterface&) = delete;
27     CryptsetupInterface& operator=(const CryptsetupInterface&) = delete;
28 
29     CryptsetupInterface(CryptsetupInterface&&) = delete;
30     CryptsetupInterface& operator=(CryptsetupInterface&&) = delete;
31 
32     /** @brief Wrapper around crypt_format.
33      *  @details Used for mocking purposes.
34      *
35      *  @param[in] cd - crypt device handle.
36      *  @param[in] type - type of device (optional params struct must be of
37      *    this type).
38      *  @param[in] cipher - (e.g. "aes").
39      *  @params[in cipher_mode - including IV specification (e.g. "xts-plain").
40      *  @params[in] uuid - requested UUID or NULL if it should be generated.
41      *  @params[in] volume_key - pre-generated volume key or NULL if it should
42      *    be generated (only for LUKS).
43      *  @params[in] volume_key_size - size of volume key in bytes.
44      *  @params[in] params - crypt type specific parameters.
45      *
46      *  @returns 0 on success or negative errno value otherwise.
47      */
48     virtual int cryptFormat(struct crypt_device* cd, const char* type,
49                             const char* cipher, const char* cipherMode,
50                             const char* uuid, const char* volumeKey,
51                             size_t volumeKeySize, void* params) = 0;
52 
53     /** @brief Wrapper around crypt_keyslot_change_by_passphrase.
54      *  @details Used for mocking purposes.
55      *
56      *  @param[in] cd - crypt device handle.
57      *  @param[in] keyslotOld - old keyslot or CRYPT_ANY_SLOT.
58      *  @param[in] keyslotNew - new keyslot or CRYPT_ANY_SLOT.
59      *  @param[in] passphrase - passphrase for new keyslot.
60      *  @param[in] passphraseSize - size of passphrase.
61      *  @param[in] newPassphrase - new passphrase for the specified keyslot
62      *  @param[in] newPassphraseSize - size of newPassphrase (in bytes).
63      *
64      *  @returns allocated key slot number or negative errno otherwise.
65      */
66     virtual int cryptKeyslotChangeByPassphrase(struct crypt_device* cd,
67                                                int keyslotOld, int keyslotNew,
68                                                const char* passphrase,
69                                                size_t passphraseSize,
70                                                const char* newPassphrase,
71                                                size_t newPassphraseSize) = 0;
72 
73     /** @brief Wrapper around crypt_keyslot_add_by_volume_key.
74      *  @details Used for mocking purposes.
75      *
76      *  @param[in] cd - crypt device handle.
77      *  @param[in] keyslot - requested keyslot or CRYPT_ANY_SLOT.
78      *  @param[in] volume_key - provided volume key or NULL if used after
79      *    crypt_format.
80      *  @param[in] volume_key_size - size of volume_key.
81      *  @param[in] passphrase - passphrase for new keyslot.
82      *  @param[in] passphrase_size - size of passphrase.
83      *
84      *  @returns allocated key slot number or negative errno otherwise.
85      */
86     virtual int cryptKeyslotAddByVolumeKey(struct crypt_device* cd, int keyslot,
87                                            const char* volumeKey,
88                                            size_t volumeKeySize,
89                                            const char* passphrase,
90                                            size_t passphraseSize) = 0;
91 
92     /** @brief Wrapper around crypt_load.
93      *  @details Used for mocking purposes.
94      *
95      *  @param[in] cd - crypt device handle.
96      *  @param[in] requested_type - crypt-type or NULL for all known.
97      *  @param[in] params - crypt type specific parameters (see crypt-type).
98      *
99      *  @returns 0 on success or negative errno value otherwise.
100      */
101     virtual int cryptLoad(struct crypt_device* cd, const char* requestedType,
102                           void* params) = 0;
103 
104     /** @brief Wrapper around crypt_activate_by_passphrase.
105      *  @details Used for mocking purposes.
106      *
107      *  @param[in] cd - crypt device handle.
108      *  @param[in] name - name of device to create, if NULL only check
109      *    passphrase.
110      *  @param[in] keyslot - requested keyslot to check or CRYPT_ANY_SLOT.
111      *  @param[in] passphrase - passphrase used to unlock volume key.
112      *  @param[in] passphrase_size - size of passphrase.
113      *  @param[in] flags - activation flags.
114      *
115      *  @returns unlocked key slot number or negative errno otherwise.
116      */
117     virtual int cryptActivateByPassphrase(struct crypt_device* cd,
118                                           const char* name, int keyslot,
119                                           const char* passphrase,
120                                           size_t passphraseSize,
121                                           uint32_t flags) = 0;
122 
123     /** @brief Wrapper around crypt_deactivate.
124      *  @details Used for mocking purposes.
125      *
126      *  @param[in] cd - crypt device handle, can be NULL.
127      *  @param[in] name - name of device to deactivate.
128      *
129      *  @returns 0 on success or negative errno value otherwise.
130      */
131     virtual int cryptDeactivate(struct crypt_device* cd, const char* name) = 0;
132 
133     /** @brief Wrapper around crypt_keyslot_destory.
134      *  @details Used for mocking purposes.
135      *
136      *  @param[in] cd - crypt device handle, can not be NULL.
137      *  @param[in] keyslot requested key slot to destroy
138      *
139      *  @returns 0 on success or negative errno value otherwise.
140      */
141     virtual int cryptKeyslotDestroy(struct crypt_device* cd, int keyslot) = 0;
142 
143     /** @brief Wrapper around crypt_keyslot_max
144      *  @details Used for mocking purposes.
145      *
146      * @param type crypt device type
147      *
148      * @return slot count or negative errno otherwise if device
149      * does not support keyslots.
150      */
151     virtual int cryptKeySlotMax(const char* type) = 0;
152 
153     /** @brief Wrapper around crypt_keyslot_status
154      *  @details Used for mocking purposes.
155      *  Get information about particular key slot.
156      *
157      * @param cd crypt device handle
158      * @param keyslot requested keyslot to check or CRYPT_ANY_SLOT
159      *
160      * @return value defined by crypt_keyslot_info
161      */
162     virtual crypt_keyslot_info cryptKeySlotStatus(struct crypt_device* cd,
163                                                   int keyslot) = 0;
164 
165     /** @brief Wrapper around crypt_get_dir.
166      *  @details Used for mocking purposes.
167      *
168      *  @returns the directory where mapped crypt devices are created.
169      */
170     virtual std::string cryptGetDir() = 0;
171 };
172 
173 /** @class Cryptsetup
174  *  @brief Implements CryptsetupInterface.
175  */
176 class Cryptsetup : public CryptsetupInterface
177 {
178   public:
179     ~Cryptsetup() override = default;
180 
181     Cryptsetup() = default;
182     Cryptsetup(const Cryptsetup&) = delete;
183     Cryptsetup& operator=(const Cryptsetup&) = delete;
184 
185     Cryptsetup(Cryptsetup&&) = delete;
186     Cryptsetup& operator=(Cryptsetup&&) = delete;
187     int cryptFormat(struct crypt_device* cd, const char* type,
188                     const char* cipher, const char* cipherMode,
189                     const char* uuid, const char* volumeKey,
190                     size_t volumeKeySize, void* params) override
191     {
192         return crypt_format(cd, type, cipher, cipherMode, uuid, volumeKey,
193                             volumeKeySize, params);
194     }
195 
196     int cryptKeyslotChangeByPassphrase(struct crypt_device* cd, int keyslotOld,
197                                        int keyslotNew, const char* passphrase,
198                                        size_t passphraseSize,
199                                        const char* newPassphrase,
200                                        size_t newPassphraseSize) override
201     {
202         return crypt_keyslot_change_by_passphrase(
203             cd, keyslotOld, keyslotNew, passphrase, passphraseSize,
204             newPassphrase, newPassphraseSize);
205     }
206 
207     int cryptKeyslotAddByVolumeKey(struct crypt_device* cd, int keyslot,
208                                    const char* volumeKey, size_t volumeKeySize,
209                                    const char* passphrase,
210                                    size_t passphraseSize) override
211     {
212         return crypt_keyslot_add_by_volume_key(
213             cd, keyslot, volumeKey, volumeKeySize, passphrase, passphraseSize);
214     }
215 
216     int cryptLoad(struct crypt_device* cd, const char* requestedType,
217                   void* params) override
218     {
219         return crypt_load(cd, requestedType, params);
220     }
221 
222     int cryptActivateByPassphrase(struct crypt_device* cd, const char* name,
223                                   int keyslot, const char* passphrase,
224                                   size_t passphraseSize,
225                                   uint32_t flags) override
226     {
227         return crypt_activate_by_passphrase(cd, name, keyslot, passphrase,
228                                             passphraseSize, flags);
229     }
230 
231     int cryptDeactivate(struct crypt_device* cd, const char* name) override
232     {
233         return crypt_deactivate(cd, name);
234     }
235 
236     int cryptKeyslotDestroy(struct crypt_device* cd, const int keyslot) override
237     {
238         return crypt_keyslot_destroy(cd, keyslot);
239     }
240 
241     int cryptKeySlotMax(const char* type) override
242     {
243         return crypt_keyslot_max(type);
244     }
245 
246     crypt_keyslot_info cryptKeySlotStatus(struct crypt_device* cd,
247                                           int keyslot) override
248     {
249         return crypt_keyslot_status(cd, keyslot);
250     }
251 
252     std::string cryptGetDir() override
253     {
254         return {crypt_get_dir()};
255     }
256 };
257 
258 /** @class CryptHandle
259  *  @brief This manages a crypt_device struct and automatically frees it when
260  *  this handle exits the current scope.
261  */
262 class CryptHandle
263 {
264   public:
265     /** @brief Constructor for CryptHandle
266      *
267      *  @param[in] device - path to device file
268      */
269     explicit CryptHandle(const std::string_view& device) : handle(init(device))
270     {}
271 
272     /** @brief Get a pointer to the crypt_device struct. */
273     struct crypt_device* get()
274     {
275         if (*handle == nullptr)
276         {
277             lg2::error("Failed to get crypt device handle",
278                        "REDFISH_MESSAGE_ID",
279                        std::string("OpenBMC.0.1.HandleGetFail"));
280             throw ResourceNotFound();
281         }
282 
283         return *handle;
284     }
285 
286   private:
287     /** @brief Allocate and initialize the crypt_device struct
288      *
289      *  @param[in] device - path to device file
290      */
291     struct crypt_device* init(const std::string_view& device)
292     {
293         struct crypt_device* cryptDev = nullptr;
294         int retval = crypt_init(&cryptDev, device.data());
295         if (retval < 0)
296         {
297             lg2::error("Failed to crypt_init", "REDFISH_MESSAGE_ID",
298                        std::string("OpenBMC.0.1.InitFail"));
299             throw ResourceNotFound();
300         }
301 
302         return cryptDev;
303     }
304 
305     /** @brief Free the crypt_device struct
306      *
307      *  @param[in] cd - pointer to crypt_device*, to be freed
308      */
309     static void cryptFree(struct crypt_device*&& cd)
310     {
311         crypt_free(cd);
312     }
313 
314     /** @brief Managed handle to crypt_device struct */
315     stdplus::Managed<struct crypt_device*>::Handle<cryptFree> handle;
316 };
317 
318 } // namespace estoraged
319