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(
67         struct crypt_device* cd, int keyslotOld, int keyslotNew,
68         const char* passphrase, size_t passphraseSize,
69         const char* newPassphrase, size_t newPassphraseSize) = 0;
70 
71     /** @brief Wrapper around crypt_keyslot_add_by_volume_key.
72      *  @details Used for mocking purposes.
73      *
74      *  @param[in] cd - crypt device handle.
75      *  @param[in] keyslot - requested keyslot or CRYPT_ANY_SLOT.
76      *  @param[in] volume_key - provided volume key or NULL if used after
77      *    crypt_format.
78      *  @param[in] volume_key_size - size of volume_key.
79      *  @param[in] passphrase - passphrase for new keyslot.
80      *  @param[in] passphrase_size - size of passphrase.
81      *
82      *  @returns allocated key slot number or negative errno otherwise.
83      */
84     virtual int cryptKeyslotAddByVolumeKey(
85         struct crypt_device* cd, int keyslot, const char* volumeKey,
86         size_t volumeKeySize, const char* passphrase,
87         size_t passphraseSize) = 0;
88 
89     /** @brief Wrapper around crypt_load.
90      *  @details Used for mocking purposes.
91      *
92      *  @param[in] cd - crypt device handle.
93      *  @param[in] requested_type - crypt-type or NULL for all known.
94      *  @param[in] params - crypt type specific parameters (see crypt-type).
95      *
96      *  @returns 0 on success or negative errno value otherwise.
97      */
98     virtual int cryptLoad(struct crypt_device* cd, const char* requestedType,
99                           void* params) = 0;
100 
101     /** @brief Wrapper around crypt_activate_by_passphrase.
102      *  @details Used for mocking purposes.
103      *
104      *  @param[in] cd - crypt device handle.
105      *  @param[in] name - name of device to create, if NULL only check
106      *    passphrase.
107      *  @param[in] keyslot - requested keyslot to check or CRYPT_ANY_SLOT.
108      *  @param[in] passphrase - passphrase used to unlock volume key.
109      *  @param[in] passphrase_size - size of passphrase.
110      *  @param[in] flags - activation flags.
111      *
112      *  @returns unlocked key slot number or negative errno otherwise.
113      */
114     virtual int cryptActivateByPassphrase(
115         struct crypt_device* cd, const char* name, int keyslot,
116         const char* passphrase, size_t passphraseSize, uint32_t flags) = 0;
117 
118     /** @brief Wrapper around crypt_deactivate.
119      *  @details Used for mocking purposes.
120      *
121      *  @param[in] cd - crypt device handle, can be NULL.
122      *  @param[in] name - name of device to deactivate.
123      *
124      *  @returns 0 on success or negative errno value otherwise.
125      */
126     virtual int cryptDeactivate(struct crypt_device* cd, const char* name) = 0;
127 
128     /** @brief Wrapper around crypt_keyslot_destory.
129      *  @details Used for mocking purposes.
130      *
131      *  @param[in] cd - crypt device handle, can not be NULL.
132      *  @param[in] keyslot requested key slot to destroy
133      *
134      *  @returns 0 on success or negative errno value otherwise.
135      */
136     virtual int cryptKeyslotDestroy(struct crypt_device* cd, int keyslot) = 0;
137 
138     /** @brief Wrapper around crypt_keyslot_max
139      *  @details Used for mocking purposes.
140      *
141      * @param type crypt device type
142      *
143      * @return slot count or negative errno otherwise if device
144      * does not support keyslots.
145      */
146     virtual int cryptKeySlotMax(const char* type) = 0;
147 
148     /** @brief Wrapper around crypt_keyslot_status
149      *  @details Used for mocking purposes.
150      *  Get information about particular key slot.
151      *
152      * @param cd crypt device handle
153      * @param keyslot requested keyslot to check or CRYPT_ANY_SLOT
154      *
155      * @return value defined by crypt_keyslot_info
156      */
157     virtual crypt_keyslot_info
158         cryptKeySlotStatus(struct crypt_device* cd, int keyslot) = 0;
159 
160     /** @brief Wrapper around crypt_get_dir.
161      *  @details Used for mocking purposes.
162      *
163      *  @returns the directory where mapped crypt devices are created.
164      */
165     virtual std::string cryptGetDir() = 0;
166 };
167 
168 /** @class Cryptsetup
169  *  @brief Implements CryptsetupInterface.
170  */
171 class Cryptsetup : public CryptsetupInterface
172 {
173   public:
174     ~Cryptsetup() override = default;
175 
176     Cryptsetup() = default;
177     Cryptsetup(const Cryptsetup&) = delete;
178     Cryptsetup& operator=(const Cryptsetup&) = delete;
179 
180     Cryptsetup(Cryptsetup&&) = delete;
181     Cryptsetup& operator=(Cryptsetup&&) = delete;
cryptFormat(struct crypt_device * cd,const char * type,const char * cipher,const char * cipherMode,const char * uuid,const char * volumeKey,size_t volumeKeySize,void * params)182     int cryptFormat(struct crypt_device* cd, const char* type,
183                     const char* cipher, const char* cipherMode,
184                     const char* uuid, const char* volumeKey,
185                     size_t volumeKeySize, void* params) override
186     {
187         return crypt_format(cd, type, cipher, cipherMode, uuid, volumeKey,
188                             volumeKeySize, params);
189     }
190 
cryptKeyslotChangeByPassphrase(struct crypt_device * cd,int keyslotOld,int keyslotNew,const char * passphrase,size_t passphraseSize,const char * newPassphrase,size_t newPassphraseSize)191     int cryptKeyslotChangeByPassphrase(
192         struct crypt_device* cd, int keyslotOld, int keyslotNew,
193         const char* passphrase, size_t passphraseSize,
194         const char* newPassphrase, size_t newPassphraseSize) override
195     {
196         return crypt_keyslot_change_by_passphrase(
197             cd, keyslotOld, keyslotNew, passphrase, passphraseSize,
198             newPassphrase, newPassphraseSize);
199     }
200 
cryptKeyslotAddByVolumeKey(struct crypt_device * cd,int keyslot,const char * volumeKey,size_t volumeKeySize,const char * passphrase,size_t passphraseSize)201     int cryptKeyslotAddByVolumeKey(struct crypt_device* cd, int keyslot,
202                                    const char* volumeKey, size_t volumeKeySize,
203                                    const char* passphrase,
204                                    size_t passphraseSize) override
205     {
206         return crypt_keyslot_add_by_volume_key(
207             cd, keyslot, volumeKey, volumeKeySize, passphrase, passphraseSize);
208     }
209 
cryptLoad(struct crypt_device * cd,const char * requestedType,void * params)210     int cryptLoad(struct crypt_device* cd, const char* requestedType,
211                   void* params) override
212     {
213         return crypt_load(cd, requestedType, params);
214     }
215 
cryptActivateByPassphrase(struct crypt_device * cd,const char * name,int keyslot,const char * passphrase,size_t passphraseSize,uint32_t flags)216     int cryptActivateByPassphrase(
217         struct crypt_device* cd, const char* name, int keyslot,
218         const char* passphrase, size_t passphraseSize, uint32_t flags) override
219     {
220         return crypt_activate_by_passphrase(cd, name, keyslot, passphrase,
221                                             passphraseSize, flags);
222     }
223 
cryptDeactivate(struct crypt_device * cd,const char * name)224     int cryptDeactivate(struct crypt_device* cd, const char* name) override
225     {
226         return crypt_deactivate(cd, name);
227     }
228 
cryptKeyslotDestroy(struct crypt_device * cd,const int keyslot)229     int cryptKeyslotDestroy(struct crypt_device* cd, const int keyslot) override
230     {
231         return crypt_keyslot_destroy(cd, keyslot);
232     }
233 
cryptKeySlotMax(const char * type)234     int cryptKeySlotMax(const char* type) override
235     {
236         return crypt_keyslot_max(type);
237     }
238 
cryptKeySlotStatus(struct crypt_device * cd,int keyslot)239     crypt_keyslot_info cryptKeySlotStatus(struct crypt_device* cd,
240                                           int keyslot) override
241     {
242         return crypt_keyslot_status(cd, keyslot);
243     }
244 
cryptGetDir()245     std::string cryptGetDir() override
246     {
247         return {crypt_get_dir()};
248     }
249 };
250 
251 /** @class CryptHandle
252  *  @brief This manages a crypt_device struct and automatically frees it when
253  *  this handle exits the current scope.
254  */
255 class CryptHandle
256 {
257   public:
258     /** @brief Constructor for CryptHandle
259      *
260      *  @param[in] device - path to device file
261      */
CryptHandle(const std::string_view & device)262     explicit CryptHandle(const std::string_view& device) : handle(init(device))
263     {}
264 
265     /** @brief Get a pointer to the crypt_device struct. */
get()266     struct crypt_device* get()
267     {
268         if (*handle == nullptr)
269         {
270             lg2::error("Failed to get crypt device handle",
271                        "REDFISH_MESSAGE_ID",
272                        std::string("OpenBMC.0.1.HandleGetFail"));
273             throw ResourceNotFound();
274         }
275 
276         return *handle;
277     }
278 
279   private:
280     /** @brief Allocate and initialize the crypt_device struct
281      *
282      *  @param[in] device - path to device file
283      */
init(const std::string_view & device)284     struct crypt_device* init(const std::string_view& device)
285     {
286         struct crypt_device* cryptDev = nullptr;
287         int retval = crypt_init(&cryptDev, device.data());
288         if (retval < 0)
289         {
290             lg2::error("Failed to crypt_init", "REDFISH_MESSAGE_ID",
291                        std::string("OpenBMC.0.1.InitFail"));
292             throw ResourceNotFound();
293         }
294 
295         return cryptDev;
296     }
297 
298     /** @brief Free the crypt_device struct
299      *
300      *  @param[in] cd - pointer to crypt_device*, to be freed
301      */
cryptFree(struct crypt_device * && cd)302     static void cryptFree(struct crypt_device*&& cd)
303     {
304         crypt_free(cd);
305     }
306 
307     /** @brief Managed handle to crypt_device struct */
308     stdplus::Managed<struct crypt_device*>::Handle<cryptFree> handle;
309 };
310 
311 } // namespace estoraged
312