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