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