1 #include "certs_manager.hpp" 2 3 #include <openssl/evp.h> 4 #include <openssl/pem.h> 5 #include <unistd.h> 6 7 #include <algorithm> 8 #include <phosphor-logging/elog-errors.hpp> 9 #include <xyz/openbmc_project/Certs/error.hpp> 10 #include <xyz/openbmc_project/Common/error.hpp> 11 12 namespace phosphor::certs 13 { 14 using InternalFailure = 15 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 16 using InvalidCertificate = 17 sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate; 18 using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON; 19 20 using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>; 21 using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>; 22 using InvalidArgument = 23 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 24 using Argument = xyz::openbmc_project::Common::InvalidArgument; 25 26 constexpr auto SUPPORTED_KEYBITLENGTH = 2048; 27 28 Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event, 29 const char* path, const CertificateType& type, 30 UnitsToRestart&& unit, CertInstallPath&& installPath) : 31 Ifaces(bus, path), 32 bus(bus), event(event), objectPath(path), certType(type), 33 unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)), 34 certParentInstallPath(fs::path(certInstallPath).parent_path()) 35 { 36 try 37 { 38 // Create certificate directory if not existing. 39 // Set correct certificate directory permissions. 40 fs::path certDirectory; 41 try 42 { 43 if (certType == AUTHORITY) 44 { 45 certDirectory = certInstallPath; 46 } 47 else 48 { 49 certDirectory = certParentInstallPath; 50 } 51 52 if (!fs::exists(certDirectory)) 53 { 54 fs::create_directories(certDirectory); 55 } 56 57 auto permission = fs::perms::owner_read | fs::perms::owner_write | 58 fs::perms::owner_exec; 59 fs::permissions(certDirectory, permission, 60 fs::perm_options::replace); 61 storageUpdate(); 62 } 63 catch (const fs::filesystem_error& e) 64 { 65 log<level::ERR>( 66 "Failed to create directory", entry("ERR=%s", e.what()), 67 entry("DIRECTORY=%s", certParentInstallPath.c_str())); 68 report<InternalFailure>(); 69 } 70 71 // Generating RSA private key file if certificate type is server/client 72 if (certType != AUTHORITY) 73 { 74 createRSAPrivateKeyFile(); 75 } 76 77 // restore any existing certificates 78 createCertificates(); 79 80 // watch is not required for authority certificates 81 if (certType != AUTHORITY) 82 { 83 // watch for certificate file create/replace 84 certWatchPtr = std::make_unique< 85 Watch>(event, certInstallPath, [this]() { 86 try 87 { 88 // if certificate file existing update it 89 if (!installedCerts.empty()) 90 { 91 log<level::INFO>("Inotify callback to update " 92 "certificate properties"); 93 installedCerts[0]->populateProperties(); 94 } 95 else 96 { 97 log<level::INFO>( 98 "Inotify callback to create certificate object"); 99 createCertificates(); 100 } 101 } 102 catch (const InternalFailure& e) 103 { 104 commit<InternalFailure>(); 105 } 106 catch (const InvalidCertificate& e) 107 { 108 commit<InvalidCertificate>(); 109 } 110 }); 111 } 112 else 113 { 114 try 115 { 116 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem"; 117 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath)) 118 { 119 log<level::NOTICE>( 120 "Legacy certificate detected, will be installed from: ", 121 entry("SINGLE_CERTPATH=%s", singleCertPath.c_str())); 122 install(singleCertPath); 123 if (!fs::remove(singleCertPath)) 124 { 125 log<level::ERR>( 126 "Unable to remove old certificate from: ", 127 entry("SINGLE_CERTPATH=%s", 128 singleCertPath.c_str())); 129 elog<InternalFailure>(); 130 } 131 } 132 } 133 catch (const std::exception& ex) 134 { 135 log<level::ERR>("Error in restoring legacy certificate", 136 entry("ERROR_STR=%s", ex.what())); 137 } 138 } 139 } 140 catch (const std::exception& ex) 141 { 142 log<level::ERR>("Error in certificate manager constructor", 143 entry("ERROR_STR=%s", ex.what())); 144 } 145 } 146 147 std::string Manager::install(const std::string filePath) 148 { 149 using NotAllowed = 150 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 151 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON; 152 153 if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty()) 154 { 155 elog<NotAllowed>(Reason("Certificate already exist")); 156 } 157 else if (certType == phosphor::certs::AUTHORITY && 158 installedCerts.size() >= maxNumAuthorityCertificates) 159 { 160 elog<NotAllowed>(Reason("Certificates limit reached")); 161 } 162 163 std::string certObjectPath; 164 if (isCertificateUnique(filePath)) 165 { 166 certObjectPath = objectPath + '/' + std::to_string(certIdCounter); 167 installedCerts.emplace_back(std::make_unique<Certificate>( 168 bus, certObjectPath, certType, certInstallPath, filePath, 169 certWatchPtr, *this)); 170 reloadOrReset(unitToRestart); 171 certIdCounter++; 172 } 173 else 174 { 175 elog<NotAllowed>(Reason("Certificate already exist")); 176 } 177 178 return certObjectPath; 179 } 180 181 void Manager::deleteAll() 182 { 183 // TODO: #Issue 4 when a certificate is deleted system auto generates 184 // certificate file. At present we are not supporting creation of 185 // certificate object for the auto-generated certificate file as 186 // deletion if only applicable for REST server and Bmcweb does not allow 187 // deletion of certificates 188 installedCerts.clear(); 189 storageUpdate(); 190 reloadOrReset(unitToRestart); 191 } 192 193 void Manager::deleteCertificate(const Certificate* const certificate) 194 { 195 std::vector<std::unique_ptr<Certificate>>::iterator const& certIt = 196 std::find_if(installedCerts.begin(), installedCerts.end(), 197 [certificate](std::unique_ptr<Certificate> const& cert) { 198 return (cert.get() == certificate); 199 }); 200 if (certIt != installedCerts.end()) 201 { 202 installedCerts.erase(certIt); 203 storageUpdate(); 204 reloadOrReset(unitToRestart); 205 } 206 else 207 { 208 log<level::ERR>("Certificate does not exist", 209 entry("ID=%s", certificate->getCertId().c_str())); 210 elog<InternalFailure>(); 211 } 212 } 213 214 void Manager::replaceCertificate(Certificate* const certificate, 215 const std::string& filePath) 216 { 217 if (isCertificateUnique(filePath, certificate)) 218 { 219 certificate->install(filePath); 220 storageUpdate(); 221 reloadOrReset(unitToRestart); 222 } 223 else 224 { 225 using NotAllowed = 226 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 227 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON; 228 229 elog<NotAllowed>(Reason("Certificate already exist")); 230 } 231 } 232 233 std::string Manager::generateCSR( 234 std::vector<std::string> alternativeNames, std::string challengePassword, 235 std::string city, std::string commonName, std::string contactPerson, 236 std::string country, std::string email, std::string givenName, 237 std::string initials, int64_t keyBitLength, std::string keyCurveId, 238 std::string keyPairAlgorithm, std::vector<std::string> keyUsage, 239 std::string organization, std::string organizationalUnit, std::string state, 240 std::string surname, std::string unstructuredName) 241 { 242 // We support only one CSR. 243 csrPtr.reset(nullptr); 244 auto pid = fork(); 245 if (pid == -1) 246 { 247 log<level::ERR>("Error occurred during forking process"); 248 report<InternalFailure>(); 249 } 250 else if (pid == 0) 251 { 252 try 253 { 254 generateCSRHelper(alternativeNames, challengePassword, city, 255 commonName, contactPerson, country, email, 256 givenName, initials, keyBitLength, keyCurveId, 257 keyPairAlgorithm, keyUsage, organization, 258 organizationalUnit, state, surname, 259 unstructuredName); 260 exit(EXIT_SUCCESS); 261 } 262 catch (const InternalFailure& e) 263 { 264 // commit the error reported in child process and exit 265 // Callback method from SDEvent Loop looks for exit status 266 exit(EXIT_FAILURE); 267 commit<InternalFailure>(); 268 } 269 catch (const InvalidArgument& e) 270 { 271 // commit the error reported in child process and exit 272 // Callback method from SDEvent Loop looks for exit status 273 exit(EXIT_FAILURE); 274 commit<InvalidArgument>(); 275 } 276 } 277 else 278 { 279 using namespace sdeventplus::source; 280 Child::Callback callback = [this](Child& eventSource, 281 const siginfo_t* si) { 282 eventSource.set_enabled(Enabled::On); 283 if (si->si_status != 0) 284 { 285 this->createCSRObject(Status::FAILURE); 286 } 287 else 288 { 289 this->createCSRObject(Status::SUCCESS); 290 } 291 }; 292 try 293 { 294 sigset_t ss; 295 if (sigemptyset(&ss) < 0) 296 { 297 log<level::ERR>("Unable to initialize signal set"); 298 elog<InternalFailure>(); 299 } 300 if (sigaddset(&ss, SIGCHLD) < 0) 301 { 302 log<level::ERR>("Unable to add signal to signal set"); 303 elog<InternalFailure>(); 304 } 305 306 // Block SIGCHLD first, so that the event loop can handle it 307 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0) 308 { 309 log<level::ERR>("Unable to block signal"); 310 elog<InternalFailure>(); 311 } 312 if (childPtr) 313 { 314 childPtr.reset(); 315 } 316 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED, 317 std::move(callback)); 318 } 319 catch (const InternalFailure& e) 320 { 321 commit<InternalFailure>(); 322 } 323 } 324 auto csrObjectPath = objectPath + '/' + "csr"; 325 return csrObjectPath; 326 } 327 328 std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates() 329 { 330 return installedCerts; 331 } 332 333 void Manager::generateCSRHelper( 334 std::vector<std::string> alternativeNames, std::string challengePassword, 335 std::string city, std::string commonName, std::string contactPerson, 336 std::string country, std::string email, std::string givenName, 337 std::string initials, int64_t keyBitLength, std::string keyCurveId, 338 std::string keyPairAlgorithm, std::vector<std::string> keyUsage, 339 std::string organization, std::string organizationalUnit, std::string state, 340 std::string surname, std::string unstructuredName) 341 { 342 int ret = 0; 343 344 // set version of x509 req 345 int nVersion = 1; 346 // TODO: Issue#6 need to make version number configurable 347 X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free); 348 ret = X509_REQ_set_version(x509Req.get(), nVersion); 349 if (ret == 0) 350 { 351 log<level::ERR>("Error occurred during X509_REQ_set_version call"); 352 elog<InternalFailure>(); 353 } 354 355 // set subject of x509 req 356 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get()); 357 358 if (!alternativeNames.empty()) 359 { 360 for (auto& name : alternativeNames) 361 { 362 addEntry(x509Name, "subjectAltName", name); 363 } 364 } 365 addEntry(x509Name, "challengePassword", challengePassword); 366 addEntry(x509Name, "L", city); 367 addEntry(x509Name, "CN", commonName); 368 addEntry(x509Name, "name", contactPerson); 369 addEntry(x509Name, "C", country); 370 addEntry(x509Name, "emailAddress", email); 371 addEntry(x509Name, "GN", givenName); 372 addEntry(x509Name, "initials", initials); 373 addEntry(x509Name, "algorithm", keyPairAlgorithm); 374 if (!keyUsage.empty()) 375 { 376 for (auto& usage : keyUsage) 377 { 378 if (isExtendedKeyUsage(usage)) 379 { 380 addEntry(x509Name, "extendedKeyUsage", usage); 381 } 382 else 383 { 384 addEntry(x509Name, "keyUsage", usage); 385 } 386 } 387 } 388 addEntry(x509Name, "O", organization); 389 addEntry(x509Name, "OU", organizationalUnit); 390 addEntry(x509Name, "ST", state); 391 addEntry(x509Name, "SN", surname); 392 addEntry(x509Name, "unstructuredName", unstructuredName); 393 394 EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free); 395 396 log<level::INFO>("Given Key pair algorithm", 397 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str())); 398 399 // Used EC algorithm as default if user did not give algorithm type. 400 if (keyPairAlgorithm == "RSA") 401 pKey = getRSAKeyPair(keyBitLength); 402 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty())) 403 pKey = generateECKeyPair(keyCurveId); 404 else 405 { 406 log<level::ERR>("Given Key pair algorithm is not supported. Supporting " 407 "RSA and EC only"); 408 elog<InvalidArgument>( 409 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"), 410 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str())); 411 } 412 413 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get()); 414 if (ret == 0) 415 { 416 log<level::ERR>("Error occurred while setting Public key"); 417 elog<InternalFailure>(); 418 } 419 420 // Write private key to file 421 writePrivateKey(pKey, defaultPrivateKeyFileName); 422 423 // set sign key of x509 req 424 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256()); 425 if (ret == 0) 426 { 427 log<level::ERR>("Error occurred while signing key of x509"); 428 elog<InternalFailure>(); 429 } 430 431 log<level::INFO>("Writing CSR to file"); 432 fs::path csrFilePath = certParentInstallPath / defaultCSRFileName; 433 writeCSR(csrFilePath.string(), x509Req); 434 } 435 436 bool Manager::isExtendedKeyUsage(const std::string& usage) 437 { 438 const static std::array<const char*, 6> usageList = { 439 "ServerAuthentication", "ClientAuthentication", "OCSPSigning", 440 "Timestamping", "CodeSigning", "EmailProtection"}; 441 auto it = std::find_if( 442 usageList.begin(), usageList.end(), 443 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); }); 444 return it != usageList.end(); 445 } 446 EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength) 447 { 448 int64_t keyBitLen = keyBitLength; 449 // set keybit length to default value if not set 450 if (keyBitLen <= 0) 451 { 452 constexpr auto DEFAULT_KEYBITLENGTH = 2048; 453 log<level::INFO>( 454 "KeyBitLength is not given.Hence, using default KeyBitLength", 455 entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH)); 456 keyBitLen = DEFAULT_KEYBITLENGTH; 457 } 458 459 #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 460 461 // generate rsa key 462 BIGNUM_Ptr bne(BN_new(), ::BN_free); 463 auto ret = BN_set_word(bne.get(), RSA_F4); 464 if (ret == 0) 465 { 466 log<level::ERR>("Error occurred during BN_set_word call"); 467 elog<InternalFailure>(); 468 } 469 470 RSA* rsa = RSA_new(); 471 ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), nullptr); 472 if (ret != 1) 473 { 474 free(rsa); 475 log<level::ERR>("Error occurred during RSA_generate_key_ex call", 476 entry("KEYBITLENGTH=%PRIu64", keyBitLen)); 477 elog<InternalFailure>(); 478 } 479 480 // set public key of x509 req 481 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 482 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa); 483 if (ret == 0) 484 { 485 free(rsa); 486 log<level::ERR>("Error occurred during assign rsa key into EVP"); 487 elog<InternalFailure>(); 488 } 489 490 return pKey; 491 492 #else 493 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 494 EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free); 495 if (!ctx) 496 { 497 log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm"); 498 elog<InternalFailure>(); 499 } 500 501 if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) || 502 (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0)) 503 504 { 505 log<level::ERR>("Error occurred initializing keygen context"); 506 elog<InternalFailure>(); 507 } 508 509 EVP_PKEY* pKey = nullptr; 510 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 511 { 512 log<level::ERR>("Error occurred during generate EC key"); 513 elog<InternalFailure>(); 514 } 515 516 return {pKey, &::EVP_PKEY_free}; 517 #endif 518 } 519 520 EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId) 521 { 522 std::string curId(curveId); 523 524 if (curId.empty()) 525 { 526 // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349 527 constexpr auto DEFAULT_KEYCURVEID = "secp224r1"; 528 log<level::INFO>( 529 "KeyCurveId is not given. Hence using default curve id", 530 entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID)); 531 curId = DEFAULT_KEYCURVEID; 532 } 533 534 int ecGrp = OBJ_txt2nid(curId.c_str()); 535 if (ecGrp == NID_undef) 536 { 537 log<level::ERR>( 538 "Error occurred during convert the curve id string format into NID", 539 entry("KEYCURVEID=%s", curId.c_str())); 540 elog<InternalFailure>(); 541 } 542 543 #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 544 545 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp); 546 547 if (ecKey == nullptr) 548 { 549 log<level::ERR>( 550 "Error occurred during create the EC_Key object from NID", 551 entry("ECGROUP=%d", ecGrp)); 552 elog<InternalFailure>(); 553 } 554 555 // If you want to save a key and later load it with 556 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE 557 // flag on the key. 558 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE); 559 560 int ret = EC_KEY_generate_key(ecKey); 561 562 if (ret == 0) 563 { 564 EC_KEY_free(ecKey); 565 log<level::ERR>("Error occurred during generate EC key"); 566 elog<InternalFailure>(); 567 } 568 569 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 570 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey); 571 if (ret == 0) 572 { 573 EC_KEY_free(ecKey); 574 log<level::ERR>("Error occurred during assign EC Key into EVP"); 575 elog<InternalFailure>(); 576 } 577 578 return pKey; 579 580 #else 581 auto holder_of_key = [](EVP_PKEY* key) { 582 return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{ 583 key, &::EVP_PKEY_free}; 584 }; 585 586 // Create context to set up curve parameters. 587 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 588 EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free); 589 if (!ctx) 590 { 591 log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params"); 592 elog<InternalFailure>(); 593 } 594 595 // Set up curve parameters. 596 EVP_PKEY* params = nullptr; 597 598 if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) || 599 (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <= 600 0) || 601 (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) || 602 (EVP_PKEY_paramgen(ctx.get(), ¶ms) <= 0)) 603 { 604 log<level::ERR>("Error occurred setting curve parameters"); 605 elog<InternalFailure>(); 606 } 607 608 // Move parameters to RAII holder. 609 auto pparms = holder_of_key(params); 610 611 // Create new context for key. 612 ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr)); 613 614 if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0)) 615 { 616 log<level::ERR>("Error occurred initializing keygen context"); 617 elog<InternalFailure>(); 618 } 619 620 EVP_PKEY* pKey = nullptr; 621 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 622 { 623 log<level::ERR>("Error occurred during generate EC key"); 624 elog<InternalFailure>(); 625 } 626 627 return holder_of_key(pKey); 628 #endif 629 } 630 631 void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey, 632 const std::string& privKeyFileName) 633 { 634 log<level::INFO>("Writing private key to file"); 635 // write private key to file 636 fs::path privKeyPath = certParentInstallPath / privKeyFileName; 637 638 FILE* fp = std::fopen(privKeyPath.c_str(), "w"); 639 if (fp == nullptr) 640 { 641 log<level::ERR>("Error occurred creating private key file"); 642 elog<InternalFailure>(); 643 } 644 int ret = 645 PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr); 646 std::fclose(fp); 647 if (ret == 0) 648 { 649 log<level::ERR>("Error occurred while writing private key to file"); 650 elog<InternalFailure>(); 651 } 652 } 653 654 void Manager::addEntry(X509_NAME* x509Name, const char* field, 655 const std::string& bytes) 656 { 657 if (bytes.empty()) 658 { 659 return; 660 } 661 int ret = X509_NAME_add_entry_by_txt( 662 x509Name, field, MBSTRING_ASC, 663 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0); 664 if (ret != 1) 665 { 666 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field), 667 entry("VALUE=%s", bytes.c_str())); 668 elog<InternalFailure>(); 669 } 670 } 671 672 void Manager::createCSRObject(const Status& status) 673 { 674 if (csrPtr) 675 { 676 csrPtr.reset(nullptr); 677 } 678 auto csrObjectPath = objectPath + '/' + "csr"; 679 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(), 680 certInstallPath.c_str(), status); 681 } 682 683 void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req) 684 { 685 if (fs::exists(filePath)) 686 { 687 log<level::INFO>("Removing the existing file", 688 entry("FILENAME=%s", filePath.c_str())); 689 if (!fs::remove(filePath.c_str())) 690 { 691 log<level::ERR>("Unable to remove the file", 692 entry("FILENAME=%s", filePath.c_str())); 693 elog<InternalFailure>(); 694 } 695 } 696 697 FILE* fp = nullptr; 698 699 if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr) 700 { 701 log<level::ERR>("Error opening the file to write the CSR", 702 entry("FILENAME=%s", filePath.c_str())); 703 elog<InternalFailure>(); 704 } 705 706 int rc = PEM_write_X509_REQ(fp, x509Req.get()); 707 if (!rc) 708 { 709 log<level::ERR>("PEM write routine failed", 710 entry("FILENAME=%s", filePath.c_str())); 711 std::fclose(fp); 712 elog<InternalFailure>(); 713 } 714 std::fclose(fp); 715 } 716 717 void Manager::createCertificates() 718 { 719 auto certObjectPath = objectPath + '/'; 720 721 if (certType == phosphor::certs::AUTHORITY) 722 { 723 // Check whether install path is a directory. 724 if (!fs::is_directory(certInstallPath)) 725 { 726 log<level::ERR>("Certificate installation path exists and it is " 727 "not a directory"); 728 elog<InternalFailure>(); 729 return; 730 } 731 732 for (auto& path : fs::directory_iterator(certInstallPath)) 733 { 734 try 735 { 736 // Assume here any regular file located in certificate directory 737 // contains certificates body. Do not want to use soft links 738 // would add value. 739 if (fs::is_regular_file(path)) 740 { 741 installedCerts.emplace_back(std::make_unique<Certificate>( 742 bus, certObjectPath + std::to_string(certIdCounter++), 743 certType, certInstallPath, path.path(), certWatchPtr, 744 *this)); 745 } 746 } 747 catch (const InternalFailure& e) 748 { 749 report<InternalFailure>(); 750 } 751 catch (const InvalidCertificate& e) 752 { 753 report<InvalidCertificate>( 754 Reason("Existing certificate file is corrupted")); 755 } 756 } 757 } 758 else if (fs::exists(certInstallPath)) 759 { 760 try 761 { 762 installedCerts.emplace_back(std::make_unique<Certificate>( 763 bus, certObjectPath + '1', certType, certInstallPath, 764 certInstallPath, certWatchPtr, *this)); 765 } 766 catch (const InternalFailure& e) 767 { 768 report<InternalFailure>(); 769 } 770 catch (const InvalidCertificate& e) 771 { 772 report<InvalidCertificate>( 773 Reason("Existing certificate file is corrupted")); 774 } 775 } 776 } 777 778 void Manager::createRSAPrivateKeyFile() 779 { 780 fs::path rsaPrivateKeyFileName = 781 certParentInstallPath / defaultRSAPrivateKeyFileName; 782 783 try 784 { 785 if (!fs::exists(rsaPrivateKeyFileName)) 786 { 787 writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH), 788 defaultRSAPrivateKeyFileName); 789 } 790 } 791 catch (const InternalFailure& e) 792 { 793 report<InternalFailure>(); 794 } 795 } 796 797 EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength) 798 { 799 if (keyBitLength != SUPPORTED_KEYBITLENGTH) 800 { 801 log<level::ERR>( 802 "Given Key bit length is not supported", 803 entry("GIVENKEYBITLENGTH=%d", keyBitLength), 804 entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH)); 805 elog<InvalidArgument>( 806 Argument::ARGUMENT_NAME("KEYBITLENGTH"), 807 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str())); 808 } 809 fs::path rsaPrivateKeyFileName = 810 certParentInstallPath / defaultRSAPrivateKeyFileName; 811 812 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r"); 813 if (!privateKeyFile) 814 { 815 log<level::ERR>("Unable to open RSA private key file to read", 816 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()), 817 entry("ERRORREASON=%s", strerror(errno))); 818 elog<InternalFailure>(); 819 } 820 821 EVP_PKEY_Ptr privateKey( 822 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr), 823 ::EVP_PKEY_free); 824 std::fclose(privateKeyFile); 825 826 if (!privateKey) 827 { 828 log<level::ERR>("Error occurred during PEM_read_PrivateKey call"); 829 elog<InternalFailure>(); 830 } 831 return privateKey; 832 } 833 834 void Manager::storageUpdate() 835 { 836 if (certType == phosphor::certs::AUTHORITY) 837 { 838 // Remove symbolic links in the certificate directory 839 for (auto& certPath : fs::directory_iterator(certInstallPath)) 840 { 841 try 842 { 843 if (fs::is_symlink(certPath)) 844 { 845 fs::remove(certPath); 846 } 847 } 848 catch (const std::exception& e) 849 { 850 log<level::ERR>( 851 "Failed to remove symlink for certificate", 852 entry("ERR=%s", e.what()), 853 entry("SYMLINK=%s", certPath.path().string().c_str())); 854 elog<InternalFailure>(); 855 } 856 } 857 } 858 859 for (const auto& cert : installedCerts) 860 { 861 cert->storageUpdate(); 862 } 863 } 864 865 void Manager::reloadOrReset(const UnitsToRestart& unit) 866 { 867 if (!unit.empty()) 868 { 869 try 870 { 871 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 872 constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 873 constexpr auto SYSTEMD_INTERFACE = 874 "org.freedesktop.systemd1.Manager"; 875 876 auto method = 877 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, 878 SYSTEMD_INTERFACE, "ReloadOrRestartUnit"); 879 method.append(unit, "replace"); 880 bus.call_noreply(method); 881 } 882 catch (const sdbusplus::exception::exception& e) 883 { 884 log<level::ERR>("Failed to reload or restart service", 885 entry("ERR=%s", e.what()), 886 entry("UNIT=%s", unit.c_str())); 887 elog<InternalFailure>(); 888 } 889 } 890 } 891 892 bool Manager::isCertificateUnique(const std::string& filePath, 893 const Certificate* const certToDrop) 894 { 895 if (std::any_of( 896 installedCerts.begin(), installedCerts.end(), 897 [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) { 898 return cert.get() != certToDrop && cert->isSame(filePath); 899 })) 900 { 901 return false; 902 } 903 else 904 { 905 return true; 906 } 907 } 908 909 } // namespace phosphor::certs 910