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