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