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