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