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