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/err.h> 11 #include <openssl/evp.h> 12 #include <openssl/obj_mac.h> 13 #include <openssl/objects.h> 14 #include <openssl/opensslv.h> 15 #include <openssl/pem.h> 16 #include <openssl/rsa.h> 17 #include <unistd.h> 18 19 #include <phosphor-logging/elog-errors.hpp> 20 #include <phosphor-logging/elog.hpp> 21 #include <phosphor-logging/lg2.hpp> 22 #include <sdbusplus/bus.hpp> 23 #include <sdbusplus/exception.hpp> 24 #include <sdbusplus/message.hpp> 25 #include <sdeventplus/source/base.hpp> 26 #include <sdeventplus/source/child.hpp> 27 #include <xyz/openbmc_project/Certs/error.hpp> 28 #include <xyz/openbmc_project/Common/error.hpp> 29 30 #include <algorithm> 31 #include <array> 32 #include <cerrno> 33 #include <chrono> 34 #include <csignal> 35 #include <cstdio> 36 #include <cstdlib> 37 #include <cstring> 38 #include <exception> 39 #include <fstream> 40 #include <utility> 41 42 namespace phosphor::certs 43 { 44 namespace 45 { 46 namespace fs = std::filesystem; 47 using ::phosphor::logging::commit; 48 using ::phosphor::logging::elog; 49 using ::phosphor::logging::report; 50 51 using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate; 52 using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 53 using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 54 using NotAllowedReason = 55 ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON; 56 using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project:: 57 Certs::InvalidCertificate::REASON; 58 using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 59 using Argument = 60 ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument; 61 62 // RAII support for openSSL functions. 63 using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>; 64 using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>; 65 using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>; 66 using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>; 67 68 constexpr int supportedKeyBitLength = 2048; 69 constexpr int defaultKeyBitLength = 2048; 70 // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349 71 constexpr auto defaultKeyCurveID = "secp224r1"; 72 // PEM certificate block markers, defined in go/rfc/7468. 73 constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----"; 74 constexpr std::string_view endCertificate = "-----END CERTIFICATE-----"; 75 76 /** 77 * @brief Splits the given authorities list file and returns an array of 78 * individual PEM encoded x509 certificate. 79 * 80 * @param[in] sourceFilePath - Path to the authorities list file. 81 * 82 * @return An array of individual PEM encoded x509 certificate 83 */ 84 std::vector<std::string> splitCertificates(const std::string& sourceFilePath) 85 { 86 std::ifstream inputCertFileStream; 87 inputCertFileStream.exceptions( 88 std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit); 89 90 std::stringstream pemStream; 91 std::vector<std::string> certificatesList; 92 try 93 { 94 inputCertFileStream.open(sourceFilePath); 95 pemStream << inputCertFileStream.rdbuf(); 96 inputCertFileStream.close(); 97 } 98 catch (const std::exception& e) 99 { 100 lg2::error("Failed to read certificates list, ERR:{ERR}, SRC:{SRC}", 101 "ERR", e, "SRC", sourceFilePath); 102 elog<InternalFailure>(); 103 } 104 std::string pem = pemStream.str(); 105 size_t begin = 0; 106 // |begin| points to the current start position for searching the next 107 // |beginCertificate| block. When we find the beginning of the certificate, 108 // we extract the content between the beginning and the end of the current 109 // certificate. And finally we move |begin| to the end of the current 110 // certificate to start searching the next potential certificate. 111 for (begin = pem.find(beginCertificate, begin); begin != std::string::npos; 112 begin = pem.find(beginCertificate, begin)) 113 { 114 size_t end = pem.find(endCertificate, begin); 115 if (end == std::string::npos) 116 { 117 lg2::error( 118 "invalid PEM contains a BEGIN identifier without an END"); 119 elog<InvalidCertificate>(InvalidCertificateReason( 120 "invalid PEM contains a BEGIN identifier without an END")); 121 } 122 end += endCertificate.size(); 123 certificatesList.emplace_back(pem.substr(begin, end - begin)); 124 begin = end; 125 } 126 return certificatesList; 127 } 128 129 } // namespace 130 131 Manager::Manager(sdbusplus::bus_t& bus, sdeventplus::Event& event, 132 const char* path, CertificateType type, 133 const std::string& unit, const std::string& installPath) : 134 internal::ManagerInterface(bus, path), bus(bus), event(event), 135 objectPath(path), certType(type), unitToRestart(std::move(unit)), 136 certInstallPath(std::move(installPath)), 137 certParentInstallPath(fs::path(certInstallPath).parent_path()) 138 { 139 try 140 { 141 // Create certificate directory if not existing. 142 // Set correct certificate directory permissions. 143 fs::path certDirectory; 144 try 145 { 146 if (certType == CertificateType::authority) 147 { 148 certDirectory = certInstallPath; 149 } 150 else 151 { 152 certDirectory = certParentInstallPath; 153 } 154 155 if (!fs::exists(certDirectory)) 156 { 157 fs::create_directories(certDirectory); 158 } 159 160 auto permission = fs::perms::owner_read | fs::perms::owner_write | 161 fs::perms::owner_exec; 162 fs::permissions(certDirectory, permission, 163 fs::perm_options::replace); 164 storageUpdate(); 165 } 166 catch (const fs::filesystem_error& e) 167 { 168 lg2::error( 169 "Failed to create directory, ERR:{ERR}, DIRECTORY:{DIRECTORY}", 170 "ERR", e, "DIRECTORY", certParentInstallPath); 171 report<InternalFailure>(); 172 } 173 174 // Generating RSA private key file if certificate type is server/client 175 if (certType != CertificateType::authority) 176 { 177 createRSAPrivateKeyFile(); 178 } 179 180 // restore any existing certificates 181 createCertificates(); 182 183 // watch is not required for authority certificates 184 if (certType != CertificateType::authority) 185 { 186 // watch for certificate file create/replace 187 certWatchPtr = std::make_unique< 188 Watch>(event, certInstallPath, [this]() { 189 try 190 { 191 // if certificate file existing update it 192 if (!installedCerts.empty()) 193 { 194 lg2::info("Inotify callback to update " 195 "certificate properties"); 196 installedCerts[0]->populateProperties(); 197 } 198 else 199 { 200 lg2::info( 201 "Inotify callback to create certificate object"); 202 createCertificates(); 203 } 204 } 205 catch (const InternalFailure& e) 206 { 207 commit<InternalFailure>(); 208 } 209 catch (const InvalidCertificate& e) 210 { 211 commit<InvalidCertificate>(); 212 } 213 }); 214 } 215 else 216 { 217 try 218 { 219 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem"; 220 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath)) 221 { 222 lg2::notice( 223 "Legacy certificate detected, will be installed from," 224 "SINGLE_CERTPATH:{SINGLE_CERTPATH}", 225 "SINGLE_CERTPATH", singleCertPath); 226 install(singleCertPath); 227 if (!fs::remove(singleCertPath)) 228 { 229 lg2::error("Unable to remove old certificate from," 230 "SINGLE_CERTPATH:{SINGLE_CERTPATH}", 231 "SINGLE_CERTPATH", singleCertPath); 232 elog<InternalFailure>(); 233 } 234 } 235 } 236 catch (const std::exception& ex) 237 { 238 lg2::error( 239 "Error in restoring legacy certificate, ERROR_STR:{ERROR_STR}", 240 "ERROR_STR", ex); 241 } 242 } 243 } 244 catch (const std::exception& ex) 245 { 246 lg2::error( 247 "Error in certificate manager constructor, ERROR_STR:{ERROR_STR}", 248 "ERROR_STR", ex); 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>(NotAllowedReason( 288 "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 lg2::error("File is Missing, FILE:{FILE}", "FILE", filePath); 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 lg2::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( 353 certInstallPath / 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 lg2::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 const std::vector<std::unique_ptr<Certificate>>::iterator& certIt = 405 std::find_if(installedCerts.begin(), installedCerts.end(), 406 [certificate](const std::unique_ptr<Certificate>& 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 lg2::error("Certificate does not exist, ID:{ID}", "ID", 418 certificate->getCertId()); 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 lg2::error("Error occurred during forking process"); 453 report<InternalFailure>(); 454 } 455 else if (pid == 0) 456 { 457 try 458 { 459 generateCSRHelper( 460 alternativeNames, challengePassword, city, commonName, 461 contactPerson, country, email, givenName, initials, 462 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage, 463 organization, 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 = 486 [this](Child& eventSource, 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 lg2::error("Unable to initialize signal set"); 503 elog<InternalFailure>(); 504 } 505 if (sigaddset(&ss, SIGCHLD) < 0) 506 { 507 lg2::error("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 lg2::error("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 X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free); 550 551 // set subject of x509 req 552 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get()); 553 554 if (!alternativeNames.empty()) 555 { 556 for (auto& name : alternativeNames) 557 { 558 addEntry(x509Name, "subjectAltName", name); 559 } 560 } 561 addEntry(x509Name, "challengePassword", challengePassword); 562 addEntry(x509Name, "L", city); 563 addEntry(x509Name, "CN", commonName); 564 addEntry(x509Name, "name", contactPerson); 565 addEntry(x509Name, "C", country); 566 addEntry(x509Name, "emailAddress", email); 567 addEntry(x509Name, "GN", givenName); 568 addEntry(x509Name, "initials", initials); 569 addEntry(x509Name, "algorithm", keyPairAlgorithm); 570 if (!keyUsage.empty()) 571 { 572 for (auto& usage : keyUsage) 573 { 574 if (isExtendedKeyUsage(usage)) 575 { 576 addEntry(x509Name, "extendedKeyUsage", usage); 577 } 578 else 579 { 580 addEntry(x509Name, "keyUsage", usage); 581 } 582 } 583 } 584 addEntry(x509Name, "O", organization); 585 addEntry(x509Name, "OU", organizationalUnit); 586 addEntry(x509Name, "ST", state); 587 addEntry(x509Name, "SN", surname); 588 addEntry(x509Name, "unstructuredName", unstructuredName); 589 590 EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free); 591 592 lg2::info("Given Key pair algorithm, KEYPAIRALGORITHM:{KEYPAIRALGORITHM}", 593 "KEYPAIRALGORITHM", keyPairAlgorithm); 594 595 // Used EC algorithm as default if user did not give algorithm type. 596 if (keyPairAlgorithm == "RSA") 597 pKey = getRSAKeyPair(keyBitLength); 598 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty())) 599 pKey = generateECKeyPair(keyCurveId); 600 else 601 { 602 lg2::error("Given Key pair algorithm is not supported. Supporting " 603 "RSA and EC only"); 604 elog<InvalidArgument>( 605 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"), 606 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str())); 607 } 608 609 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get()); 610 if (ret == 0) 611 { 612 lg2::error("Error occurred while setting Public key"); 613 ERR_print_errors_fp(stderr); 614 elog<InternalFailure>(); 615 } 616 617 // Write private key to file 618 writePrivateKey(pKey, defaultPrivateKeyFileName); 619 620 // set sign key of x509 req 621 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256()); 622 if (ret == 0) 623 { 624 lg2::error("Error occurred while signing key of x509"); 625 ERR_print_errors_fp(stderr); 626 elog<InternalFailure>(); 627 } 628 629 lg2::info("Writing CSR to file"); 630 fs::path csrFilePath = certParentInstallPath / defaultCSRFileName; 631 writeCSR(csrFilePath.string(), x509Req); 632 } 633 634 bool Manager::isExtendedKeyUsage(const std::string& usage) 635 { 636 const static std::array<const char*, 6> usageList = { 637 "ServerAuthentication", "ClientAuthentication", "OCSPSigning", 638 "Timestamping", "CodeSigning", "EmailProtection"}; 639 auto it = std::find_if( 640 usageList.begin(), usageList.end(), 641 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); }); 642 return it != usageList.end(); 643 } 644 EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength) 645 { 646 int64_t keyBitLen = keyBitLength; 647 // set keybit length to default value if not set 648 if (keyBitLen <= 0) 649 { 650 lg2::info("KeyBitLength is not given.Hence, using default KeyBitLength:" 651 "{DEFAULTKEYBITLENGTH}", 652 "DEFAULTKEYBITLENGTH", defaultKeyBitLength); 653 keyBitLen = defaultKeyBitLength; 654 } 655 656 #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 657 658 // generate rsa key 659 BignumPtr bne(BN_new(), ::BN_free); 660 auto ret = BN_set_word(bne.get(), RSA_F4); 661 if (ret == 0) 662 { 663 lg2::error("Error occurred during BN_set_word call"); 664 ERR_print_errors_fp(stderr); 665 elog<InternalFailure>(); 666 } 667 using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>; 668 RSAPtr rsa(RSA_new(), ::RSA_free); 669 ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr); 670 if (ret != 1) 671 { 672 lg2::error( 673 "Error occurred during RSA_generate_key_ex call: {KEYBITLENGTH}", 674 "KEYBITLENGTH", keyBitLen); 675 ERR_print_errors_fp(stderr); 676 elog<InternalFailure>(); 677 } 678 679 // set public key of x509 req 680 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 681 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get()); 682 if (ret == 0) 683 { 684 lg2::error("Error occurred during assign rsa key into EVP"); 685 ERR_print_errors_fp(stderr); 686 elog<InternalFailure>(); 687 } 688 // Now |rsa| is managed by |pKey| 689 rsa.release(); 690 return pKey; 691 692 #else 693 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 694 EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free); 695 if (!ctx) 696 { 697 lg2::error("Error occurred creating EVP_PKEY_CTX from algorithm"); 698 ERR_print_errors_fp(stderr); 699 elog<InternalFailure>(); 700 } 701 702 if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) || 703 (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), 704 static_cast<int>(keyBitLen)) <= 0)) 705 706 { 707 lg2::error("Error occurred initializing keygen context"); 708 ERR_print_errors_fp(stderr); 709 elog<InternalFailure>(); 710 } 711 712 EVP_PKEY* pKey = nullptr; 713 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 714 { 715 lg2::error("Error occurred during generate EC key"); 716 ERR_print_errors_fp(stderr); 717 elog<InternalFailure>(); 718 } 719 720 return {pKey, &::EVP_PKEY_free}; 721 #endif 722 } 723 724 EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId) 725 { 726 std::string curId(curveId); 727 728 if (curId.empty()) 729 { 730 lg2::info("KeyCurveId is not given. Hence using default curve id," 731 "DEFAULTKEYCURVEID:{DEFAULTKEYCURVEID}", 732 "DEFAULTKEYCURVEID", defaultKeyCurveID); 733 curId = defaultKeyCurveID; 734 } 735 736 int ecGrp = OBJ_txt2nid(curId.c_str()); 737 if (ecGrp == NID_undef) 738 { 739 lg2::error( 740 "Error occurred during convert the curve id string format into NID," 741 "KEYCURVEID:{KEYCURVEID}", 742 "KEYCURVEID", curId); 743 elog<InternalFailure>(); 744 } 745 746 #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 747 748 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp); 749 750 if (ecKey == nullptr) 751 { 752 lg2::error( 753 "Error occurred during create the EC_Key object from NID, ECGROUP:{ECGROUP}", 754 "ECGROUP", ecGrp); 755 ERR_print_errors_fp(stderr); 756 elog<InternalFailure>(); 757 } 758 759 // If you want to save a key and later load it with 760 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE 761 // flag on the key. 762 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE); 763 764 int ret = EC_KEY_generate_key(ecKey); 765 766 if (ret == 0) 767 { 768 EC_KEY_free(ecKey); 769 lg2::error("Error occurred during generate EC key"); 770 ERR_print_errors_fp(stderr); 771 elog<InternalFailure>(); 772 } 773 774 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 775 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey); 776 if (ret == 0) 777 { 778 EC_KEY_free(ecKey); 779 lg2::error("Error occurred during assign EC Key into EVP"); 780 ERR_print_errors_fp(stderr); 781 elog<InternalFailure>(); 782 } 783 784 return pKey; 785 786 #else 787 auto holderOfKey = [](EVP_PKEY* key) { 788 return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{ 789 key, &::EVP_PKEY_free}; 790 }; 791 792 // Create context to set up curve parameters. 793 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 794 EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free); 795 if (!ctx) 796 { 797 lg2::error("Error occurred creating EVP_PKEY_CTX for params"); 798 ERR_print_errors_fp(stderr); 799 elog<InternalFailure>(); 800 } 801 802 // Set up curve parameters. 803 EVP_PKEY* params = nullptr; 804 805 if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) || 806 (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <= 807 0) || 808 (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) || 809 (EVP_PKEY_paramgen(ctx.get(), ¶ms) <= 0)) 810 { 811 lg2::error("Error occurred setting curve parameters"); 812 ERR_print_errors_fp(stderr); 813 elog<InternalFailure>(); 814 } 815 816 // Move parameters to RAII holder. 817 auto pparms = holderOfKey(params); 818 819 // Create new context for key. 820 ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr)); 821 822 if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0)) 823 { 824 lg2::error("Error occurred initializing keygen context"); 825 ERR_print_errors_fp(stderr); 826 elog<InternalFailure>(); 827 } 828 829 EVP_PKEY* pKey = nullptr; 830 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 831 { 832 lg2::error("Error occurred during generate EC key"); 833 ERR_print_errors_fp(stderr); 834 elog<InternalFailure>(); 835 } 836 837 return holderOfKey(pKey); 838 #endif 839 } 840 841 void Manager::writePrivateKey(const EVPPkeyPtr& pKey, 842 const std::string& privKeyFileName) 843 { 844 lg2::info("Writing private key to file"); 845 // write private key to file 846 fs::path privKeyPath = certParentInstallPath / privKeyFileName; 847 848 FILE* fp = std::fopen(privKeyPath.c_str(), "w"); 849 if (fp == nullptr) 850 { 851 lg2::error("Error occurred creating private key file"); 852 elog<InternalFailure>(); 853 } 854 int ret = 855 PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr); 856 std::fclose(fp); 857 if (ret == 0) 858 { 859 lg2::error("Error occurred while writing private key to file"); 860 elog<InternalFailure>(); 861 } 862 } 863 864 void Manager::addEntry(X509_NAME* x509Name, const char* field, 865 const std::string& bytes) 866 { 867 if (bytes.empty()) 868 { 869 return; 870 } 871 int ret = X509_NAME_add_entry_by_txt( 872 x509Name, field, MBSTRING_ASC, 873 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0); 874 if (ret != 1) 875 { 876 lg2::error("Unable to set entry, FIELD:{FIELD}, VALUE:{VALUE}", "FIELD", 877 field, "VALUE", bytes); 878 ERR_print_errors_fp(stderr); 879 elog<InternalFailure>(); 880 } 881 } 882 883 void Manager::createCSRObject(const Status& status) 884 { 885 if (csrPtr) 886 { 887 csrPtr.reset(nullptr); 888 } 889 auto csrObjectPath = objectPath + '/' + "csr"; 890 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(), 891 certInstallPath.c_str(), status); 892 } 893 894 void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req) 895 { 896 if (fs::exists(filePath)) 897 { 898 lg2::info("Removing the existing file, FILENAME:{FILENAME}", "FILENAME", 899 filePath); 900 if (!fs::remove(filePath.c_str())) 901 { 902 lg2::error("Unable to remove the file, FILENAME:{FILENAME}", 903 "FILENAME", filePath); 904 elog<InternalFailure>(); 905 } 906 } 907 908 FILE* fp = std::fopen(filePath.c_str(), "w"); 909 910 if (fp == nullptr) 911 { 912 lg2::error( 913 "Error opening the file to write the CSR, FILENAME:{FILENAME}", 914 "FILENAME", filePath); 915 elog<InternalFailure>(); 916 } 917 918 int rc = PEM_write_X509_REQ(fp, x509Req.get()); 919 if (!rc) 920 { 921 lg2::error("PEM write routine failed, FILENAME:{FILENAME}", "FILENAME", 922 filePath); 923 std::fclose(fp); 924 elog<InternalFailure>(); 925 } 926 std::fclose(fp); 927 } 928 929 void Manager::createCertificates() 930 { 931 auto certObjectPath = objectPath + '/'; 932 933 if (certType == CertificateType::authority) 934 { 935 // Check whether install path is a directory. 936 if (!fs::is_directory(certInstallPath)) 937 { 938 lg2::error("Certificate installation path exists and it is " 939 "not a directory"); 940 elog<InternalFailure>(); 941 } 942 943 // If the authorities list exists, recover from it and return 944 if (fs::path authoritiesListFilePath = 945 fs::path(certInstallPath) / defaultAuthoritiesListFileName; 946 fs::exists(authoritiesListFilePath)) 947 { 948 // remove all other files and directories 949 for (auto& path : fs::directory_iterator(certInstallPath)) 950 { 951 if (path.path() != authoritiesListFilePath) 952 { 953 fs::remove_all(path); 954 } 955 } 956 installAll(authoritiesListFilePath); 957 return; 958 } 959 960 for (auto& path : fs::directory_iterator(certInstallPath)) 961 { 962 try 963 { 964 // Assume here any regular file located in certificate directory 965 // contains certificates body. Do not want to use soft links 966 // would add value. 967 if (fs::is_regular_file(path)) 968 { 969 installedCerts.emplace_back(std::make_unique<Certificate>( 970 bus, certObjectPath + std::to_string(certIdCounter++), 971 certType, certInstallPath, path.path(), 972 certWatchPtr.get(), *this, /*restore=*/true)); 973 } 974 } 975 catch (const InternalFailure& e) 976 { 977 report<InternalFailure>(); 978 } 979 catch (const InvalidCertificate& e) 980 { 981 report<InvalidCertificate>(InvalidCertificateReason( 982 "Existing certificate file is corrupted")); 983 } 984 } 985 } 986 else if (fs::exists(certInstallPath)) 987 { 988 try 989 { 990 installedCerts.emplace_back(std::make_unique<Certificate>( 991 bus, certObjectPath + '1', certType, certInstallPath, 992 certInstallPath, certWatchPtr.get(), *this, /*restore=*/false)); 993 } 994 catch (const InternalFailure& e) 995 { 996 report<InternalFailure>(); 997 } 998 catch (const InvalidCertificate& e) 999 { 1000 report<InvalidCertificate>(InvalidCertificateReason( 1001 "Existing certificate file is corrupted")); 1002 } 1003 } 1004 } 1005 1006 void Manager::createRSAPrivateKeyFile() 1007 { 1008 fs::path rsaPrivateKeyFileName = 1009 certParentInstallPath / defaultRSAPrivateKeyFileName; 1010 1011 try 1012 { 1013 if (!fs::exists(rsaPrivateKeyFileName)) 1014 { 1015 writePrivateKey(generateRSAKeyPair(supportedKeyBitLength), 1016 defaultRSAPrivateKeyFileName); 1017 } 1018 } 1019 catch (const InternalFailure& e) 1020 { 1021 report<InternalFailure>(); 1022 } 1023 } 1024 1025 EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength) 1026 { 1027 if (keyBitLength != supportedKeyBitLength) 1028 { 1029 lg2::error( 1030 "Given Key bit length is not supported, GIVENKEYBITLENGTH:" 1031 "{GIVENKEYBITLENGTH}, SUPPORTEDKEYBITLENGTH:{SUPPORTEDKEYBITLENGTH}", 1032 "GIVENKEYBITLENGTH", keyBitLength, "SUPPORTEDKEYBITLENGTH", 1033 supportedKeyBitLength); 1034 elog<InvalidArgument>( 1035 Argument::ARGUMENT_NAME("KEYBITLENGTH"), 1036 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str())); 1037 } 1038 fs::path rsaPrivateKeyFileName = 1039 certParentInstallPath / defaultRSAPrivateKeyFileName; 1040 1041 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r"); 1042 if (!privateKeyFile) 1043 { 1044 lg2::error( 1045 "Unable to open RSA private key file to read, RSAKEYFILE:{RSAKEYFILE}," 1046 "ERRORREASON:{ERRORREASON}", 1047 "RSAKEYFILE", rsaPrivateKeyFileName, "ERRORREASON", 1048 strerror(errno)); 1049 elog<InternalFailure>(); 1050 } 1051 1052 EVPPkeyPtr privateKey( 1053 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr), 1054 ::EVP_PKEY_free); 1055 std::fclose(privateKeyFile); 1056 1057 if (!privateKey) 1058 { 1059 lg2::error("Error occurred during PEM_read_PrivateKey call"); 1060 elog<InternalFailure>(); 1061 } 1062 return privateKey; 1063 } 1064 1065 void Manager::storageUpdate() 1066 { 1067 if (certType == CertificateType::authority) 1068 { 1069 // Remove symbolic links in the certificate directory 1070 for (auto& certPath : fs::directory_iterator(certInstallPath)) 1071 { 1072 try 1073 { 1074 if (fs::is_symlink(certPath)) 1075 { 1076 fs::remove(certPath); 1077 } 1078 } 1079 catch (const std::exception& e) 1080 { 1081 lg2::error( 1082 "Failed to remove symlink for certificate, ERR:{ERR} SYMLINK:{SYMLINK}", 1083 "ERR", e, "SYMLINK", certPath.path().string()); 1084 elog<InternalFailure>(); 1085 } 1086 } 1087 } 1088 1089 for (const auto& cert : installedCerts) 1090 { 1091 cert->storageUpdate(); 1092 } 1093 } 1094 1095 void Manager::reloadOrReset(const std::string& unit) 1096 { 1097 if (!unit.empty()) 1098 { 1099 try 1100 { 1101 constexpr auto defaultSystemdService = "org.freedesktop.systemd1"; 1102 constexpr auto defaultSystemdObjectPath = 1103 "/org/freedesktop/systemd1"; 1104 constexpr auto defaultSystemdInterface = 1105 "org.freedesktop.systemd1.Manager"; 1106 auto method = bus.new_method_call( 1107 defaultSystemdService, defaultSystemdObjectPath, 1108 defaultSystemdInterface, "ReloadOrRestartUnit"); 1109 method.append(unit, "replace"); 1110 bus.call_noreply(method); 1111 } 1112 catch (const sdbusplus::exception_t& e) 1113 { 1114 lg2::error( 1115 "Failed to reload or restart service, ERR:{ERR}, UNIT:{UNIT}", 1116 "ERR", e, "UNIT", unit); 1117 elog<InternalFailure>(); 1118 } 1119 } 1120 } 1121 1122 bool Manager::isCertificateUnique(const std::string& filePath, 1123 const Certificate* const certToDrop) 1124 { 1125 if (std::any_of( 1126 installedCerts.begin(), installedCerts.end(), 1127 [&filePath, certToDrop](const std::unique_ptr<Certificate>& cert) { 1128 return cert.get() != certToDrop && cert->isSame(filePath); 1129 })) 1130 { 1131 return false; 1132 } 1133 else 1134 { 1135 return true; 1136 } 1137 } 1138 1139 } // namespace phosphor::certs 1140