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