1cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp" 2cfbc8dc8SJayanth Othayoth 3*26fb83efSPatrick 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. 41fe590c4eSZbigniew Lukwinski // Set correct certificate directory permitions. 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 309f4682712SMarri Devender Rao if (sigprocmask(SIG_BLOCK, &ss, NULL) < 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 { 353f4682712SMarri Devender Rao log<level::ERR>("Error occured 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 { 4188a09b52aSRamesh Iyyar log<level::ERR>("Error occured 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 { 429f4682712SMarri Devender Rao log<level::ERR>("Error occured 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 } 460*26fb83efSPatrick Williams 461*26fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 462*26fb83efSPatrick Williams 463*26fb83efSPatrick Williams // generate rsa key 464*26fb83efSPatrick Williams BIGNUM_Ptr bne(BN_new(), ::BN_free); 465*26fb83efSPatrick Williams auto ret = BN_set_word(bne.get(), RSA_F4); 466*26fb83efSPatrick Williams if (ret == 0) 467*26fb83efSPatrick Williams { 468*26fb83efSPatrick Williams log<level::ERR>("Error occured during BN_set_word call"); 469*26fb83efSPatrick Williams elog<InternalFailure>(); 470*26fb83efSPatrick Williams } 471*26fb83efSPatrick Williams 472f4682712SMarri Devender Rao RSA* rsa = RSA_new(); 4738a09b52aSRamesh Iyyar ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL); 474f4682712SMarri Devender Rao if (ret != 1) 475f4682712SMarri Devender Rao { 476f4682712SMarri Devender Rao free(rsa); 477f4682712SMarri Devender Rao log<level::ERR>("Error occured 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); 4888a09b52aSRamesh Iyyar log<level::ERR>("Error occured during assign rsa key into EVP"); 489f4682712SMarri Devender Rao elog<InternalFailure>(); 490f4682712SMarri Devender Rao } 491f4682712SMarri Devender Rao 4928a09b52aSRamesh Iyyar return pKey; 493*26fb83efSPatrick Williams 494*26fb83efSPatrick Williams #else 495*26fb83efSPatrick Williams auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 496*26fb83efSPatrick Williams EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free); 497*26fb83efSPatrick Williams if (!ctx) 498*26fb83efSPatrick Williams { 499*26fb83efSPatrick Williams log<level::ERR>("Error occured creating EVP_PKEY_CTX from algorithm"); 500*26fb83efSPatrick Williams elog<InternalFailure>(); 501*26fb83efSPatrick Williams } 502*26fb83efSPatrick Williams 503*26fb83efSPatrick Williams if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) || 504*26fb83efSPatrick Williams (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0)) 505*26fb83efSPatrick Williams 506*26fb83efSPatrick Williams { 507*26fb83efSPatrick Williams log<level::ERR>("Error occured initializing keygen context"); 508*26fb83efSPatrick Williams elog<InternalFailure>(); 509*26fb83efSPatrick Williams } 510*26fb83efSPatrick Williams 511*26fb83efSPatrick Williams EVP_PKEY* pKey = nullptr; 512*26fb83efSPatrick Williams if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 513*26fb83efSPatrick Williams { 514*26fb83efSPatrick Williams log<level::ERR>("Error occured during generate EC key"); 515*26fb83efSPatrick Williams elog<InternalFailure>(); 516*26fb83efSPatrick Williams } 517*26fb83efSPatrick Williams 518*26fb83efSPatrick Williams return {pKey, &::EVP_PKEY_free}; 519*26fb83efSPatrick 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>( 5408a09b52aSRamesh Iyyar "Error occured 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 545*26fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 546*26fb83efSPatrick Williams 5478a09b52aSRamesh Iyyar EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp); 5488a09b52aSRamesh Iyyar 5498a09b52aSRamesh Iyyar if (ecKey == NULL) 5508a09b52aSRamesh Iyyar { 5518a09b52aSRamesh Iyyar log<level::ERR>( 5528a09b52aSRamesh Iyyar "Error occured 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); 5678a09b52aSRamesh Iyyar log<level::ERR>("Error occured 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); 5768a09b52aSRamesh Iyyar log<level::ERR>("Error occured during assign EC Key into EVP"); 5778a09b52aSRamesh Iyyar elog<InternalFailure>(); 5788a09b52aSRamesh Iyyar } 5798a09b52aSRamesh Iyyar 5808a09b52aSRamesh Iyyar return pKey; 581*26fb83efSPatrick Williams 582*26fb83efSPatrick Williams #else 583*26fb83efSPatrick Williams auto holder_of_key = [](EVP_PKEY* key) { 584*26fb83efSPatrick Williams return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{ 585*26fb83efSPatrick Williams key, &::EVP_PKEY_free}; 586*26fb83efSPatrick Williams }; 587*26fb83efSPatrick Williams 588*26fb83efSPatrick Williams // Create context to set up curve parameters. 589*26fb83efSPatrick Williams auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 590*26fb83efSPatrick Williams EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free); 591*26fb83efSPatrick Williams if (!ctx) 592*26fb83efSPatrick Williams { 593*26fb83efSPatrick Williams log<level::ERR>("Error occured creating EVP_PKEY_CTX for params"); 594*26fb83efSPatrick Williams elog<InternalFailure>(); 595*26fb83efSPatrick Williams } 596*26fb83efSPatrick Williams 597*26fb83efSPatrick Williams // Set up curve parameters. 598*26fb83efSPatrick Williams EVP_PKEY* params = nullptr; 599*26fb83efSPatrick Williams 600*26fb83efSPatrick Williams if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) || 601*26fb83efSPatrick Williams (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <= 602*26fb83efSPatrick Williams 0) || 603*26fb83efSPatrick Williams (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) || 604*26fb83efSPatrick Williams (EVP_PKEY_paramgen(ctx.get(), ¶ms) <= 0)) 605*26fb83efSPatrick Williams { 606*26fb83efSPatrick Williams log<level::ERR>("Error occured setting curve parameters"); 607*26fb83efSPatrick Williams elog<InternalFailure>(); 608*26fb83efSPatrick Williams } 609*26fb83efSPatrick Williams 610*26fb83efSPatrick Williams // Move parameters to RAII holder. 611*26fb83efSPatrick Williams auto pparms = holder_of_key(params); 612*26fb83efSPatrick Williams 613*26fb83efSPatrick Williams // Create new context for key. 614*26fb83efSPatrick Williams ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr)); 615*26fb83efSPatrick Williams 616*26fb83efSPatrick Williams if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0)) 617*26fb83efSPatrick Williams { 618*26fb83efSPatrick Williams log<level::ERR>("Error occured initializing keygen context"); 619*26fb83efSPatrick Williams elog<InternalFailure>(); 620*26fb83efSPatrick Williams } 621*26fb83efSPatrick Williams 622*26fb83efSPatrick Williams EVP_PKEY* pKey = nullptr; 623*26fb83efSPatrick Williams if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 624*26fb83efSPatrick Williams { 625*26fb83efSPatrick Williams log<level::ERR>("Error occured during generate EC key"); 626*26fb83efSPatrick Williams elog<InternalFailure>(); 627*26fb83efSPatrick Williams } 628*26fb83efSPatrick Williams 629*26fb83efSPatrick Williams return holder_of_key(pKey); 630*26fb83efSPatrick 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"); 641f4682712SMarri Devender Rao if (fp == NULL) 642f4682712SMarri Devender Rao { 643f4682712SMarri Devender Rao log<level::ERR>("Error occured creating private key file"); 644f4682712SMarri Devender Rao elog<InternalFailure>(); 645f4682712SMarri Devender Rao } 6468a09b52aSRamesh Iyyar int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL); 647f4682712SMarri Devender Rao std::fclose(fp); 648f4682712SMarri Devender Rao if (ret == 0) 649f4682712SMarri Devender Rao { 650f4682712SMarri Devender Rao log<level::ERR>("Error occured while writing private key to file"); 651f4682712SMarri Devender Rao elog<InternalFailure>(); 652f4682712SMarri Devender Rao } 653f4682712SMarri Devender Rao } 654f4682712SMarri Devender Rao 655f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field, 656f4682712SMarri Devender Rao const std::string& bytes) 657f4682712SMarri Devender Rao { 658f4682712SMarri Devender Rao if (bytes.empty()) 659f4682712SMarri Devender Rao { 660f4682712SMarri Devender Rao return; 661f4682712SMarri Devender Rao } 662f4682712SMarri Devender Rao int ret = X509_NAME_add_entry_by_txt( 663f4682712SMarri Devender Rao x509Name, field, MBSTRING_ASC, 664f4682712SMarri Devender Rao reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0); 665f4682712SMarri Devender Rao if (ret != 1) 666f4682712SMarri Devender Rao { 667f4682712SMarri Devender Rao log<level::ERR>("Unable to set entry", entry("FIELD=%s", field), 668f4682712SMarri Devender Rao entry("VALUE=%s", bytes.c_str())); 669f4682712SMarri Devender Rao elog<InternalFailure>(); 670f4682712SMarri Devender Rao } 671f4682712SMarri Devender Rao } 672f4682712SMarri Devender Rao 673f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status) 674f4682712SMarri Devender Rao { 675f4682712SMarri Devender Rao if (csrPtr) 676f4682712SMarri Devender Rao { 677f4682712SMarri Devender Rao csrPtr.reset(nullptr); 678f4682712SMarri Devender Rao } 679f4682712SMarri Devender Rao auto csrObjectPath = objectPath + '/' + "csr"; 680f4682712SMarri Devender Rao csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(), 681f4682712SMarri Devender Rao certInstallPath.c_str(), status); 682f4682712SMarri Devender Rao } 683f4682712SMarri Devender Rao 684f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req) 685f4682712SMarri Devender Rao { 686f4682712SMarri Devender Rao if (fs::exists(filePath)) 687f4682712SMarri Devender Rao { 688f4682712SMarri Devender Rao log<level::INFO>("Removing the existing file", 689f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 690f4682712SMarri Devender Rao if (!fs::remove(filePath.c_str())) 691f4682712SMarri Devender Rao { 692f4682712SMarri Devender Rao log<level::ERR>("Unable to remove the file", 693f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 694f4682712SMarri Devender Rao elog<InternalFailure>(); 695f4682712SMarri Devender Rao } 696f4682712SMarri Devender Rao } 697f4682712SMarri Devender Rao 698f4682712SMarri Devender Rao FILE* fp = NULL; 699f4682712SMarri Devender Rao 700f4682712SMarri Devender Rao if ((fp = std::fopen(filePath.c_str(), "w")) == NULL) 701f4682712SMarri Devender Rao { 702f4682712SMarri Devender Rao log<level::ERR>("Error opening the file to write the CSR", 703f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 704f4682712SMarri Devender Rao elog<InternalFailure>(); 705f4682712SMarri Devender Rao } 706f4682712SMarri Devender Rao 707f4682712SMarri Devender Rao int rc = PEM_write_X509_REQ(fp, x509Req.get()); 708f4682712SMarri Devender Rao if (!rc) 709f4682712SMarri Devender Rao { 710f4682712SMarri Devender Rao log<level::ERR>("PEM write routine failed", 711f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 712f4682712SMarri Devender Rao std::fclose(fp); 713f4682712SMarri Devender Rao elog<InternalFailure>(); 714f4682712SMarri Devender Rao } 715f4682712SMarri Devender Rao std::fclose(fp); 716f4682712SMarri Devender Rao } 717f4682712SMarri Devender Rao 718db029c95SKowalski, Kamil void Manager::createCertificates() 719db029c95SKowalski, Kamil { 720db029c95SKowalski, Kamil auto certObjectPath = objectPath + '/'; 721db029c95SKowalski, Kamil 722db029c95SKowalski, Kamil if (certType == phosphor::certs::AUTHORITY) 723db029c95SKowalski, Kamil { 724fe590c4eSZbigniew Lukwinski // Check whether install path is a directory. 725db029c95SKowalski, Kamil if (!fs::is_directory(certInstallPath)) 726db029c95SKowalski, Kamil { 727db029c95SKowalski, Kamil log<level::ERR>("Certificate installation path exists and it is " 728db029c95SKowalski, Kamil "not a directory"); 729db029c95SKowalski, Kamil elog<InternalFailure>(); 730db029c95SKowalski, Kamil return; 731db029c95SKowalski, Kamil } 732db029c95SKowalski, Kamil 733db029c95SKowalski, Kamil for (auto& path : fs::directory_iterator(certInstallPath)) 734ffad1ef1SMarri Devender Rao { 735ffad1ef1SMarri Devender Rao try 736ffad1ef1SMarri Devender Rao { 7372f3563ccSZbigniew Lukwinski // Assume here any regular file located in certificate directory 7382f3563ccSZbigniew Lukwinski // contains certificates body. Do not want to use soft links 7392f3563ccSZbigniew Lukwinski // would add value. 7402f3563ccSZbigniew Lukwinski if (fs::is_regular_file(path)) 7412f3563ccSZbigniew Lukwinski { 742db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 743db029c95SKowalski, Kamil bus, certObjectPath + std::to_string(certIdCounter++), 7442f3563ccSZbigniew Lukwinski certType, certInstallPath, path.path(), certWatchPtr, 7452f3563ccSZbigniew Lukwinski *this)); 7462f3563ccSZbigniew Lukwinski } 747ffad1ef1SMarri Devender Rao } 748ffad1ef1SMarri Devender Rao catch (const InternalFailure& e) 749ffad1ef1SMarri Devender Rao { 750ffad1ef1SMarri Devender Rao report<InternalFailure>(); 751ffad1ef1SMarri Devender Rao } 752ffad1ef1SMarri Devender Rao catch (const InvalidCertificate& e) 753ffad1ef1SMarri Devender Rao { 754ffad1ef1SMarri Devender Rao report<InvalidCertificate>( 755ffad1ef1SMarri Devender Rao Reason("Existing certificate file is corrupted")); 756ffad1ef1SMarri Devender Rao } 757ffad1ef1SMarri Devender Rao } 758db029c95SKowalski, Kamil } 759db029c95SKowalski, Kamil else if (fs::exists(certInstallPath)) 760db029c95SKowalski, Kamil { 761db029c95SKowalski, Kamil try 762db029c95SKowalski, Kamil { 763db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 7642f3563ccSZbigniew Lukwinski bus, certObjectPath + '1', certType, certInstallPath, 7652f3563ccSZbigniew Lukwinski certInstallPath, certWatchPtr, *this)); 766db029c95SKowalski, Kamil } 767db029c95SKowalski, Kamil catch (const InternalFailure& e) 768db029c95SKowalski, Kamil { 769db029c95SKowalski, Kamil report<InternalFailure>(); 770db029c95SKowalski, Kamil } 771db029c95SKowalski, Kamil catch (const InvalidCertificate& e) 772db029c95SKowalski, Kamil { 773db029c95SKowalski, Kamil report<InvalidCertificate>( 774db029c95SKowalski, Kamil Reason("Existing certificate file is corrupted")); 775db029c95SKowalski, Kamil } 776db029c95SKowalski, Kamil } 777db029c95SKowalski, Kamil } 778c6e58c7eSRamesh Iyyar 779c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile() 780c6e58c7eSRamesh Iyyar { 781c6e58c7eSRamesh Iyyar fs::path rsaPrivateKeyFileName = 782c6e58c7eSRamesh Iyyar certParentInstallPath / RSA_PRIV_KEY_FILE_NAME; 783c6e58c7eSRamesh Iyyar 784c6e58c7eSRamesh Iyyar try 785c6e58c7eSRamesh Iyyar { 786c6e58c7eSRamesh Iyyar if (!fs::exists(rsaPrivateKeyFileName)) 787c6e58c7eSRamesh Iyyar { 788c6e58c7eSRamesh Iyyar writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH), 789c6e58c7eSRamesh Iyyar RSA_PRIV_KEY_FILE_NAME); 790c6e58c7eSRamesh Iyyar } 791c6e58c7eSRamesh Iyyar } 792c6e58c7eSRamesh Iyyar catch (const InternalFailure& e) 793c6e58c7eSRamesh Iyyar { 794c6e58c7eSRamesh Iyyar report<InternalFailure>(); 795c6e58c7eSRamesh Iyyar } 796c6e58c7eSRamesh Iyyar } 797c6e58c7eSRamesh Iyyar 798c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength) 799c6e58c7eSRamesh Iyyar { 800c6e58c7eSRamesh Iyyar if (keyBitLength != SUPPORTED_KEYBITLENGTH) 801c6e58c7eSRamesh Iyyar { 802c6e58c7eSRamesh Iyyar log<level::ERR>( 803c6e58c7eSRamesh Iyyar "Given Key bit length is not supported", 804c6e58c7eSRamesh Iyyar entry("GIVENKEYBITLENGTH=%d", keyBitLength), 805c6e58c7eSRamesh Iyyar entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH)); 806c6e58c7eSRamesh Iyyar elog<InvalidArgument>( 807c6e58c7eSRamesh Iyyar Argument::ARGUMENT_NAME("KEYBITLENGTH"), 808c6e58c7eSRamesh Iyyar Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str())); 809c6e58c7eSRamesh Iyyar } 810c6e58c7eSRamesh Iyyar fs::path rsaPrivateKeyFileName = 811c6e58c7eSRamesh Iyyar certParentInstallPath / RSA_PRIV_KEY_FILE_NAME; 812c6e58c7eSRamesh Iyyar 813c6e58c7eSRamesh Iyyar FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r"); 814c6e58c7eSRamesh Iyyar if (!privateKeyFile) 815c6e58c7eSRamesh Iyyar { 816c6e58c7eSRamesh Iyyar log<level::ERR>("Unable to open RSA private key file to read", 817c6e58c7eSRamesh Iyyar entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()), 818c6e58c7eSRamesh Iyyar entry("ERRORREASON=%s", strerror(errno))); 819c6e58c7eSRamesh Iyyar elog<InternalFailure>(); 820c6e58c7eSRamesh Iyyar } 821c6e58c7eSRamesh Iyyar 822c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr privateKey( 823c6e58c7eSRamesh Iyyar PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr), 824c6e58c7eSRamesh Iyyar ::EVP_PKEY_free); 825c6e58c7eSRamesh Iyyar std::fclose(privateKeyFile); 826c6e58c7eSRamesh Iyyar 827c6e58c7eSRamesh Iyyar if (!privateKey) 828c6e58c7eSRamesh Iyyar { 829c6e58c7eSRamesh Iyyar log<level::ERR>("Error occured during PEM_read_PrivateKey call"); 830c6e58c7eSRamesh Iyyar elog<InternalFailure>(); 831c6e58c7eSRamesh Iyyar } 832c6e58c7eSRamesh Iyyar return privateKey; 833c6e58c7eSRamesh Iyyar } 8342f3563ccSZbigniew Lukwinski 8352f3563ccSZbigniew Lukwinski void Manager::storageUpdate() 8362f3563ccSZbigniew Lukwinski { 8372f3563ccSZbigniew Lukwinski if (certType == phosphor::certs::AUTHORITY) 8382f3563ccSZbigniew Lukwinski { 8392f3563ccSZbigniew Lukwinski // Remove symbolic links in the certificate directory 8402f3563ccSZbigniew Lukwinski for (auto& certPath : fs::directory_iterator(certInstallPath)) 8412f3563ccSZbigniew Lukwinski { 8422f3563ccSZbigniew Lukwinski try 8432f3563ccSZbigniew Lukwinski { 8442f3563ccSZbigniew Lukwinski if (fs::is_symlink(certPath)) 8452f3563ccSZbigniew Lukwinski { 8462f3563ccSZbigniew Lukwinski fs::remove(certPath); 8472f3563ccSZbigniew Lukwinski } 8482f3563ccSZbigniew Lukwinski } 8492f3563ccSZbigniew Lukwinski catch (const std::exception& e) 8502f3563ccSZbigniew Lukwinski { 8512f3563ccSZbigniew Lukwinski log<level::ERR>( 8522f3563ccSZbigniew Lukwinski "Failed to remove symlink for certificate", 8532f3563ccSZbigniew Lukwinski entry("ERR=%s", e.what()), 8542f3563ccSZbigniew Lukwinski entry("SYMLINK=%s", certPath.path().string().c_str())); 8552f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 8562f3563ccSZbigniew Lukwinski } 8572f3563ccSZbigniew Lukwinski } 8582f3563ccSZbigniew Lukwinski } 8592f3563ccSZbigniew Lukwinski 8602f3563ccSZbigniew Lukwinski for (const auto& cert : installedCerts) 8612f3563ccSZbigniew Lukwinski { 8622f3563ccSZbigniew Lukwinski cert->storageUpdate(); 8632f3563ccSZbigniew Lukwinski } 8642f3563ccSZbigniew Lukwinski } 8652f3563ccSZbigniew Lukwinski 8662f3563ccSZbigniew Lukwinski void Manager::reloadOrReset(const UnitsToRestart& unit) 8672f3563ccSZbigniew Lukwinski { 8682f3563ccSZbigniew Lukwinski if (!unit.empty()) 8692f3563ccSZbigniew Lukwinski { 8702f3563ccSZbigniew Lukwinski try 8712f3563ccSZbigniew Lukwinski { 8722f3563ccSZbigniew Lukwinski constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 8732f3563ccSZbigniew Lukwinski constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 8742f3563ccSZbigniew Lukwinski constexpr auto SYSTEMD_INTERFACE = 8752f3563ccSZbigniew Lukwinski "org.freedesktop.systemd1.Manager"; 8762f3563ccSZbigniew Lukwinski 8772f3563ccSZbigniew Lukwinski auto method = 8782f3563ccSZbigniew Lukwinski bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, 8792f3563ccSZbigniew Lukwinski SYSTEMD_INTERFACE, "ReloadOrRestartUnit"); 8802f3563ccSZbigniew Lukwinski method.append(unit, "replace"); 8812f3563ccSZbigniew Lukwinski bus.call_noreply(method); 8822f3563ccSZbigniew Lukwinski } 883ca128117SPatrick Williams catch (const sdbusplus::exception::exception& e) 8842f3563ccSZbigniew Lukwinski { 8852f3563ccSZbigniew Lukwinski log<level::ERR>("Failed to reload or restart service", 8862f3563ccSZbigniew Lukwinski entry("ERR=%s", e.what()), 8872f3563ccSZbigniew Lukwinski entry("UNIT=%s", unit.c_str())); 8882f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 8892f3563ccSZbigniew Lukwinski } 8902f3563ccSZbigniew Lukwinski } 8912f3563ccSZbigniew Lukwinski } 8922f3563ccSZbigniew Lukwinski 8932f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath, 8942f3563ccSZbigniew Lukwinski const Certificate* const certToDrop) 8952f3563ccSZbigniew Lukwinski { 8962f3563ccSZbigniew Lukwinski if (std::any_of( 8972f3563ccSZbigniew Lukwinski installedCerts.begin(), installedCerts.end(), 8982f3563ccSZbigniew Lukwinski [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) { 8992f3563ccSZbigniew Lukwinski return cert.get() != certToDrop && cert->isSame(filePath); 9002f3563ccSZbigniew Lukwinski })) 9012f3563ccSZbigniew Lukwinski { 9022f3563ccSZbigniew Lukwinski return false; 9032f3563ccSZbigniew Lukwinski } 9042f3563ccSZbigniew Lukwinski else 9052f3563ccSZbigniew Lukwinski { 9062f3563ccSZbigniew Lukwinski return true; 9072f3563ccSZbigniew Lukwinski } 9082f3563ccSZbigniew Lukwinski } 9092f3563ccSZbigniew Lukwinski 910cfbc8dc8SJayanth Othayoth } // namespace certs 911cfbc8dc8SJayanth Othayoth } // namespace phosphor 912