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