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