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