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