xref: /openbmc/estoraged/src/estoraged.cpp (revision e6ffe704)
1 
2 #include "estoraged.hpp"
3 
4 #include "cryptsetupInterface.hpp"
5 #include "verifyDriveGeometry.hpp"
6 
7 #include <libcryptsetup.h>
8 #include <openssl/rand.h>
9 #include <stdlib.h>
10 
11 #include <phosphor-logging/lg2.hpp>
12 #include <xyz/openbmc_project/eStoraged/error.hpp>
13 
14 #include <filesystem>
15 #include <iostream>
16 #include <string_view>
17 #include <vector>
18 
19 using sdbusplus::xyz::openbmc_project::eStoraged::Error::EraseError;
20 
21 namespace estoraged
22 {
23 
24 using sdbusplus::xyz::openbmc_project::eStoraged::Error::EncryptionError;
25 using sdbusplus::xyz::openbmc_project::eStoraged::Error::FilesystemError;
26 
27 void eStoraged::format(std::vector<uint8_t> password)
28 {
29     std::string msg = "OpenBMC.0.1.DriveFormat";
30     lg2::info("Starting format", "REDFISH_MESSAGE_ID", msg);
31 
32     struct crypt_device* cryptDev;
33     CryptHandle cryptHandle(&cryptDev, devPath.c_str());
34     if (*cryptHandle.handle == nullptr)
35     {
36         lg2::error("Failed to initialize crypt device", "REDFISH_MESSAGE_ID",
37                    std::string("OpenBMC.0.1.FormatFail"));
38         throw EncryptionError();
39     }
40 
41     formatLuksDev(cryptDev, password);
42     activateLuksDev(cryptDev, password);
43 
44     createFilesystem();
45     mountFilesystem();
46 }
47 
48 void eStoraged::erase(std::vector<uint8_t>, EraseMethod inEraseMethod)
49 {
50     std::cerr << "Erasing encrypted eMMC" << std::endl;
51     lg2::info("Starting erase", "REDFISH_MESSAGE_ID",
52               std::string("OpenBMC.0.1.DriveErase"));
53     switch (inEraseMethod)
54     {
55         case EraseMethod::CryptoErase:
56         {
57             break;
58         }
59         case EraseMethod::VerifyGeometry:
60         {
61             VerifyDriveGeometry myVerifyGeometry(devPath);
62             uint64_t size = myVerifyGeometry.findSizeOfBlockDevice();
63             myVerifyGeometry.geometryOkay(size);
64             break;
65         }
66         case EraseMethod::LogicalOverWrite:
67         {
68             break;
69         }
70         case EraseMethod::LogicalVerify:
71         {
72             break;
73         }
74         case EraseMethod::VendorSanitize:
75         {
76             break;
77         }
78         case EraseMethod::ZeroOverWrite:
79         {
80             break;
81         }
82         case EraseMethod::ZeroVerify:
83         {
84             break;
85         }
86         case EraseMethod::SecuredLocked:
87         {
88             break;
89         }
90     }
91 }
92 
93 void eStoraged::lock(std::vector<uint8_t>)
94 {
95     std::string msg = "OpenBMC.0.1.DriveLock";
96     lg2::info("Starting lock", "REDFISH_MESSAGE_ID", msg);
97 
98     unmountFilesystem();
99     deactivateLuksDev();
100 }
101 
102 void eStoraged::unlock(std::vector<uint8_t> password)
103 {
104     std::string msg = "OpenBMC.0.1.DriveUnlock";
105     lg2::info("Starting unlock", "REDFISH_MESSAGE_ID", msg);
106 
107     struct crypt_device* cryptDev;
108     CryptHandle cryptHandle(&cryptDev, devPath.c_str());
109     if (*cryptHandle.handle == nullptr)
110     {
111         lg2::error("Failed to initialize crypt device", "REDFISH_MESSAGE_ID",
112                    std::string("OpenBMC.0.1.UnlockFail"));
113         throw EncryptionError();
114     }
115 
116     activateLuksDev(cryptDev, password);
117     mountFilesystem();
118 }
119 
120 void eStoraged::changePassword(std::vector<uint8_t>, std::vector<uint8_t>)
121 {
122     std::cerr << "Changing password for encrypted eMMC" << std::endl;
123     lg2::info("Starting change password", "REDFISH_MESSAGE_ID",
124               std::string("OpenBMC.0.1.DrivePasswordChanged"));
125 }
126 
127 bool eStoraged::isLocked() const
128 {
129     return locked();
130 }
131 
132 std::string_view eStoraged::getMountPoint() const
133 {
134     return mountPoint;
135 }
136 
137 void eStoraged::formatLuksDev(struct crypt_device* cd,
138                               std::vector<uint8_t> password)
139 {
140     lg2::info("Formatting device {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
141               std::string("OpenBMC.0.1.FormatLuksDev"));
142 
143     /* Generate the volume key. */
144     const std::size_t keySize = 64;
145     std::vector<uint8_t> volumeKey(keySize);
146     if (RAND_bytes(volumeKey.data(), keySize) != 1)
147     {
148         lg2::error("Failed to create volume key", "REDFISH_MESSAGE_ID",
149                    std::string("OpenBMC.0.1.FormatLuksDevFail"));
150         throw EncryptionError();
151     }
152     /* Format the LUKS encrypted device. */
153     int retval =
154         cryptIface->cryptFormat(cd, CRYPT_LUKS2, "aes", "xts-plain64", nullptr,
155                                 reinterpret_cast<const char*>(volumeKey.data()),
156                                 volumeKey.size(), nullptr);
157     if (retval < 0)
158     {
159         lg2::error("Failed to format encrypted device: {RETVAL}", "RETVAL",
160                    retval, "REDFISH_MESSAGE_ID",
161                    std::string("OpenBMC.0.1.FormatLuksDevFail"));
162         throw EncryptionError();
163     }
164 
165     /* Device is now encrypted. */
166     locked(true);
167 
168     /* Set the password. */
169     retval = cryptIface->cryptKeyslotAddByVolumeKey(
170         cd, CRYPT_ANY_SLOT, nullptr, 0,
171         reinterpret_cast<const char*>(password.data()), password.size());
172 
173     if (retval < 0)
174     {
175         lg2::error("Failed to set encryption password", "REDFISH_MESSAGE_ID",
176                    std::string("OpenBMC.0.1.FormatLuksDevFail"));
177         throw EncryptionError();
178     }
179 
180     lg2::info("Encrypted device {DEV} successfully formatted", "DEV", devPath,
181               "REDFISH_MESSAGE_ID",
182               std::string("OpenBMC.0.1.FormatLuksDevSuccess"));
183 }
184 
185 void eStoraged::activateLuksDev(struct crypt_device* cd,
186                                 std::vector<uint8_t> password)
187 {
188     lg2::info("Activating LUKS dev {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
189               std::string("OpenBMC.0.1.ActivateLuksDev"));
190 
191     int retval = cryptIface->cryptLoad(cd, CRYPT_LUKS2, nullptr);
192     if (retval < 0)
193     {
194         lg2::error("Failed to load LUKS header: {RETVAL}", "RETVAL", retval,
195                    "REDFISH_MESSAGE_ID",
196                    std::string("OpenBMC.0.1.ActivateLuksDevFail"));
197         throw EncryptionError();
198     }
199 
200     retval = cryptIface->cryptActivateByPassphrase(
201         cd, containerName.c_str(), CRYPT_ANY_SLOT,
202         reinterpret_cast<const char*>(password.data()), password.size(), 0);
203 
204     if (retval < 0)
205     {
206         lg2::error("Failed to activate LUKS dev: {RETVAL}", "RETVAL", retval,
207                    "REDFISH_MESSAGE_ID",
208                    std::string("OpenBMC.0.1.ActivateLuksDevFail"));
209         throw EncryptionError();
210     }
211 
212     /* Device is now unlocked. */
213     locked(false);
214 
215     lg2::info("Successfully activated LUKS dev {DEV}", "DEV", devPath,
216               "REDFISH_MESSAGE_ID",
217               std::string("OpenBMC.0.1.ActivateLuksDevSuccess"));
218 }
219 
220 void eStoraged::createFilesystem()
221 {
222     /* Run the command to create the filesystem. */
223     int retval = fsIface->runMkfs(containerName);
224     if (retval)
225     {
226         lg2::error("Failed to create filesystem: {RETVAL}", "RETVAL", retval,
227                    "REDFISH_MESSAGE_ID",
228                    std::string("OpenBMC.0.1.CreateFilesystemFail"));
229         throw FilesystemError();
230     }
231     lg2::info("Successfully created filesystem for /dev/mapper/{CONTAINER}",
232               "CONTAINER", containerName, "REDFISH_MESSAGE_ID",
233               std::string("OpenBMC.0.1.CreateFilesystemSuccess"));
234 }
235 
236 void eStoraged::mountFilesystem()
237 {
238     /* Create directory for the filesystem. */
239     bool success = fsIface->createDirectory(std::filesystem::path(mountPoint));
240     if (!success)
241     {
242         lg2::error("Failed to create mount point: {DIR}", "DIR", mountPoint,
243                    "REDFISH_MESSAGE_ID",
244                    std::string("OpenBMC.0.1.MountFilesystemFail"));
245         throw FilesystemError();
246     }
247 
248     /* Run the command to mount the filesystem. */
249     std::string luksContainer("/dev/mapper/" + containerName);
250     int retval = fsIface->doMount(luksContainer.c_str(), mountPoint.c_str(),
251                                   "ext4", 0, nullptr);
252     if (retval)
253     {
254         lg2::error("Failed to mount filesystem: {RETVAL}", "RETVAL", retval,
255                    "REDFISH_MESSAGE_ID",
256                    std::string("OpenBMC.0.1.MountFilesystemFail"));
257         bool removeSuccess =
258             fsIface->removeDirectory(std::filesystem::path(mountPoint));
259         if (!removeSuccess)
260         {
261             lg2::error("Failed to remove mount point: {DIR}", "DIR", mountPoint,
262                        "REDFISH_MESSAGE_ID",
263                        std::string("OpenBMC.0.1.MountFilesystemFail"));
264         }
265         throw FilesystemError();
266     }
267 
268     lg2::info("Successfully mounted filesystem at {DIR}", "DIR", mountPoint,
269               "REDFISH_MESSAGE_ID",
270               std::string("OpenBMC.0.1.MountFilesystemSuccess"));
271 }
272 
273 void eStoraged::unmountFilesystem()
274 {
275     int retval = fsIface->doUnmount(mountPoint.c_str());
276     if (retval)
277     {
278         lg2::error("Failed to unmount filesystem: {RETVAL}", "RETVAL", retval,
279                    "REDFISH_MESSAGE_ID",
280                    std::string("OpenBMC.0.1.UnmountFilesystemFail"));
281         throw FilesystemError();
282     }
283 
284     /* Remove the mount point. */
285     bool success = fsIface->removeDirectory(std::filesystem::path(mountPoint));
286     if (!success)
287     {
288         lg2::error("Failed to remove mount point {DIR}", "DIR", mountPoint,
289                    "REDFISH_MESSAGE_ID",
290                    std::string("OpenBMC.0.1.UnmountFilesystemFail"));
291         throw FilesystemError();
292     }
293 
294     lg2::info("Successfully unmounted filesystem at {DIR}", "DIR", mountPoint,
295               "REDFISH_MESSAGE_ID",
296               std::string("OpenBMC.0.1.MountFilesystemSuccess"));
297 }
298 
299 void eStoraged::deactivateLuksDev()
300 {
301     lg2::info("Deactivating LUKS device {DEV}", "DEV", devPath,
302               "REDFISH_MESSAGE_ID",
303               std::string("OpenBMC.0.1.DeactivateLuksDev"));
304 
305     int retval = cryptIface->cryptDeactivate(nullptr, containerName.c_str());
306     if (retval < 0)
307     {
308         lg2::error("Failed to deactivate crypt device: {RETVAL}", "RETVAL",
309                    retval, "REDFISH_MESSAGE_ID",
310                    std::string("OpenBMC.0.1.DeactivateLuksDevFail"));
311         throw EncryptionError();
312     }
313 
314     /* Device is now locked. */
315     locked(true);
316 
317     lg2::info("Successfully deactivated LUKS device {DEV}", "DEV", devPath,
318               "REDFISH_MESSAGE_ID",
319               std::string("OpenBMC.0.1.DeactivateLuksDevSuccess"));
320 }
321 
322 } // namespace estoraged
323