1 #include "config.h" 2 3 #include "certificate.hpp" 4 5 #include "certs_manager.hpp" 6 #include "x509_utils.hpp" 7 8 #include <openssl/asn1.h> 9 #include <openssl/bio.h> 10 #include <openssl/buffer.h> 11 #include <openssl/err.h> 12 #include <openssl/evp.h> 13 #include <openssl/obj_mac.h> 14 #include <openssl/objects.h> 15 #include <openssl/opensslv.h> 16 #include <openssl/pem.h> 17 #include <openssl/x509v3.h> 18 19 #include <phosphor-logging/elog-errors.hpp> 20 #include <phosphor-logging/elog.hpp> 21 #include <phosphor-logging/lg2.hpp> 22 #include <watch.hpp> 23 #include <xyz/openbmc_project/Certs/error.hpp> 24 #include <xyz/openbmc_project/Common/error.hpp> 25 26 #include <cstdint> 27 #include <cstdio> 28 #include <cstdlib> 29 #include <exception> 30 #include <filesystem> 31 #include <fstream> 32 #include <map> 33 #include <utility> 34 #include <vector> 35 36 namespace phosphor::certs 37 { 38 39 namespace 40 { 41 namespace fs = std::filesystem; 42 using ::phosphor::logging::elog; 43 using InvalidCertificateError = 44 ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate; 45 using ::phosphor::logging::xyz::openbmc_project::Certs::InvalidCertificate; 46 using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 47 48 // RAII support for openSSL functions. 49 using BIOMemPtr = std::unique_ptr<BIO, decltype(&::BIO_free)>; 50 using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>; 51 using ASN1TimePtr = std::unique_ptr<ASN1_TIME, decltype(&ASN1_STRING_free)>; 52 using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>; 53 using BufMemPtr = std::unique_ptr<BUF_MEM, decltype(&::BUF_MEM_free)>; 54 55 // Refer to schema 2018.3 56 // http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for 57 // supported KeyUsage types in redfish 58 // Refer to 59 // https://github.com/openssl/openssl/blob/master/include/openssl/x509v3.h for 60 // key usage bit fields 61 std::map<uint8_t, std::string> keyUsageToRfStr = { 62 {KU_DIGITAL_SIGNATURE, "DigitalSignature"}, 63 {KU_NON_REPUDIATION, "NonRepudiation"}, 64 {KU_KEY_ENCIPHERMENT, "KeyEncipherment"}, 65 {KU_DATA_ENCIPHERMENT, "DataEncipherment"}, 66 {KU_KEY_AGREEMENT, "KeyAgreement"}, 67 {KU_KEY_CERT_SIGN, "KeyCertSign"}, 68 {KU_CRL_SIGN, "CRLSigning"}, 69 {KU_ENCIPHER_ONLY, "EncipherOnly"}, 70 {KU_DECIPHER_ONLY, "DecipherOnly"}}; 71 72 // Refer to schema 2018.3 73 // http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for 74 // supported Extended KeyUsage types in redfish 75 std::map<uint8_t, std::string> extendedKeyUsageToRfStr = { 76 {NID_server_auth, "ServerAuthentication"}, 77 {NID_client_auth, "ClientAuthentication"}, 78 {NID_email_protect, "EmailProtection"}, 79 {NID_OCSP_sign, "OCSPSigning"}, 80 {NID_ad_timeStamping, "Timestamping"}, 81 {NID_code_sign, "CodeSigning"}}; 82 83 /** 84 * @brief Dumps the PEM encoded certificate to installFilePath 85 * 86 * @param[in] pem - PEM encoded X509 certificate buffer. 87 * @param[in] certFilePath - Path to the destination file. 88 * 89 * @return void 90 */ 91 92 void dumpCertificate(const std::string& pem, const std::string& certFilePath) 93 { 94 std::ofstream outputCertFileStream; 95 96 outputCertFileStream.exceptions( 97 std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit); 98 99 try 100 { 101 outputCertFileStream.open(certFilePath, std::ios::out); 102 outputCertFileStream << pem << "\n" << std::flush; 103 outputCertFileStream.close(); 104 } 105 catch (const std::exception& e) 106 { 107 lg2::error( 108 "Failed to dump certificate, ERR:{ERR}, SRC_PEM:{SRC_PEM}, DST:{DST}", 109 "ERR", e, "SRC_PEM", pem, "DST", certFilePath); 110 elog<InternalFailure>(); 111 } 112 } 113 } // namespace 114 115 void Certificate::copyCertificate(const std::string& certSrcFilePath, 116 const std::string& certFilePath) 117 { 118 try 119 { 120 // Copy the certificate to the installation path 121 // During bootup will be parsing existing file so no need to 122 // copy it. 123 if (certSrcFilePath != certFilePath) 124 { 125 fs::copy(certSrcFilePath, certFilePath, 126 fs::copy_options::overwrite_existing); 127 } 128 } 129 catch (const fs::filesystem_error& e) 130 { 131 lg2::error( 132 "Failed to copy certificate, ERR:{ERR}, SRC:{SRC}, DST:{DST}", 133 "ERR", e.what(), "SRC", certSrcFilePath, "DST", certFilePath); 134 elog<InternalFailure>(); 135 } 136 } 137 138 std::string 139 Certificate::generateUniqueFilePath(const std::string& directoryPath) 140 { 141 char* filePath = tempnam(directoryPath.c_str(), nullptr); 142 if (filePath == nullptr) 143 { 144 lg2::error( 145 "Error occurred while creating random certificate file path, DIR:{DIR}", 146 "DIR", directoryPath); 147 elog<InternalFailure>(); 148 } 149 std::string filePathStr(filePath); 150 free(filePath); 151 return filePathStr; 152 } 153 154 std::string Certificate::generateAuthCertFileX509Path( 155 const std::string& certSrcFilePath, const std::string& certDstDirPath) 156 { 157 const internal::X509Ptr cert = loadCert(certSrcFilePath); 158 unsigned long hash = X509_subject_name_hash(cert.get()); 159 static constexpr auto certHashLength = 9; 160 char hashBuf[certHashLength]; 161 162 snprintf(hashBuf, certHashLength, "%08lx", hash); 163 164 const std::string certHash(hashBuf); 165 for (size_t i = 0; i < maxNumAuthorityCertificates; ++i) 166 { 167 const std::string certDstFileX509Path = 168 certDstDirPath + "/" + certHash + "." + std::to_string(i); 169 if (!fs::exists(certDstFileX509Path)) 170 { 171 return certDstFileX509Path; 172 } 173 } 174 175 lg2::error("Authority certificate x509 file path already used, DIR:{DIR}", 176 "DIR", certDstDirPath); 177 elog<InternalFailure>(); 178 } 179 180 std::string 181 Certificate::generateAuthCertFilePath(const std::string& certSrcFilePath) 182 { 183 // If there is a certificate file path (which means certificate replacement 184 // is doing) use it (do not create new one) 185 if (!certFilePath.empty()) 186 { 187 return certFilePath; 188 } 189 // If source certificate file is located in the certificates directory use 190 // it (do not create new one) 191 else if (fs::path(certSrcFilePath).parent_path().string() == 192 certInstallPath) 193 { 194 return certSrcFilePath; 195 } 196 // Otherwise generate new file name/path 197 else 198 { 199 return generateUniqueFilePath(certInstallPath); 200 } 201 } 202 203 std::string 204 Certificate::generateCertFilePath(const std::string& certSrcFilePath) 205 { 206 if (certType == CertificateType::authority) 207 { 208 return generateAuthCertFilePath(certSrcFilePath); 209 } 210 else 211 { 212 return certInstallPath; 213 } 214 } 215 216 Certificate::Certificate(sdbusplus::bus_t& bus, const std::string& objPath, 217 CertificateType type, const std::string& installPath, 218 const std::string& uploadPath, Watch* watch, 219 Manager& parent, bool restore) : 220 internal::CertificateInterface( 221 bus, objPath.c_str(), 222 internal::CertificateInterface::action::defer_emit), 223 objectPath(objPath), certType(type), certInstallPath(installPath), 224 certWatch(watch), manager(parent) 225 { 226 auto installHelper = [this](const auto& filePath) { 227 if (!compareKeys(filePath)) 228 { 229 elog<InvalidCertificateError>(InvalidCertificate::REASON( 230 "Private key does not match the Certificate")); 231 }; 232 }; 233 typeFuncMap[CertificateType::server] = installHelper; 234 typeFuncMap[CertificateType::client] = installHelper; 235 typeFuncMap[CertificateType::authority] = [](const std::string&) {}; 236 237 auto appendPrivateKey = [this](const std::string& filePath) { 238 checkAndAppendPrivateKey(filePath); 239 }; 240 241 appendKeyMap[CertificateType::server] = appendPrivateKey; 242 appendKeyMap[CertificateType::client] = appendPrivateKey; 243 appendKeyMap[CertificateType::authority] = [](const std::string&) {}; 244 245 // Generate certificate file path 246 certFilePath = generateCertFilePath(uploadPath); 247 248 // install the certificate 249 install(uploadPath, restore); 250 251 this->emit_object_added(); 252 } 253 254 Certificate::Certificate(sdbusplus::bus_t& bus, const std::string& objPath, 255 const CertificateType& type, 256 const std::string& installPath, X509_STORE& x509Store, 257 const std::string& pem, Watch* watchPtr, 258 Manager& parent, bool restore) : 259 internal::CertificateInterface( 260 bus, objPath.c_str(), 261 internal::CertificateInterface::action::defer_emit), 262 objectPath(objPath), certType(type), certInstallPath(installPath), 263 certWatch(watchPtr), manager(parent) 264 { 265 // Generate certificate file path 266 certFilePath = generateUniqueFilePath(installPath); 267 268 // install the certificate 269 install(x509Store, pem, restore); 270 271 this->emit_object_added(); 272 } 273 274 Certificate::~Certificate() 275 { 276 if (!fs::remove(certFilePath)) 277 { 278 lg2::info("Certificate file not found! PATH:{PATH}", "PATH", 279 certFilePath); 280 } 281 } 282 283 void Certificate::replace(const std::string filePath) 284 { 285 manager.replaceCertificate(this, filePath); 286 } 287 288 void Certificate::install(const std::string& certSrcFilePath, bool restore) 289 { 290 if (restore) 291 { 292 lg2::debug("Certificate install, FILEPATH:{FILEPATH}", "FILEPATH", 293 certSrcFilePath); 294 } 295 else 296 { 297 lg2::info("Certificate install, FILEPATH:{FILEPATH}", "FILEPATH", 298 certSrcFilePath); 299 } 300 301 // stop watch for user initiated certificate install 302 if (certWatch != nullptr) 303 { 304 certWatch->stopWatch(); 305 } 306 307 // Verify the certificate file 308 fs::path file(certSrcFilePath); 309 if (!fs::exists(file)) 310 { 311 lg2::error("File is Missing, FILE:{FILE}", "FILE", certSrcFilePath); 312 elog<InternalFailure>(); 313 } 314 315 try 316 { 317 if (fs::file_size(certSrcFilePath) == 0) 318 { 319 // file is empty 320 lg2::error("File is empty, FILE:{FILE}", "FILE", certSrcFilePath); 321 elog<InvalidCertificateError>( 322 InvalidCertificate::REASON("File is empty")); 323 } 324 } 325 catch (const fs::filesystem_error& e) 326 { 327 // Log Error message 328 lg2::error("File is empty, FILE:{FILE}, ERR:{ERR}", "FILE", 329 certSrcFilePath, "ERR", e); 330 elog<InternalFailure>(); 331 } 332 333 X509StorePtr x509Store = getX509Store(certSrcFilePath); 334 335 // Load Certificate file into the X509 structure. 336 internal::X509Ptr cert = loadCert(certSrcFilePath); 337 338 // Perform validation 339 validateCertificateAgainstStore(*x509Store, *cert); 340 validateCertificateStartDate(*cert); 341 validateCertificateInSSLContext(*cert); 342 343 // Invoke type specific append private key function. 344 if (auto it = appendKeyMap.find(certType); it == appendKeyMap.end()) 345 { 346 lg2::error("Unsupported Type, TYPE:{TYPE}", "TYPE", 347 certificateTypeToString(certType)); 348 elog<InternalFailure>(); 349 } 350 else 351 { 352 it->second(certSrcFilePath); 353 } 354 355 // Invoke type specific compare keys function. 356 if (auto it = typeFuncMap.find(certType); it == typeFuncMap.end()) 357 { 358 lg2::error("Unsupported Type, TYPE:{TYPE}", "TYPE", 359 certificateTypeToString(certType)); 360 elog<InternalFailure>(); 361 } 362 else 363 { 364 it->second(certSrcFilePath); 365 } 366 367 copyCertificate(certSrcFilePath, certFilePath); 368 storageUpdate(); 369 370 // Keep certificate ID 371 certId = generateCertId(*cert); 372 373 // Parse the certificate file and populate properties 374 populateProperties(*cert); 375 376 // restart watch 377 if (certWatch != nullptr) 378 { 379 certWatch->startWatch(); 380 } 381 } 382 383 void Certificate::install(X509_STORE& x509Store, const std::string& pem, 384 bool restore) 385 { 386 if (restore) 387 { 388 lg2::debug("Certificate install, PEM_STR:{PEM_STR}", "PEM_STR", pem); 389 } 390 else 391 { 392 lg2::info("Certificate install, PEM_STR:{PEM_STR} ", "PEM_STR", pem); 393 } 394 395 if (certType != CertificateType::authority) 396 { 397 lg2::error("Bulk install error: Unsupported Type; only authority " 398 "supports bulk install, TYPE:{TYPE}", 399 "TYPE", certificateTypeToString(certType)); 400 elog<InternalFailure>(); 401 } 402 403 // stop watch for user initiated certificate install 404 if (certWatch) 405 { 406 certWatch->stopWatch(); 407 } 408 409 // Load Certificate file into the X509 structure. 410 internal::X509Ptr cert = parseCert(pem); 411 // Perform validation; no type specific compare keys function 412 validateCertificateAgainstStore(x509Store, *cert); 413 validateCertificateStartDate(*cert); 414 validateCertificateInSSLContext(*cert); 415 416 // Copy the PEM to the installation path 417 dumpCertificate(pem, certFilePath); 418 storageUpdate(); 419 // Keep certificate ID 420 certId = generateCertId(*cert); 421 // Parse the certificate file and populate properties 422 populateProperties(*cert); 423 // restart watch 424 if (certWatch) 425 { 426 certWatch->startWatch(); 427 } 428 } 429 430 void Certificate::populateProperties() 431 { 432 internal::X509Ptr cert = loadCert(certInstallPath); 433 populateProperties(*cert); 434 } 435 436 std::string Certificate::getCertId() const 437 { 438 return certId; 439 } 440 441 bool Certificate::isSame(const std::string& certPath) 442 { 443 internal::X509Ptr cert = loadCert(certPath); 444 return getCertId() == generateCertId(*cert); 445 } 446 447 void Certificate::storageUpdate() 448 { 449 if (certType == CertificateType::authority) 450 { 451 // Create symbolic link in the certificate directory 452 std::string certFileX509Path; 453 try 454 { 455 if (!certFilePath.empty() && 456 fs::is_regular_file(fs::path(certFilePath))) 457 { 458 certFileX509Path = 459 generateAuthCertFileX509Path(certFilePath, certInstallPath); 460 fs::create_symlink(fs::path(certFilePath), 461 fs::path(certFileX509Path)); 462 } 463 } 464 catch (const std::exception& e) 465 { 466 lg2::error("Failed to create symlink for certificate, ERR:{ERR}," 467 "FILE:{FILE}, SYMLINK:{SYMLINK}", 468 "ERR", e, "FILE", certFilePath, "SYMLINK", 469 certFileX509Path); 470 elog<InternalFailure>(); 471 } 472 } 473 } 474 475 void Certificate::populateProperties(X509& cert) 476 { 477 // Update properties if no error thrown 478 BIOMemPtr certBio(BIO_new(BIO_s_mem()), BIO_free); 479 PEM_write_bio_X509(certBio.get(), &cert); 480 BufMemPtr certBuf(BUF_MEM_new(), BUF_MEM_free); 481 BUF_MEM* buf = certBuf.get(); 482 BIO_get_mem_ptr(certBio.get(), &buf); 483 std::string certStr(buf->data, buf->length); 484 certificateString(certStr); 485 486 static const int maxKeySize = 4096; 487 char subBuffer[maxKeySize] = {0}; 488 BIOMemPtr subBio(BIO_new(BIO_s_mem()), BIO_free); 489 // This pointer cannot be freed independently. 490 X509_NAME* sub = X509_get_subject_name(&cert); 491 X509_NAME_print_ex(subBio.get(), sub, 0, XN_FLAG_SEP_COMMA_PLUS); 492 BIO_read(subBio.get(), subBuffer, maxKeySize); 493 subject(subBuffer); 494 495 char issuerBuffer[maxKeySize] = {0}; 496 BIOMemPtr issuerBio(BIO_new(BIO_s_mem()), BIO_free); 497 // This pointer cannot be freed independently. 498 X509_NAME* issuerName = X509_get_issuer_name(&cert); 499 X509_NAME_print_ex(issuerBio.get(), issuerName, 0, XN_FLAG_SEP_COMMA_PLUS); 500 BIO_read(issuerBio.get(), issuerBuffer, maxKeySize); 501 issuer(issuerBuffer); 502 503 std::vector<std::string> keyUsageList; 504 505 // Go through each usage in the bit string and convert to 506 // corresponding string value 507 ASN1_BIT_STRING* usage = static_cast<ASN1_BIT_STRING*>( 508 X509_get_ext_d2i(&cert, NID_key_usage, nullptr, nullptr)); 509 if (usage != nullptr) 510 { 511 for (auto i = 0; i < usage->length; ++i) 512 { 513 for (auto& x : keyUsageToRfStr) 514 { 515 if (x.first & usage->data[i]) 516 { 517 keyUsageList.push_back(x.second); 518 break; 519 } 520 } 521 } 522 } 523 524 EXTENDED_KEY_USAGE* extUsage = static_cast<EXTENDED_KEY_USAGE*>( 525 X509_get_ext_d2i(&cert, NID_ext_key_usage, nullptr, nullptr)); 526 if (extUsage == nullptr) 527 { 528 for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++) 529 { 530 keyUsageList.push_back(extendedKeyUsageToRfStr[OBJ_obj2nid( 531 sk_ASN1_OBJECT_value(extUsage, i))]); 532 } 533 } 534 keyUsage(keyUsageList); 535 536 int days = 0; 537 int secs = 0; 538 539 ASN1TimePtr epoch(ASN1_TIME_new(), ASN1_STRING_free); 540 // Set time to 00:00am GMT, Jan 1 1970; format: YYYYMMDDHHMMSSZ 541 ASN1_TIME_set_string(epoch.get(), "19700101000000Z"); 542 543 constexpr uint64_t dayToSeconds = 86400; // 24 * 60 * 60 544 ASN1_TIME* notAfter = X509_get_notAfter(&cert); 545 ASN1_TIME_diff(&days, &secs, epoch.get(), notAfter); 546 validNotAfter((days * dayToSeconds) + secs); 547 548 ASN1_TIME* notBefore = X509_get_notBefore(&cert); 549 ASN1_TIME_diff(&days, &secs, epoch.get(), notBefore); 550 validNotBefore((days * dayToSeconds) + secs); 551 } 552 553 void Certificate::checkAndAppendPrivateKey(const std::string& filePath) 554 { 555 BIOMemPtr keyBio(BIO_new(BIO_s_file()), ::BIO_free); 556 if (!keyBio) 557 { 558 lg2::error("Error occurred during BIO_s_file call, FILE:{FILE}", "FILE", 559 filePath); 560 elog<InternalFailure>(); 561 } 562 BIO_read_filename(keyBio.get(), filePath.c_str()); 563 564 EVPPkeyPtr priKey( 565 PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr), 566 ::EVP_PKEY_free); 567 if (!priKey) 568 { 569 lg2::info("Private key not present in file, FILE:{FILE}", "FILE", 570 filePath); 571 fs::path privateKeyFile = fs::path(certInstallPath).parent_path(); 572 privateKeyFile = privateKeyFile / defaultPrivateKeyFileName; 573 if (!fs::exists(privateKeyFile)) 574 { 575 lg2::error("Private key file is not found, FILE:{FILE}", "FILE", 576 privateKeyFile); 577 elog<InternalFailure>(); 578 } 579 580 std::ifstream privKeyFileStream; 581 std::ofstream certFileStream; 582 privKeyFileStream.exceptions( 583 std::ifstream::failbit | std::ifstream::badbit | 584 std::ifstream::eofbit); 585 certFileStream.exceptions( 586 std::ofstream::failbit | std::ofstream::badbit | 587 std::ofstream::eofbit); 588 try 589 { 590 privKeyFileStream.open(privateKeyFile); 591 certFileStream.open(filePath, std::ios::app); 592 certFileStream << std::endl; // insert line break 593 certFileStream << privKeyFileStream.rdbuf() << std::flush; 594 privKeyFileStream.close(); 595 certFileStream.close(); 596 } 597 catch (const std::exception& e) 598 { 599 lg2::error( 600 "Failed to append private key, ERR:{ERR}, SRC:{SRC}, DST:{DST}", 601 "ERR", e, "SRC", privateKeyFile, "DST", filePath); 602 elog<InternalFailure>(); 603 } 604 } 605 } 606 607 bool Certificate::compareKeys(const std::string& filePath) 608 { 609 lg2::info("Certificate compareKeys, FILEPATH:{FILEPATH}", "FILEPATH", 610 filePath); 611 internal::X509Ptr cert(X509_new(), ::X509_free); 612 if (!cert) 613 { 614 lg2::error( 615 "Error occurred during X509_new call, FILE:{FILE}, ERRCODE:{ERRCODE}", 616 "FILE", filePath, "ERRCODE", ERR_get_error()); 617 elog<InternalFailure>(); 618 } 619 620 BIOMemPtr bioCert(BIO_new_file(filePath.c_str(), "rb"), ::BIO_free); 621 if (!bioCert) 622 { 623 lg2::error("Error occurred during BIO_new_file call, FILE:{FILE}", 624 "FILE", filePath); 625 elog<InternalFailure>(); 626 } 627 628 X509* x509 = cert.get(); 629 PEM_read_bio_X509(bioCert.get(), &x509, nullptr, nullptr); 630 631 EVPPkeyPtr pubKey(X509_get_pubkey(cert.get()), ::EVP_PKEY_free); 632 if (!pubKey) 633 { 634 lg2::error( 635 "Error occurred during X509_get_pubkey, FILE:{FILE}, ERRCODE:{ERRCODE}", 636 "FILE", filePath, "ERRCODE", ERR_get_error()); 637 elog<InvalidCertificateError>( 638 InvalidCertificate::REASON("Failed to get public key info")); 639 } 640 641 BIOMemPtr keyBio(BIO_new(BIO_s_file()), ::BIO_free); 642 if (!keyBio) 643 { 644 lg2::error("Error occurred during BIO_s_file call, FILE:{FILE}", "FILE", 645 filePath); 646 elog<InternalFailure>(); 647 } 648 BIO_read_filename(keyBio.get(), filePath.c_str()); 649 650 EVPPkeyPtr priKey( 651 PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr), 652 ::EVP_PKEY_free); 653 if (!priKey) 654 { 655 lg2::error( 656 "Error occurred during PEM_read_bio_PrivateKey, FILE:{FILE}, ERRCODE:{ERRCODE}", 657 "FILE", filePath, "ERRCODE", ERR_get_error()); 658 elog<InvalidCertificateError>( 659 InvalidCertificate::REASON("Failed to get private key info")); 660 } 661 662 #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 663 int32_t rc = EVP_PKEY_cmp(priKey.get(), pubKey.get()); 664 #else 665 int32_t rc = EVP_PKEY_eq(priKey.get(), pubKey.get()); 666 #endif 667 if (rc != 1) 668 { 669 lg2::error( 670 "Private key is not matching with Certificate, FILE:{FILE}, ERRCODE:{ERRCODE}", 671 "FILE", filePath, "ERRCODE", rc); 672 return false; 673 } 674 return true; 675 } 676 677 void Certificate::delete_() 678 { 679 manager.deleteCertificate(this); 680 } 681 682 std::string Certificate::getObjectPath() 683 { 684 return objectPath; 685 } 686 687 std::string Certificate::getCertFilePath() 688 { 689 return certFilePath; 690 } 691 692 void Certificate::setCertFilePath(const std::string& path) 693 { 694 certFilePath = path; 695 } 696 697 void Certificate::setCertInstallPath(const std::string& path) 698 { 699 certInstallPath = path; 700 } 701 702 } // namespace phosphor::certs 703