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