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