1 #include "file_io_type_cert.hpp" 2 3 #include "common/utils.hpp" 4 5 #include <libpldm/base.h> 6 #include <libpldm/oem/ibm/file_io.h> 7 #include <stdint.h> 8 9 #include <phosphor-logging/lg2.hpp> 10 11 PHOSPHOR_LOG2_USING; 12 13 namespace pldm 14 { 15 using namespace utils; 16 17 namespace responder 18 { 19 constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/"; 20 constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry"; 21 static constexpr auto certFilePath = "/var/lib/ibm/bmcweb/"; 22 23 CertMap CertHandler::certMap; 24 25 int CertHandler::writeFromMemory(uint32_t offset, uint32_t length, 26 uint64_t address, 27 oem_platform::Handler* /*oemPlatformHandler*/) 28 { 29 auto it = certMap.find(certType); 30 if (it == certMap.end()) 31 { 32 error( 33 "Failed to find file type '{TYPE}' in certificate map. Write from memory during certificate exchange failed", 34 "TYPE", certType); 35 return PLDM_ERROR; 36 } 37 38 auto fd = std::get<0>(it->second); 39 auto& remSize = std::get<1>(it->second); 40 auto rc = transferFileData(fd, false, offset, length, address); 41 if (rc == PLDM_SUCCESS) 42 { 43 remSize -= length; 44 if (!remSize) 45 { 46 close(fd); 47 certMap.erase(it); 48 } 49 } 50 return rc; 51 } 52 53 int CertHandler::readIntoMemory(uint32_t offset, uint32_t length, 54 uint64_t address, 55 oem_platform::Handler* /*oemPlatformHandler*/) 56 { 57 std::string filePath = certFilePath; 58 filePath += "CSR_" + std::to_string(fileHandle); 59 if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST) 60 { 61 return PLDM_ERROR_INVALID_DATA; 62 } 63 auto rc = transferFileData(filePath.c_str(), true, offset, length, address); 64 fs::remove(filePath); 65 if (rc) 66 { 67 return PLDM_ERROR; 68 } 69 return PLDM_SUCCESS; 70 } 71 72 int CertHandler::read(uint32_t offset, uint32_t& length, Response& response, 73 oem_platform::Handler* /*oemPlatformHandler*/) 74 { 75 info( 76 "Read file response for Sign CSR failed and file handle '{FILE_HANDLE}'", 77 "FILE_HANDLE", fileHandle); 78 std::string filePath = certFilePath; 79 filePath += "CSR_" + std::to_string(fileHandle); 80 if (certType != PLDM_FILE_TYPE_CERT_SIGNING_REQUEST) 81 { 82 return PLDM_ERROR_INVALID_DATA; 83 } 84 auto rc = readFile(filePath.c_str(), offset, length, response); 85 fs::remove(filePath); 86 if (rc) 87 { 88 return PLDM_ERROR; 89 } 90 return PLDM_SUCCESS; 91 } 92 93 int CertHandler::write(const char* buffer, uint32_t offset, uint32_t& length, 94 oem_platform::Handler* /*oemPlatformHandler*/) 95 { 96 auto it = certMap.find(certType); 97 if (it == certMap.end()) 98 { 99 error( 100 "Failed to find file type '{TYPE}' in certificate map. Write during certificate exchange failed", 101 "TYPE", certType); 102 return PLDM_ERROR; 103 } 104 105 auto fd = std::get<0>(it->second); 106 int rc = lseek(fd, offset, SEEK_SET); 107 if (rc == -1) 108 { 109 error( 110 "Failed to write certificate lseek at offset '{OFFSET}' of length '{LENGTH}', error number - {ERROR_NUM}", 111 "OFFSET", offset, "LENGTH", length, "ERROR_NUM", errno); 112 return PLDM_ERROR; 113 } 114 rc = ::write(fd, buffer, length); 115 if (rc == -1) 116 { 117 error( 118 "Failed to write certificate at offset '{OFFSET}' of length '{LENGTH}', error number - {ERROR_NUM}", 119 "LENGTH", length, "OFFSET", offset, "ERROR_NUM", errno); 120 return PLDM_ERROR; 121 } 122 length = rc; 123 auto& remSize = std::get<1>(it->second); 124 remSize -= length; 125 if (!remSize) 126 { 127 close(fd); 128 certMap.erase(it); 129 } 130 131 if (certType == PLDM_FILE_TYPE_SIGNED_CERT) 132 { 133 constexpr auto certObjPath = "/xyz/openbmc_project/certs/ca/entry/"; 134 constexpr auto certEntryIntf = "xyz.openbmc_project.Certs.Entry"; 135 136 std::string filePath = certFilePath; 137 filePath += "ClientCert_" + std::to_string(fileHandle); 138 139 std::ifstream inFile; 140 inFile.open(filePath); 141 std::stringstream strStream; 142 strStream << inFile.rdbuf(); 143 std::string str = strStream.str(); 144 inFile.close(); 145 146 if (!str.empty()) 147 { 148 PropertyValue value{str}; 149 150 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle), 151 certEntryIntf, "ClientCertificate", 152 "string"}; 153 try 154 { 155 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 156 } 157 catch (const std::exception& e) 158 { 159 error( 160 "Failed to write for set client certificate, error - {ERROR}", 161 "ERROR", e); 162 return PLDM_ERROR; 163 } 164 PropertyValue valueStatus{ 165 "xyz.openbmc_project.Certs.Entry.State.Complete"}; 166 DBusMapping dbusMappingStatus{certObjPath + 167 std::to_string(fileHandle), 168 certEntryIntf, "Status", "string"}; 169 try 170 { 171 info( 172 "Client certificate write status 'complete' for file handle '{FILE_HANDLE}'", 173 "FILE_HANDLE", fileHandle); 174 pldm::utils::DBusHandler().setDbusProperty(dbusMappingStatus, 175 valueStatus); 176 } 177 catch (const std::exception& e) 178 { 179 error( 180 "Failed to write the set status property for certificate entry, error - {ERROR}", 181 "ERROR", e); 182 return PLDM_ERROR; 183 } 184 fs::remove(filePath); 185 } 186 else 187 { 188 PropertyValue value{"xyz.openbmc_project.Certs.Entry.State.BadCSR"}; 189 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle), 190 certEntryIntf, "Status", "string"}; 191 try 192 { 193 info( 194 "Client certificate write status 'Bad CSR' for file handle '{FILE_HANDLE}'", 195 "FILE_HANDLE", fileHandle); 196 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 197 } 198 catch (const std::exception& e) 199 { 200 error( 201 "Failed to write the set status property for certficate entry, error - {ERROR}", 202 "ERROR", e); 203 return PLDM_ERROR; 204 } 205 } 206 } 207 return PLDM_SUCCESS; 208 } 209 210 int CertHandler::newFileAvailable(uint64_t length) 211 { 212 fs::create_directories(certFilePath); 213 fs::permissions(certFilePath, 214 fs::perms::others_read | fs::perms::owner_write); 215 int fileFd = -1; 216 int flags = O_WRONLY | O_CREAT | O_TRUNC; 217 std::string filePath = certFilePath; 218 219 if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST) 220 { 221 return PLDM_ERROR_INVALID_DATA; 222 } 223 if (certType == PLDM_FILE_TYPE_SIGNED_CERT) 224 { 225 info( 226 "New file available for client certificate file with file handle {FILE_HANDLE}", 227 "FILE_HANDLE", fileHandle); 228 fileFd = open( 229 (filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(), 230 flags, S_IRUSR | S_IWUSR); 231 } 232 else if (certType == PLDM_FILE_TYPE_ROOT_CERT) 233 { 234 fileFd = open((filePath + "RootCert").c_str(), flags, 235 S_IRUSR | S_IWUSR); 236 } 237 if (fileFd == -1) 238 { 239 error( 240 "Failed to open new file available with file type '{TYPE}', error number - {ERROR_NUM}", 241 "TYPE", certType, "ERROR_NUM", errno); 242 return PLDM_ERROR; 243 } 244 certMap.emplace(certType, std::tuple(fileFd, length)); 245 return PLDM_SUCCESS; 246 } 247 248 int CertHandler::newFileAvailableWithMetaData(uint64_t length, 249 uint32_t metaDataValue1, 250 uint32_t /*metaDataValue2*/, 251 uint32_t /*metaDataValue3*/, 252 uint32_t /*metaDataValue4*/) 253 { 254 fs::create_directories(certFilePath); 255 fs::permissions(certFilePath, 256 fs::perms::others_read | fs::perms::owner_write); 257 int fileFd = -1; 258 int flags = O_WRONLY | O_CREAT | O_TRUNC; 259 std::string filePath = certFilePath; 260 261 if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST) 262 { 263 return PLDM_ERROR_INVALID_DATA; 264 } 265 if (certType == PLDM_FILE_TYPE_SIGNED_CERT) 266 { 267 if (metaDataValue1 == PLDM_SUCCESS) 268 { 269 info( 270 "Client certificate new file available with meta data for file handle '{FILE_HANDLE}'", 271 "FILE_HANDLE", fileHandle); 272 fileFd = open( 273 (filePath + "ClientCert_" + std::to_string(fileHandle)).c_str(), 274 flags, S_IRUSR | S_IWUSR); 275 } 276 else if (metaDataValue1 == PLDM_INVALID_CERT_DATA) 277 { 278 error( 279 "New file available with meta data for client certificate file has invalid data '{META_DATA}' with file handle '{FILE_HANDLE}'", 280 "META_DATA", metaDataValue1, "FILE_HANDLE", fileHandle); 281 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle), 282 certEntryIntf, "Status", "string"}; 283 std::string status = "xyz.openbmc_project.Certs.Entry.State.BadCSR"; 284 PropertyValue value{status}; 285 try 286 { 287 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 288 } 289 catch (const std::exception& e) 290 { 291 error( 292 "Failed to set set status property of certificate entry in new file available with meta data, error - {ERROR}", 293 "ERROR", e); 294 return PLDM_ERROR; 295 } 296 } 297 } 298 else if (certType == PLDM_FILE_TYPE_ROOT_CERT) 299 { 300 fileFd = open((filePath + "RootCert").c_str(), flags, 301 S_IRUSR | S_IWUSR); 302 } 303 if (fileFd == -1) 304 { 305 error( 306 "Failed to open file type '{TYPE}' but New file available with meta data, error number - {ERROR_NUM}", 307 "TYPE", certType, "ERROR_NUM", errno); 308 return PLDM_ERROR; 309 } 310 certMap.emplace(certType, std::tuple(fileFd, length)); 311 return PLDM_SUCCESS; 312 } 313 314 int CertHandler::fileAckWithMetaData(uint8_t fileStatus, 315 uint32_t /*metaDataValue1*/, 316 uint32_t /*metaDataValue2*/, 317 uint32_t /*metaDataValue3*/, 318 uint32_t /*metaDataValue4*/) 319 { 320 if (certType == PLDM_FILE_TYPE_CERT_SIGNING_REQUEST) 321 { 322 DBusMapping dbusMapping{certObjPath + std::to_string(fileHandle), 323 certEntryIntf, "Status", "string"}; 324 PropertyValue value = "xyz.openbmc_project.Certs.Entry.State.Pending"; 325 if (fileStatus == PLDM_ERROR_INVALID_DATA) 326 { 327 value = "xyz.openbmc_project.Certs.Entry.State.BadCSR"; 328 } 329 else if (fileStatus == PLDM_ERROR_NOT_READY) 330 { 331 value = "xyz.openbmc_project.Certs.Entry.State.Pending"; 332 } 333 try 334 { 335 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 336 } 337 catch (const std::exception& e) 338 { 339 error( 340 "Failed to set status property of certificate entry for file ack with meta data, error - {ERROR}", 341 "ERROR", e); 342 return PLDM_ERROR; 343 } 344 } 345 return PLDM_SUCCESS; 346 } 347 348 } // namespace responder 349 } // namespace pldm 350