1cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp" 2cfbc8dc8SJayanth Othayoth 326fb83efSPatrick Williams #include <openssl/evp.h> 4f4682712SMarri Devender Rao #include <openssl/pem.h> 5f4682712SMarri Devender Rao #include <unistd.h> 6f4682712SMarri Devender Rao 7a3bb38fbSZbigniew Kurzynski #include <algorithm> 86ceec40bSMarri Devender Rao #include <phosphor-logging/elog-errors.hpp> 913bf74e4SMarri Devender Rao #include <xyz/openbmc_project/Certs/error.hpp> 10cfbc8dc8SJayanth Othayoth #include <xyz/openbmc_project/Common/error.hpp> 112f3563ccSZbigniew Lukwinski 12cfbc8dc8SJayanth Othayoth namespace phosphor 13cfbc8dc8SJayanth Othayoth { 14cfbc8dc8SJayanth Othayoth namespace certs 15cfbc8dc8SJayanth Othayoth { 161396511dSMarri Devender Rao using InternalFailure = 171396511dSMarri Devender Rao sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 18ffad1ef1SMarri Devender Rao using InvalidCertificate = 19ffad1ef1SMarri Devender Rao sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate; 20ffad1ef1SMarri Devender Rao using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON; 21cfbc8dc8SJayanth Othayoth 22f4682712SMarri Devender Rao using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>; 23f4682712SMarri Devender Rao using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>; 24c6e58c7eSRamesh Iyyar using InvalidArgument = 25c6e58c7eSRamesh Iyyar sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 26c6e58c7eSRamesh Iyyar using Argument = xyz::openbmc_project::Common::InvalidArgument; 27c6e58c7eSRamesh Iyyar 28c6e58c7eSRamesh Iyyar constexpr auto SUPPORTED_KEYBITLENGTH = 2048; 29f4682712SMarri Devender Rao 30f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event, 31f4682712SMarri Devender Rao const char* path, const CertificateType& type, 32f4682712SMarri Devender Rao UnitsToRestart&& unit, CertInstallPath&& installPath) : 336ceec40bSMarri Devender Rao Ifaces(bus, path), 34f4682712SMarri Devender Rao bus(bus), event(event), objectPath(path), certType(type), 35c6e58c7eSRamesh Iyyar unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)), 36c6e58c7eSRamesh Iyyar certParentInstallPath(fs::path(certInstallPath).parent_path()) 37cfbc8dc8SJayanth Othayoth { 38db5c6fc8SMarri Devender Rao try 39db5c6fc8SMarri Devender Rao { 40fe590c4eSZbigniew Lukwinski // Create certificate directory if not existing. 41bf3cf751SNan Zhou // Set correct certificate directory permissions. 42fe590c4eSZbigniew Lukwinski fs::path certDirectory; 43b57d75e2SMarri Devender Rao try 44b57d75e2SMarri Devender Rao { 45fe590c4eSZbigniew Lukwinski if (certType == AUTHORITY) 46b57d75e2SMarri Devender Rao { 47fe590c4eSZbigniew Lukwinski certDirectory = certInstallPath; 48b57d75e2SMarri Devender Rao } 49fe590c4eSZbigniew Lukwinski else 50fe590c4eSZbigniew Lukwinski { 51fe590c4eSZbigniew Lukwinski certDirectory = certParentInstallPath; 52fe590c4eSZbigniew Lukwinski } 53fe590c4eSZbigniew Lukwinski 54fe590c4eSZbigniew Lukwinski if (!fs::exists(certDirectory)) 55fe590c4eSZbigniew Lukwinski { 56fe590c4eSZbigniew Lukwinski fs::create_directories(certDirectory); 57fe590c4eSZbigniew Lukwinski } 58fe590c4eSZbigniew Lukwinski 59667286e4SMarri Devender Rao auto permission = fs::perms::owner_read | fs::perms::owner_write | 60667286e4SMarri Devender Rao fs::perms::owner_exec; 61db5c6fc8SMarri Devender Rao fs::permissions(certDirectory, permission, 62db5c6fc8SMarri Devender Rao fs::perm_options::replace); 632f3563ccSZbigniew Lukwinski storageUpdate(); 64b57d75e2SMarri Devender Rao } 6571957992SPatrick Williams catch (const fs::filesystem_error& e) 66b57d75e2SMarri Devender Rao { 67db5c6fc8SMarri Devender Rao log<level::ERR>( 68db5c6fc8SMarri Devender Rao "Failed to create directory", entry("ERR=%s", e.what()), 69b57d75e2SMarri Devender Rao entry("DIRECTORY=%s", certParentInstallPath.c_str())); 70b57d75e2SMarri Devender Rao report<InternalFailure>(); 71b57d75e2SMarri Devender Rao } 72b57d75e2SMarri Devender Rao 73c6e58c7eSRamesh Iyyar // Generating RSA private key file if certificate type is server/client 74c6e58c7eSRamesh Iyyar if (certType != AUTHORITY) 75c6e58c7eSRamesh Iyyar { 76c6e58c7eSRamesh Iyyar createRSAPrivateKeyFile(); 77c6e58c7eSRamesh Iyyar } 78c6e58c7eSRamesh Iyyar 79ffad1ef1SMarri Devender Rao // restore any existing certificates 80db029c95SKowalski, Kamil createCertificates(); 81ffad1ef1SMarri Devender Rao 82ffad1ef1SMarri Devender Rao // watch is not required for authority certificates 83ffad1ef1SMarri Devender Rao if (certType != AUTHORITY) 84ffad1ef1SMarri Devender Rao { 85ffad1ef1SMarri Devender Rao // watch for certificate file create/replace 86ffad1ef1SMarri Devender Rao certWatchPtr = std::make_unique< 87ffad1ef1SMarri Devender Rao Watch>(event, certInstallPath, [this]() { 88bf7c588cSMarri Devender Rao try 89bf7c588cSMarri Devender Rao { 90ffad1ef1SMarri Devender Rao // if certificate file existing update it 91db029c95SKowalski, Kamil if (!installedCerts.empty()) 92ffad1ef1SMarri Devender Rao { 93db5c6fc8SMarri Devender Rao log<level::INFO>("Inotify callback to update " 94db5c6fc8SMarri Devender Rao "certificate properties"); 95db029c95SKowalski, Kamil installedCerts[0]->populateProperties(); 96ffad1ef1SMarri Devender Rao } 97ffad1ef1SMarri Devender Rao else 98ffad1ef1SMarri Devender Rao { 99ffad1ef1SMarri Devender Rao log<level::INFO>( 100ffad1ef1SMarri Devender Rao "Inotify callback to create certificate object"); 101db029c95SKowalski, Kamil createCertificates(); 102ffad1ef1SMarri Devender Rao } 103bf7c588cSMarri Devender Rao } 104bf7c588cSMarri Devender Rao catch (const InternalFailure& e) 105bf7c588cSMarri Devender Rao { 106ffad1ef1SMarri Devender Rao commit<InternalFailure>(); 107bf7c588cSMarri Devender Rao } 108bf7c588cSMarri Devender Rao catch (const InvalidCertificate& e) 109bf7c588cSMarri Devender Rao { 110ffad1ef1SMarri Devender Rao commit<InvalidCertificate>(); 111bf7c588cSMarri Devender Rao } 112ffad1ef1SMarri Devender Rao }); 113bf7c588cSMarri Devender Rao } 114db029c95SKowalski, Kamil else 115db029c95SKowalski, Kamil { 116db5c6fc8SMarri Devender Rao try 117db5c6fc8SMarri Devender Rao { 118db5c6fc8SMarri Devender Rao const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem"; 119db5c6fc8SMarri Devender Rao if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath)) 120db029c95SKowalski, Kamil { 121db029c95SKowalski, Kamil log<level::NOTICE>( 122db029c95SKowalski, Kamil "Legacy certificate detected, will be installed from: ", 123db5c6fc8SMarri Devender Rao entry("SINGLE_CERTPATH=%s", singleCertPath.c_str())); 124db5c6fc8SMarri Devender Rao install(singleCertPath); 125db5c6fc8SMarri Devender Rao if (!fs::remove(singleCertPath)) 126db029c95SKowalski, Kamil { 127db029c95SKowalski, Kamil log<level::ERR>( 128db029c95SKowalski, Kamil "Unable to remove old certificate from: ", 129db5c6fc8SMarri Devender Rao entry("SINGLE_CERTPATH=%s", 130db5c6fc8SMarri Devender Rao singleCertPath.c_str())); 131db029c95SKowalski, Kamil elog<InternalFailure>(); 132db029c95SKowalski, Kamil } 133db029c95SKowalski, Kamil } 134db029c95SKowalski, Kamil } 135db5c6fc8SMarri Devender Rao catch (const std::exception& ex) 136db5c6fc8SMarri Devender Rao { 137db5c6fc8SMarri Devender Rao log<level::ERR>("Error in restoring legacy certificate", 138db5c6fc8SMarri Devender Rao entry("ERROR_STR=%s", ex.what())); 139db5c6fc8SMarri Devender Rao } 140db5c6fc8SMarri Devender Rao } 141db5c6fc8SMarri Devender Rao } 14271957992SPatrick Williams catch (const std::exception& ex) 143db5c6fc8SMarri Devender Rao { 144db5c6fc8SMarri Devender Rao log<level::ERR>("Error in certificate manager constructor", 145db5c6fc8SMarri Devender Rao entry("ERROR_STR=%s", ex.what())); 146db5c6fc8SMarri Devender Rao } 147dd74bd20SJayanth Othayoth } 148589159f2SJayanth Othayoth 14906a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath) 150cfbc8dc8SJayanth Othayoth { 1511396511dSMarri Devender Rao using NotAllowed = 1521396511dSMarri Devender Rao sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 1531396511dSMarri Devender Rao using Reason = xyz::openbmc_project::Common::NotAllowed::REASON; 154db029c95SKowalski, Kamil 155db029c95SKowalski, Kamil if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty()) 1561396511dSMarri Devender Rao { 1571396511dSMarri Devender Rao elog<NotAllowed>(Reason("Certificate already exist")); 1581396511dSMarri Devender Rao } 1593b07b77aSZbigniew Lukwinski else if (certType == phosphor::certs::AUTHORITY && 1603b07b77aSZbigniew Lukwinski installedCerts.size() >= AUTHORITY_CERTIFICATES_LIMIT) 1613b07b77aSZbigniew Lukwinski { 1623b07b77aSZbigniew Lukwinski elog<NotAllowed>(Reason("Certificates limit reached")); 1633b07b77aSZbigniew Lukwinski } 164ffad1ef1SMarri Devender Rao 1652f3563ccSZbigniew Lukwinski std::string certObjectPath; 1662f3563ccSZbigniew Lukwinski if (isCertificateUnique(filePath)) 1672f3563ccSZbigniew Lukwinski { 1682f3563ccSZbigniew Lukwinski certObjectPath = objectPath + '/' + std::to_string(certIdCounter); 169db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 1702f3563ccSZbigniew Lukwinski bus, certObjectPath, certType, certInstallPath, filePath, 1712f3563ccSZbigniew Lukwinski certWatchPtr, *this)); 1722f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 1732f3563ccSZbigniew Lukwinski certIdCounter++; 1742f3563ccSZbigniew Lukwinski } 1752f3563ccSZbigniew Lukwinski else 1762f3563ccSZbigniew Lukwinski { 1772f3563ccSZbigniew Lukwinski elog<NotAllowed>(Reason("Certificate already exist")); 1782f3563ccSZbigniew Lukwinski } 1792f3563ccSZbigniew Lukwinski 18006a69d7bSZbigniew Kurzynski return certObjectPath; 181589159f2SJayanth Othayoth } 182ae70b3daSDeepak Kodihalli 183a3bb38fbSZbigniew Kurzynski void Manager::deleteAll() 184ae70b3daSDeepak Kodihalli { 1856ceec40bSMarri Devender Rao // TODO: #Issue 4 when a certificate is deleted system auto generates 1866ceec40bSMarri Devender Rao // certificate file. At present we are not supporting creation of 1876ceec40bSMarri Devender Rao // certificate object for the auto-generated certificate file as 1886ceec40bSMarri Devender Rao // deletion if only applicable for REST server and Bmcweb does not allow 1896ceec40bSMarri Devender Rao // deletion of certificates 190db029c95SKowalski, Kamil installedCerts.clear(); 1912f3563ccSZbigniew Lukwinski storageUpdate(); 1922f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 193ae70b3daSDeepak Kodihalli } 194f4682712SMarri Devender Rao 1952f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate) 196a3bb38fbSZbigniew Kurzynski { 197a3bb38fbSZbigniew Kurzynski std::vector<std::unique_ptr<Certificate>>::iterator const& certIt = 198a3bb38fbSZbigniew Kurzynski std::find_if(installedCerts.begin(), installedCerts.end(), 1992f3563ccSZbigniew Lukwinski [certificate](std::unique_ptr<Certificate> const& cert) { 2002f3563ccSZbigniew Lukwinski return (cert.get() == certificate); 201a3bb38fbSZbigniew Kurzynski }); 202a3bb38fbSZbigniew Kurzynski if (certIt != installedCerts.end()) 203a3bb38fbSZbigniew Kurzynski { 204a3bb38fbSZbigniew Kurzynski installedCerts.erase(certIt); 2052f3563ccSZbigniew Lukwinski storageUpdate(); 2062f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 207a3bb38fbSZbigniew Kurzynski } 208a3bb38fbSZbigniew Kurzynski else 209a3bb38fbSZbigniew Kurzynski { 210a3bb38fbSZbigniew Kurzynski log<level::ERR>("Certificate does not exist", 2112f3563ccSZbigniew Lukwinski entry("ID=%s", certificate->getCertId().c_str())); 2122f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 2132f3563ccSZbigniew Lukwinski } 2142f3563ccSZbigniew Lukwinski } 2152f3563ccSZbigniew Lukwinski 2162f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate, 2172f3563ccSZbigniew Lukwinski const std::string& filePath) 2182f3563ccSZbigniew Lukwinski { 2192f3563ccSZbigniew Lukwinski if (isCertificateUnique(filePath, certificate)) 2202f3563ccSZbigniew Lukwinski { 2212f3563ccSZbigniew Lukwinski certificate->install(filePath); 2222f3563ccSZbigniew Lukwinski storageUpdate(); 2232f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 2242f3563ccSZbigniew Lukwinski } 2252f3563ccSZbigniew Lukwinski else 2262f3563ccSZbigniew Lukwinski { 22715cbbec2SZbigniew Lukwinski using NotAllowed = 22815cbbec2SZbigniew Lukwinski sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 22915cbbec2SZbigniew Lukwinski using Reason = xyz::openbmc_project::Common::NotAllowed::REASON; 23015cbbec2SZbigniew Lukwinski 23115cbbec2SZbigniew Lukwinski elog<NotAllowed>(Reason("Certificate already exist")); 232a3bb38fbSZbigniew Kurzynski } 233a3bb38fbSZbigniew Kurzynski } 234a3bb38fbSZbigniew Kurzynski 235f4682712SMarri Devender Rao std::string Manager::generateCSR( 236f4682712SMarri Devender Rao std::vector<std::string> alternativeNames, std::string challengePassword, 237f4682712SMarri Devender Rao std::string city, std::string commonName, std::string contactPerson, 238f4682712SMarri Devender Rao std::string country, std::string email, std::string givenName, 239f4682712SMarri Devender Rao std::string initials, int64_t keyBitLength, std::string keyCurveId, 240f4682712SMarri Devender Rao std::string keyPairAlgorithm, std::vector<std::string> keyUsage, 241f4682712SMarri Devender Rao std::string organization, std::string organizationalUnit, std::string state, 242f4682712SMarri Devender Rao std::string surname, std::string unstructuredName) 243f4682712SMarri Devender Rao { 244f4682712SMarri Devender Rao // We support only one CSR. 245f4682712SMarri Devender Rao csrPtr.reset(nullptr); 246f4682712SMarri Devender Rao auto pid = fork(); 247f4682712SMarri Devender Rao if (pid == -1) 248f4682712SMarri Devender Rao { 249f4682712SMarri Devender Rao log<level::ERR>("Error occurred during forking process"); 250f4682712SMarri Devender Rao report<InternalFailure>(); 251f4682712SMarri Devender Rao } 252f4682712SMarri Devender Rao else if (pid == 0) 253f4682712SMarri Devender Rao { 254f4682712SMarri Devender Rao try 255f4682712SMarri Devender Rao { 256f4682712SMarri Devender Rao generateCSRHelper(alternativeNames, challengePassword, city, 257f4682712SMarri Devender Rao commonName, contactPerson, country, email, 258f4682712SMarri Devender Rao givenName, initials, keyBitLength, keyCurveId, 259f4682712SMarri Devender Rao keyPairAlgorithm, keyUsage, organization, 260f4682712SMarri Devender Rao organizationalUnit, state, surname, 261f4682712SMarri Devender Rao unstructuredName); 262f4682712SMarri Devender Rao exit(EXIT_SUCCESS); 263f4682712SMarri Devender Rao } 264f4682712SMarri Devender Rao catch (const InternalFailure& e) 265f4682712SMarri Devender Rao { 266f4682712SMarri Devender Rao // commit the error reported in child process and exit 267f4682712SMarri Devender Rao // Callback method from SDEvent Loop looks for exit status 268f4682712SMarri Devender Rao exit(EXIT_FAILURE); 269f4682712SMarri Devender Rao commit<InternalFailure>(); 270f4682712SMarri Devender Rao } 271d2393f23SRamesh Iyyar catch (const InvalidArgument& e) 272d2393f23SRamesh Iyyar { 273d2393f23SRamesh Iyyar // commit the error reported in child process and exit 274d2393f23SRamesh Iyyar // Callback method from SDEvent Loop looks for exit status 275d2393f23SRamesh Iyyar exit(EXIT_FAILURE); 276d2393f23SRamesh Iyyar commit<InvalidArgument>(); 277d2393f23SRamesh Iyyar } 278f4682712SMarri Devender Rao } 279f4682712SMarri Devender Rao else 280f4682712SMarri Devender Rao { 281f4682712SMarri Devender Rao using namespace sdeventplus::source; 282f4682712SMarri Devender Rao Child::Callback callback = [this](Child& eventSource, 283f4682712SMarri Devender Rao const siginfo_t* si) { 284f4682712SMarri Devender Rao eventSource.set_enabled(Enabled::On); 285f4682712SMarri Devender Rao if (si->si_status != 0) 286f4682712SMarri Devender Rao { 287f4682712SMarri Devender Rao this->createCSRObject(Status::FAILURE); 288f4682712SMarri Devender Rao } 289f4682712SMarri Devender Rao else 290f4682712SMarri Devender Rao { 291f4682712SMarri Devender Rao this->createCSRObject(Status::SUCCESS); 292f4682712SMarri Devender Rao } 293f4682712SMarri Devender Rao }; 294f4682712SMarri Devender Rao try 295f4682712SMarri Devender Rao { 296f4682712SMarri Devender Rao sigset_t ss; 297f4682712SMarri Devender Rao if (sigemptyset(&ss) < 0) 298f4682712SMarri Devender Rao { 299f4682712SMarri Devender Rao log<level::ERR>("Unable to initialize signal set"); 300f4682712SMarri Devender Rao elog<InternalFailure>(); 301f4682712SMarri Devender Rao } 302f4682712SMarri Devender Rao if (sigaddset(&ss, SIGCHLD) < 0) 303f4682712SMarri Devender Rao { 304f4682712SMarri Devender Rao log<level::ERR>("Unable to add signal to signal set"); 305f4682712SMarri Devender Rao elog<InternalFailure>(); 306f4682712SMarri Devender Rao } 307f4682712SMarri Devender Rao 308f4682712SMarri Devender Rao // Block SIGCHLD first, so that the event loop can handle it 309*cfb5802aSNan Zhou if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0) 310f4682712SMarri Devender Rao { 311f4682712SMarri Devender Rao log<level::ERR>("Unable to block signal"); 312f4682712SMarri Devender Rao elog<InternalFailure>(); 313f4682712SMarri Devender Rao } 314f4682712SMarri Devender Rao if (childPtr) 315f4682712SMarri Devender Rao { 316f4682712SMarri Devender Rao childPtr.reset(); 317f4682712SMarri Devender Rao } 318f4682712SMarri Devender Rao childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED, 319f4682712SMarri Devender Rao std::move(callback)); 320f4682712SMarri Devender Rao } 321f4682712SMarri Devender Rao catch (const InternalFailure& e) 322f4682712SMarri Devender Rao { 323f4682712SMarri Devender Rao commit<InternalFailure>(); 324f4682712SMarri Devender Rao } 325f4682712SMarri Devender Rao } 326f4682712SMarri Devender Rao auto csrObjectPath = objectPath + '/' + "csr"; 327f4682712SMarri Devender Rao return csrObjectPath; 328f4682712SMarri Devender Rao } 329f4682712SMarri Devender Rao 330db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates() 331ffad1ef1SMarri Devender Rao { 332db029c95SKowalski, Kamil return installedCerts; 333ffad1ef1SMarri Devender Rao } 334ffad1ef1SMarri Devender Rao 335f4682712SMarri Devender Rao void Manager::generateCSRHelper( 336f4682712SMarri Devender Rao std::vector<std::string> alternativeNames, std::string challengePassword, 337f4682712SMarri Devender Rao std::string city, std::string commonName, std::string contactPerson, 338f4682712SMarri Devender Rao std::string country, std::string email, std::string givenName, 339f4682712SMarri Devender Rao std::string initials, int64_t keyBitLength, std::string keyCurveId, 340f4682712SMarri Devender Rao std::string keyPairAlgorithm, std::vector<std::string> keyUsage, 341f4682712SMarri Devender Rao std::string organization, std::string organizationalUnit, std::string state, 342f4682712SMarri Devender Rao std::string surname, std::string unstructuredName) 343f4682712SMarri Devender Rao { 344f4682712SMarri Devender Rao int ret = 0; 345f4682712SMarri Devender Rao 346f4682712SMarri Devender Rao // set version of x509 req 347f4682712SMarri Devender Rao int nVersion = 1; 348f4682712SMarri Devender Rao // TODO: Issue#6 need to make version number configurable 349f4682712SMarri Devender Rao X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free); 350f4682712SMarri Devender Rao ret = X509_REQ_set_version(x509Req.get(), nVersion); 351f4682712SMarri Devender Rao if (ret == 0) 352f4682712SMarri Devender Rao { 353bf3cf751SNan Zhou log<level::ERR>("Error occurred during X509_REQ_set_version call"); 354f4682712SMarri Devender Rao elog<InternalFailure>(); 355f4682712SMarri Devender Rao } 356f4682712SMarri Devender Rao 357f4682712SMarri Devender Rao // set subject of x509 req 358f4682712SMarri Devender Rao X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get()); 359f4682712SMarri Devender Rao 360f4682712SMarri Devender Rao if (!alternativeNames.empty()) 361f4682712SMarri Devender Rao { 362f4682712SMarri Devender Rao for (auto& name : alternativeNames) 363f4682712SMarri Devender Rao { 364f4682712SMarri Devender Rao addEntry(x509Name, "subjectAltName", name); 365f4682712SMarri Devender Rao } 366f4682712SMarri Devender Rao } 367f4682712SMarri Devender Rao addEntry(x509Name, "challengePassword", challengePassword); 368f4682712SMarri Devender Rao addEntry(x509Name, "L", city); 369f4682712SMarri Devender Rao addEntry(x509Name, "CN", commonName); 370f4682712SMarri Devender Rao addEntry(x509Name, "name", contactPerson); 371f4682712SMarri Devender Rao addEntry(x509Name, "C", country); 372f4682712SMarri Devender Rao addEntry(x509Name, "emailAddress", email); 373f4682712SMarri Devender Rao addEntry(x509Name, "GN", givenName); 374f4682712SMarri Devender Rao addEntry(x509Name, "initials", initials); 375f4682712SMarri Devender Rao addEntry(x509Name, "algorithm", keyPairAlgorithm); 376f4682712SMarri Devender Rao if (!keyUsage.empty()) 377f4682712SMarri Devender Rao { 378f4682712SMarri Devender Rao for (auto& usage : keyUsage) 379f4682712SMarri Devender Rao { 3807641105dSMarri Devender Rao if (isExtendedKeyUsage(usage)) 3817641105dSMarri Devender Rao { 3827641105dSMarri Devender Rao addEntry(x509Name, "extendedKeyUsage", usage); 3837641105dSMarri Devender Rao } 3847641105dSMarri Devender Rao else 3857641105dSMarri Devender Rao { 386f4682712SMarri Devender Rao addEntry(x509Name, "keyUsage", usage); 387f4682712SMarri Devender Rao } 388f4682712SMarri Devender Rao } 3897641105dSMarri Devender Rao } 390f4682712SMarri Devender Rao addEntry(x509Name, "O", organization); 391dc91fb61SJayanth Othayoth addEntry(x509Name, "OU", organizationalUnit); 392f4682712SMarri Devender Rao addEntry(x509Name, "ST", state); 393f4682712SMarri Devender Rao addEntry(x509Name, "SN", surname); 394f4682712SMarri Devender Rao addEntry(x509Name, "unstructuredName", unstructuredName); 395f4682712SMarri Devender Rao 3968a09b52aSRamesh Iyyar EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free); 3978a09b52aSRamesh Iyyar 3988a09b52aSRamesh Iyyar log<level::INFO>("Given Key pair algorithm", 3998a09b52aSRamesh Iyyar entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str())); 4008a09b52aSRamesh Iyyar 4018a09b52aSRamesh Iyyar // Used EC algorithm as default if user did not give algorithm type. 4028a09b52aSRamesh Iyyar if (keyPairAlgorithm == "RSA") 403c6e58c7eSRamesh Iyyar pKey = getRSAKeyPair(keyBitLength); 4048a09b52aSRamesh Iyyar else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty())) 405c6e58c7eSRamesh Iyyar pKey = generateECKeyPair(keyCurveId); 4068a09b52aSRamesh Iyyar else 4078a09b52aSRamesh Iyyar { 4088a09b52aSRamesh Iyyar log<level::ERR>("Given Key pair algorithm is not supported. Supporting " 4098a09b52aSRamesh Iyyar "RSA and EC only"); 4108a09b52aSRamesh Iyyar elog<InvalidArgument>( 4118a09b52aSRamesh Iyyar Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"), 4128a09b52aSRamesh Iyyar Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str())); 4138a09b52aSRamesh Iyyar } 4148a09b52aSRamesh Iyyar 4158a09b52aSRamesh Iyyar ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get()); 4168a09b52aSRamesh Iyyar if (ret == 0) 4178a09b52aSRamesh Iyyar { 418bf3cf751SNan Zhou log<level::ERR>("Error occurred while setting Public key"); 4198a09b52aSRamesh Iyyar elog<InternalFailure>(); 4208a09b52aSRamesh Iyyar } 4218a09b52aSRamesh Iyyar 4228a09b52aSRamesh Iyyar // Write private key to file 423c6e58c7eSRamesh Iyyar writePrivateKey(pKey, PRIV_KEY_FILE_NAME); 424f4682712SMarri Devender Rao 425f4682712SMarri Devender Rao // set sign key of x509 req 426f4682712SMarri Devender Rao ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256()); 4278a09b52aSRamesh Iyyar if (ret == 0) 428f4682712SMarri Devender Rao { 429bf3cf751SNan Zhou log<level::ERR>("Error occurred while signing key of x509"); 430f4682712SMarri Devender Rao elog<InternalFailure>(); 431f4682712SMarri Devender Rao } 4328a09b52aSRamesh Iyyar 433f4682712SMarri Devender Rao log<level::INFO>("Writing CSR to file"); 434c6e58c7eSRamesh Iyyar fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME; 435c6e58c7eSRamesh Iyyar writeCSR(csrFilePath.string(), x509Req); 436f4682712SMarri Devender Rao } 437f4682712SMarri Devender Rao 4387641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage) 4397641105dSMarri Devender Rao { 4407641105dSMarri Devender Rao const static std::array<const char*, 6> usageList = { 4417641105dSMarri Devender Rao "ServerAuthentication", "ClientAuthentication", "OCSPSigning", 4427641105dSMarri Devender Rao "Timestamping", "CodeSigning", "EmailProtection"}; 4437641105dSMarri Devender Rao auto it = std::find_if( 4447641105dSMarri Devender Rao usageList.begin(), usageList.end(), 4457641105dSMarri Devender Rao [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); }); 4467641105dSMarri Devender Rao return it != usageList.end(); 4477641105dSMarri Devender Rao } 4488a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength) 449f4682712SMarri Devender Rao { 4508a09b52aSRamesh Iyyar int64_t keyBitLen = keyBitLength; 451f4682712SMarri Devender Rao // set keybit length to default value if not set 4528a09b52aSRamesh Iyyar if (keyBitLen <= 0) 453f4682712SMarri Devender Rao { 4548a09b52aSRamesh Iyyar constexpr auto DEFAULT_KEYBITLENGTH = 2048; 4558a09b52aSRamesh Iyyar log<level::INFO>( 4568a09b52aSRamesh Iyyar "KeyBitLength is not given.Hence, using default KeyBitLength", 4578a09b52aSRamesh Iyyar entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH)); 4588a09b52aSRamesh Iyyar keyBitLen = DEFAULT_KEYBITLENGTH; 459f4682712SMarri Devender Rao } 46026fb83efSPatrick Williams 46126fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 46226fb83efSPatrick Williams 46326fb83efSPatrick Williams // generate rsa key 46426fb83efSPatrick Williams BIGNUM_Ptr bne(BN_new(), ::BN_free); 46526fb83efSPatrick Williams auto ret = BN_set_word(bne.get(), RSA_F4); 46626fb83efSPatrick Williams if (ret == 0) 46726fb83efSPatrick Williams { 468bf3cf751SNan Zhou log<level::ERR>("Error occurred during BN_set_word call"); 46926fb83efSPatrick Williams elog<InternalFailure>(); 47026fb83efSPatrick Williams } 47126fb83efSPatrick Williams 472f4682712SMarri Devender Rao RSA* rsa = RSA_new(); 473*cfb5802aSNan Zhou ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), nullptr); 474f4682712SMarri Devender Rao if (ret != 1) 475f4682712SMarri Devender Rao { 476f4682712SMarri Devender Rao free(rsa); 477bf3cf751SNan Zhou log<level::ERR>("Error occurred during RSA_generate_key_ex call", 4788a09b52aSRamesh Iyyar entry("KEYBITLENGTH=%PRIu64", keyBitLen)); 479f4682712SMarri Devender Rao elog<InternalFailure>(); 480f4682712SMarri Devender Rao } 481f4682712SMarri Devender Rao 482f4682712SMarri Devender Rao // set public key of x509 req 483f4682712SMarri Devender Rao EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 4848a09b52aSRamesh Iyyar ret = EVP_PKEY_assign_RSA(pKey.get(), rsa); 485f4682712SMarri Devender Rao if (ret == 0) 486f4682712SMarri Devender Rao { 4878a09b52aSRamesh Iyyar free(rsa); 488bf3cf751SNan Zhou log<level::ERR>("Error occurred during assign rsa key into EVP"); 489f4682712SMarri Devender Rao elog<InternalFailure>(); 490f4682712SMarri Devender Rao } 491f4682712SMarri Devender Rao 4928a09b52aSRamesh Iyyar return pKey; 49326fb83efSPatrick Williams 49426fb83efSPatrick Williams #else 49526fb83efSPatrick Williams auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 49626fb83efSPatrick Williams EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free); 49726fb83efSPatrick Williams if (!ctx) 49826fb83efSPatrick Williams { 499bf3cf751SNan Zhou log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm"); 50026fb83efSPatrick Williams elog<InternalFailure>(); 50126fb83efSPatrick Williams } 50226fb83efSPatrick Williams 50326fb83efSPatrick Williams if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) || 50426fb83efSPatrick Williams (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0)) 50526fb83efSPatrick Williams 50626fb83efSPatrick Williams { 507bf3cf751SNan Zhou log<level::ERR>("Error occurred initializing keygen context"); 50826fb83efSPatrick Williams elog<InternalFailure>(); 50926fb83efSPatrick Williams } 51026fb83efSPatrick Williams 51126fb83efSPatrick Williams EVP_PKEY* pKey = nullptr; 51226fb83efSPatrick Williams if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 51326fb83efSPatrick Williams { 514bf3cf751SNan Zhou log<level::ERR>("Error occurred during generate EC key"); 51526fb83efSPatrick Williams elog<InternalFailure>(); 51626fb83efSPatrick Williams } 51726fb83efSPatrick Williams 51826fb83efSPatrick Williams return {pKey, &::EVP_PKEY_free}; 51926fb83efSPatrick Williams #endif 5208a09b52aSRamesh Iyyar } 5218a09b52aSRamesh Iyyar 5228a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId) 5238a09b52aSRamesh Iyyar { 5248a09b52aSRamesh Iyyar std::string curId(curveId); 5258a09b52aSRamesh Iyyar 5268a09b52aSRamesh Iyyar if (curId.empty()) 5278a09b52aSRamesh Iyyar { 5288a09b52aSRamesh Iyyar // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349 5298a09b52aSRamesh Iyyar constexpr auto DEFAULT_KEYCURVEID = "secp224r1"; 5308a09b52aSRamesh Iyyar log<level::INFO>( 5318a09b52aSRamesh Iyyar "KeyCurveId is not given. Hence using default curve id", 5328a09b52aSRamesh Iyyar entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID)); 5338a09b52aSRamesh Iyyar curId = DEFAULT_KEYCURVEID; 5348a09b52aSRamesh Iyyar } 5358a09b52aSRamesh Iyyar 5368a09b52aSRamesh Iyyar int ecGrp = OBJ_txt2nid(curId.c_str()); 5378a09b52aSRamesh Iyyar if (ecGrp == NID_undef) 5388a09b52aSRamesh Iyyar { 5398a09b52aSRamesh Iyyar log<level::ERR>( 540bf3cf751SNan Zhou "Error occurred during convert the curve id string format into NID", 5418a09b52aSRamesh Iyyar entry("KEYCURVEID=%s", curId.c_str())); 5428a09b52aSRamesh Iyyar elog<InternalFailure>(); 5438a09b52aSRamesh Iyyar } 5448a09b52aSRamesh Iyyar 54526fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 54626fb83efSPatrick Williams 5478a09b52aSRamesh Iyyar EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp); 5488a09b52aSRamesh Iyyar 549*cfb5802aSNan Zhou if (ecKey == nullptr) 5508a09b52aSRamesh Iyyar { 5518a09b52aSRamesh Iyyar log<level::ERR>( 552bf3cf751SNan Zhou "Error occurred during create the EC_Key object from NID", 5538a09b52aSRamesh Iyyar entry("ECGROUP=%d", ecGrp)); 5548a09b52aSRamesh Iyyar elog<InternalFailure>(); 5558a09b52aSRamesh Iyyar } 5568a09b52aSRamesh Iyyar 5578a09b52aSRamesh Iyyar // If you want to save a key and later load it with 5588a09b52aSRamesh Iyyar // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE 5598a09b52aSRamesh Iyyar // flag on the key. 5608a09b52aSRamesh Iyyar EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE); 5618a09b52aSRamesh Iyyar 5628a09b52aSRamesh Iyyar int ret = EC_KEY_generate_key(ecKey); 5638a09b52aSRamesh Iyyar 5648a09b52aSRamesh Iyyar if (ret == 0) 5658a09b52aSRamesh Iyyar { 5668a09b52aSRamesh Iyyar EC_KEY_free(ecKey); 567bf3cf751SNan Zhou log<level::ERR>("Error occurred during generate EC key"); 5688a09b52aSRamesh Iyyar elog<InternalFailure>(); 5698a09b52aSRamesh Iyyar } 5708a09b52aSRamesh Iyyar 5718a09b52aSRamesh Iyyar EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 5728a09b52aSRamesh Iyyar ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey); 5738a09b52aSRamesh Iyyar if (ret == 0) 5748a09b52aSRamesh Iyyar { 5758a09b52aSRamesh Iyyar EC_KEY_free(ecKey); 576bf3cf751SNan Zhou log<level::ERR>("Error occurred during assign EC Key into EVP"); 5778a09b52aSRamesh Iyyar elog<InternalFailure>(); 5788a09b52aSRamesh Iyyar } 5798a09b52aSRamesh Iyyar 5808a09b52aSRamesh Iyyar return pKey; 58126fb83efSPatrick Williams 58226fb83efSPatrick Williams #else 58326fb83efSPatrick Williams auto holder_of_key = [](EVP_PKEY* key) { 58426fb83efSPatrick Williams return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{ 58526fb83efSPatrick Williams key, &::EVP_PKEY_free}; 58626fb83efSPatrick Williams }; 58726fb83efSPatrick Williams 58826fb83efSPatrick Williams // Create context to set up curve parameters. 58926fb83efSPatrick Williams auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 59026fb83efSPatrick Williams EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free); 59126fb83efSPatrick Williams if (!ctx) 59226fb83efSPatrick Williams { 593bf3cf751SNan Zhou log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params"); 59426fb83efSPatrick Williams elog<InternalFailure>(); 59526fb83efSPatrick Williams } 59626fb83efSPatrick Williams 59726fb83efSPatrick Williams // Set up curve parameters. 59826fb83efSPatrick Williams EVP_PKEY* params = nullptr; 59926fb83efSPatrick Williams 60026fb83efSPatrick Williams if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) || 60126fb83efSPatrick Williams (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <= 60226fb83efSPatrick Williams 0) || 60326fb83efSPatrick Williams (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) || 60426fb83efSPatrick Williams (EVP_PKEY_paramgen(ctx.get(), ¶ms) <= 0)) 60526fb83efSPatrick Williams { 606bf3cf751SNan Zhou log<level::ERR>("Error occurred setting curve parameters"); 60726fb83efSPatrick Williams elog<InternalFailure>(); 60826fb83efSPatrick Williams } 60926fb83efSPatrick Williams 61026fb83efSPatrick Williams // Move parameters to RAII holder. 61126fb83efSPatrick Williams auto pparms = holder_of_key(params); 61226fb83efSPatrick Williams 61326fb83efSPatrick Williams // Create new context for key. 61426fb83efSPatrick Williams ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr)); 61526fb83efSPatrick Williams 61626fb83efSPatrick Williams if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0)) 61726fb83efSPatrick Williams { 618bf3cf751SNan Zhou log<level::ERR>("Error occurred initializing keygen context"); 61926fb83efSPatrick Williams elog<InternalFailure>(); 62026fb83efSPatrick Williams } 62126fb83efSPatrick Williams 62226fb83efSPatrick Williams EVP_PKEY* pKey = nullptr; 62326fb83efSPatrick Williams if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 62426fb83efSPatrick Williams { 625bf3cf751SNan Zhou log<level::ERR>("Error occurred during generate EC key"); 62626fb83efSPatrick Williams elog<InternalFailure>(); 62726fb83efSPatrick Williams } 62826fb83efSPatrick Williams 62926fb83efSPatrick Williams return holder_of_key(pKey); 63026fb83efSPatrick Williams #endif 6318a09b52aSRamesh Iyyar } 6328a09b52aSRamesh Iyyar 633c6e58c7eSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey, 634c6e58c7eSRamesh Iyyar const std::string& privKeyFileName) 6358a09b52aSRamesh Iyyar { 6368a09b52aSRamesh Iyyar log<level::INFO>("Writing private key to file"); 637f4682712SMarri Devender Rao // write private key to file 638c6e58c7eSRamesh Iyyar fs::path privKeyPath = certParentInstallPath / privKeyFileName; 639f4682712SMarri Devender Rao 640f4682712SMarri Devender Rao FILE* fp = std::fopen(privKeyPath.c_str(), "w"); 641*cfb5802aSNan Zhou if (fp == nullptr) 642f4682712SMarri Devender Rao { 643bf3cf751SNan Zhou log<level::ERR>("Error occurred creating private key file"); 644f4682712SMarri Devender Rao elog<InternalFailure>(); 645f4682712SMarri Devender Rao } 646*cfb5802aSNan Zhou int ret = 647*cfb5802aSNan Zhou PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr); 648f4682712SMarri Devender Rao std::fclose(fp); 649f4682712SMarri Devender Rao if (ret == 0) 650f4682712SMarri Devender Rao { 651bf3cf751SNan Zhou log<level::ERR>("Error occurred while writing private key to file"); 652f4682712SMarri Devender Rao elog<InternalFailure>(); 653f4682712SMarri Devender Rao } 654f4682712SMarri Devender Rao } 655f4682712SMarri Devender Rao 656f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field, 657f4682712SMarri Devender Rao const std::string& bytes) 658f4682712SMarri Devender Rao { 659f4682712SMarri Devender Rao if (bytes.empty()) 660f4682712SMarri Devender Rao { 661f4682712SMarri Devender Rao return; 662f4682712SMarri Devender Rao } 663f4682712SMarri Devender Rao int ret = X509_NAME_add_entry_by_txt( 664f4682712SMarri Devender Rao x509Name, field, MBSTRING_ASC, 665f4682712SMarri Devender Rao reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0); 666f4682712SMarri Devender Rao if (ret != 1) 667f4682712SMarri Devender Rao { 668f4682712SMarri Devender Rao log<level::ERR>("Unable to set entry", entry("FIELD=%s", field), 669f4682712SMarri Devender Rao entry("VALUE=%s", bytes.c_str())); 670f4682712SMarri Devender Rao elog<InternalFailure>(); 671f4682712SMarri Devender Rao } 672f4682712SMarri Devender Rao } 673f4682712SMarri Devender Rao 674f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status) 675f4682712SMarri Devender Rao { 676f4682712SMarri Devender Rao if (csrPtr) 677f4682712SMarri Devender Rao { 678f4682712SMarri Devender Rao csrPtr.reset(nullptr); 679f4682712SMarri Devender Rao } 680f4682712SMarri Devender Rao auto csrObjectPath = objectPath + '/' + "csr"; 681f4682712SMarri Devender Rao csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(), 682f4682712SMarri Devender Rao certInstallPath.c_str(), status); 683f4682712SMarri Devender Rao } 684f4682712SMarri Devender Rao 685f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req) 686f4682712SMarri Devender Rao { 687f4682712SMarri Devender Rao if (fs::exists(filePath)) 688f4682712SMarri Devender Rao { 689f4682712SMarri Devender Rao log<level::INFO>("Removing the existing file", 690f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 691f4682712SMarri Devender Rao if (!fs::remove(filePath.c_str())) 692f4682712SMarri Devender Rao { 693f4682712SMarri Devender Rao log<level::ERR>("Unable to remove the file", 694f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 695f4682712SMarri Devender Rao elog<InternalFailure>(); 696f4682712SMarri Devender Rao } 697f4682712SMarri Devender Rao } 698f4682712SMarri Devender Rao 699*cfb5802aSNan Zhou FILE* fp = nullptr; 700f4682712SMarri Devender Rao 701*cfb5802aSNan Zhou if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr) 702f4682712SMarri Devender Rao { 703f4682712SMarri Devender Rao log<level::ERR>("Error opening the file to write the CSR", 704f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 705f4682712SMarri Devender Rao elog<InternalFailure>(); 706f4682712SMarri Devender Rao } 707f4682712SMarri Devender Rao 708f4682712SMarri Devender Rao int rc = PEM_write_X509_REQ(fp, x509Req.get()); 709f4682712SMarri Devender Rao if (!rc) 710f4682712SMarri Devender Rao { 711f4682712SMarri Devender Rao log<level::ERR>("PEM write routine failed", 712f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 713f4682712SMarri Devender Rao std::fclose(fp); 714f4682712SMarri Devender Rao elog<InternalFailure>(); 715f4682712SMarri Devender Rao } 716f4682712SMarri Devender Rao std::fclose(fp); 717f4682712SMarri Devender Rao } 718f4682712SMarri Devender Rao 719db029c95SKowalski, Kamil void Manager::createCertificates() 720db029c95SKowalski, Kamil { 721db029c95SKowalski, Kamil auto certObjectPath = objectPath + '/'; 722db029c95SKowalski, Kamil 723db029c95SKowalski, Kamil if (certType == phosphor::certs::AUTHORITY) 724db029c95SKowalski, Kamil { 725fe590c4eSZbigniew Lukwinski // Check whether install path is a directory. 726db029c95SKowalski, Kamil if (!fs::is_directory(certInstallPath)) 727db029c95SKowalski, Kamil { 728db029c95SKowalski, Kamil log<level::ERR>("Certificate installation path exists and it is " 729db029c95SKowalski, Kamil "not a directory"); 730db029c95SKowalski, Kamil elog<InternalFailure>(); 731db029c95SKowalski, Kamil return; 732db029c95SKowalski, Kamil } 733db029c95SKowalski, Kamil 734db029c95SKowalski, Kamil for (auto& path : fs::directory_iterator(certInstallPath)) 735ffad1ef1SMarri Devender Rao { 736ffad1ef1SMarri Devender Rao try 737ffad1ef1SMarri Devender Rao { 7382f3563ccSZbigniew Lukwinski // Assume here any regular file located in certificate directory 7392f3563ccSZbigniew Lukwinski // contains certificates body. Do not want to use soft links 7402f3563ccSZbigniew Lukwinski // would add value. 7412f3563ccSZbigniew Lukwinski if (fs::is_regular_file(path)) 7422f3563ccSZbigniew Lukwinski { 743db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 744db029c95SKowalski, Kamil bus, certObjectPath + std::to_string(certIdCounter++), 7452f3563ccSZbigniew Lukwinski certType, certInstallPath, path.path(), certWatchPtr, 7462f3563ccSZbigniew Lukwinski *this)); 7472f3563ccSZbigniew Lukwinski } 748ffad1ef1SMarri Devender Rao } 749ffad1ef1SMarri Devender Rao catch (const InternalFailure& e) 750ffad1ef1SMarri Devender Rao { 751ffad1ef1SMarri Devender Rao report<InternalFailure>(); 752ffad1ef1SMarri Devender Rao } 753ffad1ef1SMarri Devender Rao catch (const InvalidCertificate& e) 754ffad1ef1SMarri Devender Rao { 755ffad1ef1SMarri Devender Rao report<InvalidCertificate>( 756ffad1ef1SMarri Devender Rao Reason("Existing certificate file is corrupted")); 757ffad1ef1SMarri Devender Rao } 758ffad1ef1SMarri Devender Rao } 759db029c95SKowalski, Kamil } 760db029c95SKowalski, Kamil else if (fs::exists(certInstallPath)) 761db029c95SKowalski, Kamil { 762db029c95SKowalski, Kamil try 763db029c95SKowalski, Kamil { 764db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 7652f3563ccSZbigniew Lukwinski bus, certObjectPath + '1', certType, certInstallPath, 7662f3563ccSZbigniew Lukwinski certInstallPath, certWatchPtr, *this)); 767db029c95SKowalski, Kamil } 768db029c95SKowalski, Kamil catch (const InternalFailure& e) 769db029c95SKowalski, Kamil { 770db029c95SKowalski, Kamil report<InternalFailure>(); 771db029c95SKowalski, Kamil } 772db029c95SKowalski, Kamil catch (const InvalidCertificate& e) 773db029c95SKowalski, Kamil { 774db029c95SKowalski, Kamil report<InvalidCertificate>( 775db029c95SKowalski, Kamil Reason("Existing certificate file is corrupted")); 776db029c95SKowalski, Kamil } 777db029c95SKowalski, Kamil } 778db029c95SKowalski, Kamil } 779c6e58c7eSRamesh Iyyar 780c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile() 781c6e58c7eSRamesh Iyyar { 782c6e58c7eSRamesh Iyyar fs::path rsaPrivateKeyFileName = 783c6e58c7eSRamesh Iyyar certParentInstallPath / RSA_PRIV_KEY_FILE_NAME; 784c6e58c7eSRamesh Iyyar 785c6e58c7eSRamesh Iyyar try 786c6e58c7eSRamesh Iyyar { 787c6e58c7eSRamesh Iyyar if (!fs::exists(rsaPrivateKeyFileName)) 788c6e58c7eSRamesh Iyyar { 789c6e58c7eSRamesh Iyyar writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH), 790c6e58c7eSRamesh Iyyar RSA_PRIV_KEY_FILE_NAME); 791c6e58c7eSRamesh Iyyar } 792c6e58c7eSRamesh Iyyar } 793c6e58c7eSRamesh Iyyar catch (const InternalFailure& e) 794c6e58c7eSRamesh Iyyar { 795c6e58c7eSRamesh Iyyar report<InternalFailure>(); 796c6e58c7eSRamesh Iyyar } 797c6e58c7eSRamesh Iyyar } 798c6e58c7eSRamesh Iyyar 799c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength) 800c6e58c7eSRamesh Iyyar { 801c6e58c7eSRamesh Iyyar if (keyBitLength != SUPPORTED_KEYBITLENGTH) 802c6e58c7eSRamesh Iyyar { 803c6e58c7eSRamesh Iyyar log<level::ERR>( 804c6e58c7eSRamesh Iyyar "Given Key bit length is not supported", 805c6e58c7eSRamesh Iyyar entry("GIVENKEYBITLENGTH=%d", keyBitLength), 806c6e58c7eSRamesh Iyyar entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH)); 807c6e58c7eSRamesh Iyyar elog<InvalidArgument>( 808c6e58c7eSRamesh Iyyar Argument::ARGUMENT_NAME("KEYBITLENGTH"), 809c6e58c7eSRamesh Iyyar Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str())); 810c6e58c7eSRamesh Iyyar } 811c6e58c7eSRamesh Iyyar fs::path rsaPrivateKeyFileName = 812c6e58c7eSRamesh Iyyar certParentInstallPath / RSA_PRIV_KEY_FILE_NAME; 813c6e58c7eSRamesh Iyyar 814c6e58c7eSRamesh Iyyar FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r"); 815c6e58c7eSRamesh Iyyar if (!privateKeyFile) 816c6e58c7eSRamesh Iyyar { 817c6e58c7eSRamesh Iyyar log<level::ERR>("Unable to open RSA private key file to read", 818c6e58c7eSRamesh Iyyar entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()), 819c6e58c7eSRamesh Iyyar entry("ERRORREASON=%s", strerror(errno))); 820c6e58c7eSRamesh Iyyar elog<InternalFailure>(); 821c6e58c7eSRamesh Iyyar } 822c6e58c7eSRamesh Iyyar 823c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr privateKey( 824c6e58c7eSRamesh Iyyar PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr), 825c6e58c7eSRamesh Iyyar ::EVP_PKEY_free); 826c6e58c7eSRamesh Iyyar std::fclose(privateKeyFile); 827c6e58c7eSRamesh Iyyar 828c6e58c7eSRamesh Iyyar if (!privateKey) 829c6e58c7eSRamesh Iyyar { 830bf3cf751SNan Zhou log<level::ERR>("Error occurred during PEM_read_PrivateKey call"); 831c6e58c7eSRamesh Iyyar elog<InternalFailure>(); 832c6e58c7eSRamesh Iyyar } 833c6e58c7eSRamesh Iyyar return privateKey; 834c6e58c7eSRamesh Iyyar } 8352f3563ccSZbigniew Lukwinski 8362f3563ccSZbigniew Lukwinski void Manager::storageUpdate() 8372f3563ccSZbigniew Lukwinski { 8382f3563ccSZbigniew Lukwinski if (certType == phosphor::certs::AUTHORITY) 8392f3563ccSZbigniew Lukwinski { 8402f3563ccSZbigniew Lukwinski // Remove symbolic links in the certificate directory 8412f3563ccSZbigniew Lukwinski for (auto& certPath : fs::directory_iterator(certInstallPath)) 8422f3563ccSZbigniew Lukwinski { 8432f3563ccSZbigniew Lukwinski try 8442f3563ccSZbigniew Lukwinski { 8452f3563ccSZbigniew Lukwinski if (fs::is_symlink(certPath)) 8462f3563ccSZbigniew Lukwinski { 8472f3563ccSZbigniew Lukwinski fs::remove(certPath); 8482f3563ccSZbigniew Lukwinski } 8492f3563ccSZbigniew Lukwinski } 8502f3563ccSZbigniew Lukwinski catch (const std::exception& e) 8512f3563ccSZbigniew Lukwinski { 8522f3563ccSZbigniew Lukwinski log<level::ERR>( 8532f3563ccSZbigniew Lukwinski "Failed to remove symlink for certificate", 8542f3563ccSZbigniew Lukwinski entry("ERR=%s", e.what()), 8552f3563ccSZbigniew Lukwinski entry("SYMLINK=%s", certPath.path().string().c_str())); 8562f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 8572f3563ccSZbigniew Lukwinski } 8582f3563ccSZbigniew Lukwinski } 8592f3563ccSZbigniew Lukwinski } 8602f3563ccSZbigniew Lukwinski 8612f3563ccSZbigniew Lukwinski for (const auto& cert : installedCerts) 8622f3563ccSZbigniew Lukwinski { 8632f3563ccSZbigniew Lukwinski cert->storageUpdate(); 8642f3563ccSZbigniew Lukwinski } 8652f3563ccSZbigniew Lukwinski } 8662f3563ccSZbigniew Lukwinski 8672f3563ccSZbigniew Lukwinski void Manager::reloadOrReset(const UnitsToRestart& unit) 8682f3563ccSZbigniew Lukwinski { 8692f3563ccSZbigniew Lukwinski if (!unit.empty()) 8702f3563ccSZbigniew Lukwinski { 8712f3563ccSZbigniew Lukwinski try 8722f3563ccSZbigniew Lukwinski { 8732f3563ccSZbigniew Lukwinski constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 8742f3563ccSZbigniew Lukwinski constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 8752f3563ccSZbigniew Lukwinski constexpr auto SYSTEMD_INTERFACE = 8762f3563ccSZbigniew Lukwinski "org.freedesktop.systemd1.Manager"; 8772f3563ccSZbigniew Lukwinski 8782f3563ccSZbigniew Lukwinski auto method = 8792f3563ccSZbigniew Lukwinski bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, 8802f3563ccSZbigniew Lukwinski SYSTEMD_INTERFACE, "ReloadOrRestartUnit"); 8812f3563ccSZbigniew Lukwinski method.append(unit, "replace"); 8822f3563ccSZbigniew Lukwinski bus.call_noreply(method); 8832f3563ccSZbigniew Lukwinski } 884ca128117SPatrick Williams catch (const sdbusplus::exception::exception& e) 8852f3563ccSZbigniew Lukwinski { 8862f3563ccSZbigniew Lukwinski log<level::ERR>("Failed to reload or restart service", 8872f3563ccSZbigniew Lukwinski entry("ERR=%s", e.what()), 8882f3563ccSZbigniew Lukwinski entry("UNIT=%s", unit.c_str())); 8892f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 8902f3563ccSZbigniew Lukwinski } 8912f3563ccSZbigniew Lukwinski } 8922f3563ccSZbigniew Lukwinski } 8932f3563ccSZbigniew Lukwinski 8942f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath, 8952f3563ccSZbigniew Lukwinski const Certificate* const certToDrop) 8962f3563ccSZbigniew Lukwinski { 8972f3563ccSZbigniew Lukwinski if (std::any_of( 8982f3563ccSZbigniew Lukwinski installedCerts.begin(), installedCerts.end(), 8992f3563ccSZbigniew Lukwinski [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) { 9002f3563ccSZbigniew Lukwinski return cert.get() != certToDrop && cert->isSame(filePath); 9012f3563ccSZbigniew Lukwinski })) 9022f3563ccSZbigniew Lukwinski { 9032f3563ccSZbigniew Lukwinski return false; 9042f3563ccSZbigniew Lukwinski } 9052f3563ccSZbigniew Lukwinski else 9062f3563ccSZbigniew Lukwinski { 9072f3563ccSZbigniew Lukwinski return true; 9082f3563ccSZbigniew Lukwinski } 9092f3563ccSZbigniew Lukwinski } 9102f3563ccSZbigniew Lukwinski 911cfbc8dc8SJayanth Othayoth } // namespace certs 912cfbc8dc8SJayanth Othayoth } // namespace phosphor 913