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