blob: cb8f0fa79865692b7ec1f39bb45e6e6b59b73dfb [file] [log] [blame]
John Wedig2098dab2021-09-14 13:56:28 -07001
2#include "estoraged.hpp"
3
John Wedigb810c922021-11-17 16:38:03 -08004#include "cryptsetupInterface.hpp"
John Edward Broadbent7f2ab642021-11-11 21:00:38 -08005#include "pattern.hpp"
John Edward Broadbente6ffe702021-10-14 14:03:11 -07006#include "verifyDriveGeometry.hpp"
John Edward Broadbent4bc8a102021-12-30 16:11:49 -08007#include "zero.hpp"
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -08008
John Wedigb810c922021-11-17 16:38:03 -08009#include <libcryptsetup.h>
10#include <openssl/rand.h>
11#include <stdlib.h>
12
13#include <phosphor-logging/lg2.hpp>
John Wedig972c3fa2021-12-29 17:30:41 -080014#include <xyz/openbmc_project/Common/error.hpp>
John Wedigb810c922021-11-17 16:38:03 -080015
16#include <filesystem>
John Wedig2098dab2021-09-14 13:56:28 -070017#include <iostream>
John Wedigb810c922021-11-17 16:38:03 -080018#include <string_view>
John Wedig2098dab2021-09-14 13:56:28 -070019#include <vector>
20
21namespace estoraged
22{
23
John Wedig972c3fa2021-12-29 17:30:41 -080024using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
25using sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound;
26using sdbusplus::xyz::openbmc_project::Common::Error::UnsupportedRequest;
John Wedigb810c922021-11-17 16:38:03 -080027
John Wedig972c3fa2021-12-29 17:30:41 -080028void eStoraged::formatLuks(std::vector<uint8_t> password, FilesystemType type)
John Wedig2098dab2021-09-14 13:56:28 -070029{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -080030 std::string msg = "OpenBMC.0.1.DriveFormat";
31 lg2::info("Starting format", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -080032
John Wedig972c3fa2021-12-29 17:30:41 -080033 if (type != FilesystemType::ext4)
34 {
35 lg2::error("Only ext4 filesystems are supported currently",
36 "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.FormatFail"));
37 throw UnsupportedRequest();
38 }
39
John Wedig6218dc52021-12-03 09:36:35 -080040 CryptHandle cryptHandle(devPath.c_str());
41 if (cryptHandle.get() == nullptr)
John Wedigb810c922021-11-17 16:38:03 -080042 {
43 lg2::error("Failed to initialize crypt device", "REDFISH_MESSAGE_ID",
44 std::string("OpenBMC.0.1.FormatFail"));
John Wedig972c3fa2021-12-29 17:30:41 -080045 throw ResourceNotFound();
John Wedigb810c922021-11-17 16:38:03 -080046 }
47
John Wedig6218dc52021-12-03 09:36:35 -080048 formatLuksDev(cryptHandle.get(), password);
49 activateLuksDev(cryptHandle.get(), password);
John Wedigb810c922021-11-17 16:38:03 -080050
51 createFilesystem();
52 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -070053}
54
John Wedig972c3fa2021-12-29 17:30:41 -080055void eStoraged::erase(EraseMethod inEraseMethod)
John Wedig2098dab2021-09-14 13:56:28 -070056{
57 std::cerr << "Erasing encrypted eMMC" << std::endl;
John Edward Broadbente6ffe702021-10-14 14:03:11 -070058 lg2::info("Starting erase", "REDFISH_MESSAGE_ID",
59 std::string("OpenBMC.0.1.DriveErase"));
60 switch (inEraseMethod)
61 {
62 case EraseMethod::CryptoErase:
63 {
64 break;
65 }
66 case EraseMethod::VerifyGeometry:
67 {
68 VerifyDriveGeometry myVerifyGeometry(devPath);
69 uint64_t size = myVerifyGeometry.findSizeOfBlockDevice();
70 myVerifyGeometry.geometryOkay(size);
71 break;
72 }
73 case EraseMethod::LogicalOverWrite:
74 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -080075 Pattern myErasePattern(devPath);
76 ManagedFd drivefd =
77 stdplus::fd::open(devPath, stdplus::fd::OpenAccess::WriteOnly);
78 myErasePattern.writePattern(myErasePattern.findSizeOfBlockDevice(),
79 drivefd);
John Edward Broadbente6ffe702021-10-14 14:03:11 -070080 break;
81 }
82 case EraseMethod::LogicalVerify:
83 {
John Edward Broadbent7f2ab642021-11-11 21:00:38 -080084 Pattern myErasePattern(devPath);
85 ManagedFd drivefd =
86 stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
87 myErasePattern.verifyPattern(myErasePattern.findSizeOfBlockDevice(),
88 drivefd);
John Edward Broadbente6ffe702021-10-14 14:03:11 -070089 break;
90 }
91 case EraseMethod::VendorSanitize:
92 {
93 break;
94 }
95 case EraseMethod::ZeroOverWrite:
96 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -080097 Zero myZero(devPath);
98 ManagedFd drivefd =
99 stdplus::fd::open(devPath, stdplus::fd::OpenAccess::WriteOnly);
100 myZero.writeZero(myZero.findSizeOfBlockDevice(), drivefd);
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700101 break;
102 }
103 case EraseMethod::ZeroVerify:
104 {
John Edward Broadbent4bc8a102021-12-30 16:11:49 -0800105 Zero myZero(devPath);
106 ManagedFd drivefd =
107 stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
108 myZero.verifyZero(myZero.findSizeOfBlockDevice(), drivefd);
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700109 break;
110 }
111 case EraseMethod::SecuredLocked:
112 {
113 break;
114 }
115 }
John Wedig2098dab2021-09-14 13:56:28 -0700116}
117
John Wedig972c3fa2021-12-29 17:30:41 -0800118void eStoraged::lock()
John Wedig2098dab2021-09-14 13:56:28 -0700119{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800120 std::string msg = "OpenBMC.0.1.DriveLock";
121 lg2::info("Starting lock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800122
123 unmountFilesystem();
124 deactivateLuksDev();
John Wedig2098dab2021-09-14 13:56:28 -0700125}
126
John Wedigb810c922021-11-17 16:38:03 -0800127void eStoraged::unlock(std::vector<uint8_t> password)
John Wedig2098dab2021-09-14 13:56:28 -0700128{
John Edward Broadbent4e13b0a2021-11-15 15:21:59 -0800129 std::string msg = "OpenBMC.0.1.DriveUnlock";
130 lg2::info("Starting unlock", "REDFISH_MESSAGE_ID", msg);
John Wedigb810c922021-11-17 16:38:03 -0800131
John Wedig6218dc52021-12-03 09:36:35 -0800132 CryptHandle cryptHandle(devPath.c_str());
133 if (cryptHandle.get() == nullptr)
John Wedigb810c922021-11-17 16:38:03 -0800134 {
135 lg2::error("Failed to initialize crypt device", "REDFISH_MESSAGE_ID",
136 std::string("OpenBMC.0.1.UnlockFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800137 throw ResourceNotFound();
John Wedigb810c922021-11-17 16:38:03 -0800138 }
139
John Wedig6218dc52021-12-03 09:36:35 -0800140 activateLuksDev(cryptHandle.get(), password);
John Wedigb810c922021-11-17 16:38:03 -0800141 mountFilesystem();
John Wedig2098dab2021-09-14 13:56:28 -0700142}
143
144void eStoraged::changePassword(std::vector<uint8_t>, std::vector<uint8_t>)
145{
146 std::cerr << "Changing password for encrypted eMMC" << std::endl;
John Edward Broadbente6ffe702021-10-14 14:03:11 -0700147 lg2::info("Starting change password", "REDFISH_MESSAGE_ID",
148 std::string("OpenBMC.0.1.DrivePasswordChanged"));
John Wedig2098dab2021-09-14 13:56:28 -0700149}
150
John Wedigb810c922021-11-17 16:38:03 -0800151bool eStoraged::isLocked() const
152{
153 return locked();
154}
155
156std::string_view eStoraged::getMountPoint() const
157{
158 return mountPoint;
159}
160
161void eStoraged::formatLuksDev(struct crypt_device* cd,
162 std::vector<uint8_t> password)
163{
164 lg2::info("Formatting device {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
165 std::string("OpenBMC.0.1.FormatLuksDev"));
166
167 /* Generate the volume key. */
168 const std::size_t keySize = 64;
169 std::vector<uint8_t> volumeKey(keySize);
170 if (RAND_bytes(volumeKey.data(), keySize) != 1)
171 {
172 lg2::error("Failed to create volume key", "REDFISH_MESSAGE_ID",
173 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800174 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800175 }
176 /* Format the LUKS encrypted device. */
177 int retval =
178 cryptIface->cryptFormat(cd, CRYPT_LUKS2, "aes", "xts-plain64", nullptr,
179 reinterpret_cast<const char*>(volumeKey.data()),
180 volumeKey.size(), nullptr);
181 if (retval < 0)
182 {
183 lg2::error("Failed to format encrypted device: {RETVAL}", "RETVAL",
184 retval, "REDFISH_MESSAGE_ID",
185 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800186 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800187 }
188
189 /* Device is now encrypted. */
190 locked(true);
191
192 /* Set the password. */
193 retval = cryptIface->cryptKeyslotAddByVolumeKey(
194 cd, CRYPT_ANY_SLOT, nullptr, 0,
195 reinterpret_cast<const char*>(password.data()), password.size());
196
197 if (retval < 0)
198 {
199 lg2::error("Failed to set encryption password", "REDFISH_MESSAGE_ID",
200 std::string("OpenBMC.0.1.FormatLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800201 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800202 }
203
204 lg2::info("Encrypted device {DEV} successfully formatted", "DEV", devPath,
205 "REDFISH_MESSAGE_ID",
206 std::string("OpenBMC.0.1.FormatLuksDevSuccess"));
207}
208
209void eStoraged::activateLuksDev(struct crypt_device* cd,
210 std::vector<uint8_t> password)
211{
212 lg2::info("Activating LUKS dev {DEV}", "DEV", devPath, "REDFISH_MESSAGE_ID",
213 std::string("OpenBMC.0.1.ActivateLuksDev"));
214
215 int retval = cryptIface->cryptLoad(cd, CRYPT_LUKS2, nullptr);
216 if (retval < 0)
217 {
218 lg2::error("Failed to load LUKS header: {RETVAL}", "RETVAL", retval,
219 "REDFISH_MESSAGE_ID",
220 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800221 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800222 }
223
224 retval = cryptIface->cryptActivateByPassphrase(
225 cd, containerName.c_str(), CRYPT_ANY_SLOT,
226 reinterpret_cast<const char*>(password.data()), password.size(), 0);
227
228 if (retval < 0)
229 {
230 lg2::error("Failed to activate LUKS dev: {RETVAL}", "RETVAL", retval,
231 "REDFISH_MESSAGE_ID",
232 std::string("OpenBMC.0.1.ActivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800233 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800234 }
235
236 /* Device is now unlocked. */
237 locked(false);
238
239 lg2::info("Successfully activated LUKS dev {DEV}", "DEV", devPath,
240 "REDFISH_MESSAGE_ID",
241 std::string("OpenBMC.0.1.ActivateLuksDevSuccess"));
242}
243
244void eStoraged::createFilesystem()
245{
246 /* Run the command to create the filesystem. */
247 int retval = fsIface->runMkfs(containerName);
248 if (retval)
249 {
250 lg2::error("Failed to create filesystem: {RETVAL}", "RETVAL", retval,
251 "REDFISH_MESSAGE_ID",
252 std::string("OpenBMC.0.1.CreateFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800253 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800254 }
255 lg2::info("Successfully created filesystem for /dev/mapper/{CONTAINER}",
256 "CONTAINER", containerName, "REDFISH_MESSAGE_ID",
257 std::string("OpenBMC.0.1.CreateFilesystemSuccess"));
258}
259
260void eStoraged::mountFilesystem()
261{
John Wedigb17f8252022-01-12 14:24:26 -0800262 /*
263 * Create directory for the filesystem, if it's not already present. It
264 * might already exist if, for example, the BMC reboots after creating the
265 * directory.
266 */
267 if (!fsIface->directoryExists(std::filesystem::path(mountPoint)))
John Wedigb810c922021-11-17 16:38:03 -0800268 {
John Wedigb17f8252022-01-12 14:24:26 -0800269 bool success =
270 fsIface->createDirectory(std::filesystem::path(mountPoint));
271 if (!success)
272 {
273 lg2::error("Failed to create mount point: {DIR}", "DIR", mountPoint,
274 "REDFISH_MESSAGE_ID",
275 std::string("OpenBMC.0.1.MountFilesystemFail"));
276 throw InternalFailure();
277 }
John Wedigb810c922021-11-17 16:38:03 -0800278 }
279
280 /* Run the command to mount the filesystem. */
281 std::string luksContainer("/dev/mapper/" + containerName);
282 int retval = fsIface->doMount(luksContainer.c_str(), mountPoint.c_str(),
283 "ext4", 0, nullptr);
284 if (retval)
285 {
286 lg2::error("Failed to mount filesystem: {RETVAL}", "RETVAL", retval,
287 "REDFISH_MESSAGE_ID",
288 std::string("OpenBMC.0.1.MountFilesystemFail"));
289 bool removeSuccess =
290 fsIface->removeDirectory(std::filesystem::path(mountPoint));
291 if (!removeSuccess)
292 {
293 lg2::error("Failed to remove mount point: {DIR}", "DIR", mountPoint,
294 "REDFISH_MESSAGE_ID",
295 std::string("OpenBMC.0.1.MountFilesystemFail"));
296 }
John Wedig972c3fa2021-12-29 17:30:41 -0800297 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800298 }
299
300 lg2::info("Successfully mounted filesystem at {DIR}", "DIR", mountPoint,
301 "REDFISH_MESSAGE_ID",
302 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
303}
304
305void eStoraged::unmountFilesystem()
306{
307 int retval = fsIface->doUnmount(mountPoint.c_str());
308 if (retval)
309 {
310 lg2::error("Failed to unmount filesystem: {RETVAL}", "RETVAL", retval,
311 "REDFISH_MESSAGE_ID",
312 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800313 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800314 }
315
316 /* Remove the mount point. */
317 bool success = fsIface->removeDirectory(std::filesystem::path(mountPoint));
318 if (!success)
319 {
320 lg2::error("Failed to remove mount point {DIR}", "DIR", mountPoint,
321 "REDFISH_MESSAGE_ID",
322 std::string("OpenBMC.0.1.UnmountFilesystemFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800323 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800324 }
325
326 lg2::info("Successfully unmounted filesystem at {DIR}", "DIR", mountPoint,
327 "REDFISH_MESSAGE_ID",
328 std::string("OpenBMC.0.1.MountFilesystemSuccess"));
329}
330
331void eStoraged::deactivateLuksDev()
332{
333 lg2::info("Deactivating LUKS device {DEV}", "DEV", devPath,
334 "REDFISH_MESSAGE_ID",
335 std::string("OpenBMC.0.1.DeactivateLuksDev"));
336
337 int retval = cryptIface->cryptDeactivate(nullptr, containerName.c_str());
338 if (retval < 0)
339 {
340 lg2::error("Failed to deactivate crypt device: {RETVAL}", "RETVAL",
341 retval, "REDFISH_MESSAGE_ID",
342 std::string("OpenBMC.0.1.DeactivateLuksDevFail"));
John Wedig972c3fa2021-12-29 17:30:41 -0800343 throw InternalFailure();
John Wedigb810c922021-11-17 16:38:03 -0800344 }
345
346 /* Device is now locked. */
347 locked(true);
348
349 lg2::info("Successfully deactivated LUKS device {DEV}", "DEV", devPath,
350 "REDFISH_MESSAGE_ID",
351 std::string("OpenBMC.0.1.DeactivateLuksDevSuccess"));
352}
353
John Wedig2098dab2021-09-14 13:56:28 -0700354} // namespace estoraged