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 12e1289adfSNan Zhou namespace phosphor::certs 13cfbc8dc8SJayanth Othayoth { 14*cf06ccdcSNan Zhou namespace 15*cf06ccdcSNan Zhou { 16*cf06ccdcSNan Zhou namespace fs = std::filesystem; 17*cf06ccdcSNan Zhou using ::phosphor::logging::commit; 18*cf06ccdcSNan Zhou using ::phosphor::logging::elog; 19*cf06ccdcSNan Zhou using ::phosphor::logging::entry; 20*cf06ccdcSNan Zhou using ::phosphor::logging::level; 21*cf06ccdcSNan Zhou using ::phosphor::logging::log; 22*cf06ccdcSNan Zhou using ::phosphor::logging::report; 23cfbc8dc8SJayanth Othayoth 24*cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate; 25*cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 26*cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 27*cf06ccdcSNan Zhou using NotAllowedReason = 28*cf06ccdcSNan Zhou ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON; 29*cf06ccdcSNan Zhou using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project:: 30*cf06ccdcSNan Zhou Certs::InvalidCertificate::REASON; 31*cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 32*cf06ccdcSNan Zhou using Argument = 33*cf06ccdcSNan Zhou ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument; 34c6e58c7eSRamesh Iyyar 35*cf06ccdcSNan Zhou // RAII support for openSSL functions. 36*cf06ccdcSNan Zhou using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>; 37*cf06ccdcSNan Zhou using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>; 38*cf06ccdcSNan Zhou using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>; 39*cf06ccdcSNan Zhou 40*cf06ccdcSNan Zhou constexpr int supportedKeyBitLength = 2048; 41*cf06ccdcSNan Zhou constexpr int defaultKeyBitLength = 2048; 42*cf06ccdcSNan Zhou // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349 43*cf06ccdcSNan Zhou constexpr auto defaultKeyCurveID = "secp224r1"; 44*cf06ccdcSNan Zhou } // namespace 45f4682712SMarri Devender Rao 46f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event, 47*cf06ccdcSNan Zhou const char* path, CertificateType type, 48*cf06ccdcSNan Zhou const std::string& unit, const std::string& installPath) : 49*cf06ccdcSNan Zhou internal::ManagerInterface(bus, path), 50f4682712SMarri Devender Rao bus(bus), event(event), objectPath(path), certType(type), 51c6e58c7eSRamesh Iyyar unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)), 52c6e58c7eSRamesh Iyyar certParentInstallPath(fs::path(certInstallPath).parent_path()) 53cfbc8dc8SJayanth Othayoth { 54db5c6fc8SMarri Devender Rao try 55db5c6fc8SMarri Devender Rao { 56fe590c4eSZbigniew Lukwinski // Create certificate directory if not existing. 57bf3cf751SNan Zhou // Set correct certificate directory permissions. 58fe590c4eSZbigniew Lukwinski fs::path certDirectory; 59b57d75e2SMarri Devender Rao try 60b57d75e2SMarri Devender Rao { 61*cf06ccdcSNan Zhou if (certType == CertificateType::Authority) 62b57d75e2SMarri Devender Rao { 63fe590c4eSZbigniew Lukwinski certDirectory = certInstallPath; 64b57d75e2SMarri Devender Rao } 65fe590c4eSZbigniew Lukwinski else 66fe590c4eSZbigniew Lukwinski { 67fe590c4eSZbigniew Lukwinski certDirectory = certParentInstallPath; 68fe590c4eSZbigniew Lukwinski } 69fe590c4eSZbigniew Lukwinski 70fe590c4eSZbigniew Lukwinski if (!fs::exists(certDirectory)) 71fe590c4eSZbigniew Lukwinski { 72fe590c4eSZbigniew Lukwinski fs::create_directories(certDirectory); 73fe590c4eSZbigniew Lukwinski } 74fe590c4eSZbigniew Lukwinski 75667286e4SMarri Devender Rao auto permission = fs::perms::owner_read | fs::perms::owner_write | 76667286e4SMarri Devender Rao fs::perms::owner_exec; 77db5c6fc8SMarri Devender Rao fs::permissions(certDirectory, permission, 78db5c6fc8SMarri Devender Rao fs::perm_options::replace); 792f3563ccSZbigniew Lukwinski storageUpdate(); 80b57d75e2SMarri Devender Rao } 8171957992SPatrick Williams catch (const fs::filesystem_error& e) 82b57d75e2SMarri Devender Rao { 83db5c6fc8SMarri Devender Rao log<level::ERR>( 84db5c6fc8SMarri Devender Rao "Failed to create directory", entry("ERR=%s", e.what()), 85b57d75e2SMarri Devender Rao entry("DIRECTORY=%s", certParentInstallPath.c_str())); 86b57d75e2SMarri Devender Rao report<InternalFailure>(); 87b57d75e2SMarri Devender Rao } 88b57d75e2SMarri Devender Rao 89c6e58c7eSRamesh Iyyar // Generating RSA private key file if certificate type is server/client 90*cf06ccdcSNan Zhou if (certType != CertificateType::Authority) 91c6e58c7eSRamesh Iyyar { 92c6e58c7eSRamesh Iyyar createRSAPrivateKeyFile(); 93c6e58c7eSRamesh Iyyar } 94c6e58c7eSRamesh Iyyar 95ffad1ef1SMarri Devender Rao // restore any existing certificates 96db029c95SKowalski, Kamil createCertificates(); 97ffad1ef1SMarri Devender Rao 98ffad1ef1SMarri Devender Rao // watch is not required for authority certificates 99*cf06ccdcSNan Zhou if (certType != CertificateType::Authority) 100ffad1ef1SMarri Devender Rao { 101ffad1ef1SMarri Devender Rao // watch for certificate file create/replace 102ffad1ef1SMarri Devender Rao certWatchPtr = std::make_unique< 103ffad1ef1SMarri Devender Rao Watch>(event, certInstallPath, [this]() { 104bf7c588cSMarri Devender Rao try 105bf7c588cSMarri Devender Rao { 106ffad1ef1SMarri Devender Rao // if certificate file existing update it 107db029c95SKowalski, Kamil if (!installedCerts.empty()) 108ffad1ef1SMarri Devender Rao { 109db5c6fc8SMarri Devender Rao log<level::INFO>("Inotify callback to update " 110db5c6fc8SMarri Devender Rao "certificate properties"); 111db029c95SKowalski, Kamil installedCerts[0]->populateProperties(); 112ffad1ef1SMarri Devender Rao } 113ffad1ef1SMarri Devender Rao else 114ffad1ef1SMarri Devender Rao { 115ffad1ef1SMarri Devender Rao log<level::INFO>( 116ffad1ef1SMarri Devender Rao "Inotify callback to create certificate object"); 117db029c95SKowalski, Kamil createCertificates(); 118ffad1ef1SMarri Devender Rao } 119bf7c588cSMarri Devender Rao } 120bf7c588cSMarri Devender Rao catch (const InternalFailure& e) 121bf7c588cSMarri Devender Rao { 122ffad1ef1SMarri Devender Rao commit<InternalFailure>(); 123bf7c588cSMarri Devender Rao } 124bf7c588cSMarri Devender Rao catch (const InvalidCertificate& e) 125bf7c588cSMarri Devender Rao { 126ffad1ef1SMarri Devender Rao commit<InvalidCertificate>(); 127bf7c588cSMarri Devender Rao } 128ffad1ef1SMarri Devender Rao }); 129bf7c588cSMarri Devender Rao } 130db029c95SKowalski, Kamil else 131db029c95SKowalski, Kamil { 132db5c6fc8SMarri Devender Rao try 133db5c6fc8SMarri Devender Rao { 134db5c6fc8SMarri Devender Rao const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem"; 135db5c6fc8SMarri Devender Rao if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath)) 136db029c95SKowalski, Kamil { 137db029c95SKowalski, Kamil log<level::NOTICE>( 138db029c95SKowalski, Kamil "Legacy certificate detected, will be installed from: ", 139db5c6fc8SMarri Devender Rao entry("SINGLE_CERTPATH=%s", singleCertPath.c_str())); 140db5c6fc8SMarri Devender Rao install(singleCertPath); 141db5c6fc8SMarri Devender Rao if (!fs::remove(singleCertPath)) 142db029c95SKowalski, Kamil { 143db029c95SKowalski, Kamil log<level::ERR>( 144db029c95SKowalski, Kamil "Unable to remove old certificate from: ", 145db5c6fc8SMarri Devender Rao entry("SINGLE_CERTPATH=%s", 146db5c6fc8SMarri Devender Rao singleCertPath.c_str())); 147db029c95SKowalski, Kamil elog<InternalFailure>(); 148db029c95SKowalski, Kamil } 149db029c95SKowalski, Kamil } 150db029c95SKowalski, Kamil } 151db5c6fc8SMarri Devender Rao catch (const std::exception& ex) 152db5c6fc8SMarri Devender Rao { 153db5c6fc8SMarri Devender Rao log<level::ERR>("Error in restoring legacy certificate", 154db5c6fc8SMarri Devender Rao entry("ERROR_STR=%s", ex.what())); 155db5c6fc8SMarri Devender Rao } 156db5c6fc8SMarri Devender Rao } 157db5c6fc8SMarri Devender Rao } 15871957992SPatrick Williams catch (const std::exception& ex) 159db5c6fc8SMarri Devender Rao { 160db5c6fc8SMarri Devender Rao log<level::ERR>("Error in certificate manager constructor", 161db5c6fc8SMarri Devender Rao entry("ERROR_STR=%s", ex.what())); 162db5c6fc8SMarri Devender Rao } 163dd74bd20SJayanth Othayoth } 164589159f2SJayanth Othayoth 16506a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath) 166cfbc8dc8SJayanth Othayoth { 167*cf06ccdcSNan Zhou if (certType != CertificateType::Authority && !installedCerts.empty()) 1681396511dSMarri Devender Rao { 169*cf06ccdcSNan Zhou elog<NotAllowed>(NotAllowedReason("Certificate already exist")); 1701396511dSMarri Devender Rao } 171*cf06ccdcSNan Zhou else if (certType == CertificateType::Authority && 172718eef37SNan Zhou installedCerts.size() >= maxNumAuthorityCertificates) 1733b07b77aSZbigniew Lukwinski { 174*cf06ccdcSNan Zhou elog<NotAllowed>(NotAllowedReason("Certificates limit reached")); 1753b07b77aSZbigniew Lukwinski } 176ffad1ef1SMarri Devender Rao 1772f3563ccSZbigniew Lukwinski std::string certObjectPath; 1782f3563ccSZbigniew Lukwinski if (isCertificateUnique(filePath)) 1792f3563ccSZbigniew Lukwinski { 1802f3563ccSZbigniew Lukwinski certObjectPath = objectPath + '/' + std::to_string(certIdCounter); 181db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 1822f3563ccSZbigniew Lukwinski bus, certObjectPath, certType, certInstallPath, filePath, 183*cf06ccdcSNan Zhou certWatchPtr.get(), *this)); 1842f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 1852f3563ccSZbigniew Lukwinski certIdCounter++; 1862f3563ccSZbigniew Lukwinski } 1872f3563ccSZbigniew Lukwinski else 1882f3563ccSZbigniew Lukwinski { 189*cf06ccdcSNan Zhou elog<NotAllowed>(NotAllowedReason("Certificate already exist")); 1902f3563ccSZbigniew Lukwinski } 1912f3563ccSZbigniew Lukwinski 19206a69d7bSZbigniew Kurzynski return certObjectPath; 193589159f2SJayanth Othayoth } 194ae70b3daSDeepak Kodihalli 195a3bb38fbSZbigniew Kurzynski void Manager::deleteAll() 196ae70b3daSDeepak Kodihalli { 1976ceec40bSMarri Devender Rao // TODO: #Issue 4 when a certificate is deleted system auto generates 1986ceec40bSMarri Devender Rao // certificate file. At present we are not supporting creation of 1996ceec40bSMarri Devender Rao // certificate object for the auto-generated certificate file as 2006ceec40bSMarri Devender Rao // deletion if only applicable for REST server and Bmcweb does not allow 2016ceec40bSMarri Devender Rao // deletion of certificates 202db029c95SKowalski, Kamil installedCerts.clear(); 2032f3563ccSZbigniew Lukwinski storageUpdate(); 2042f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 205ae70b3daSDeepak Kodihalli } 206f4682712SMarri Devender Rao 2072f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate) 208a3bb38fbSZbigniew Kurzynski { 209a3bb38fbSZbigniew Kurzynski std::vector<std::unique_ptr<Certificate>>::iterator const& certIt = 210a3bb38fbSZbigniew Kurzynski std::find_if(installedCerts.begin(), installedCerts.end(), 2112f3563ccSZbigniew Lukwinski [certificate](std::unique_ptr<Certificate> const& cert) { 2122f3563ccSZbigniew Lukwinski return (cert.get() == certificate); 213a3bb38fbSZbigniew Kurzynski }); 214a3bb38fbSZbigniew Kurzynski if (certIt != installedCerts.end()) 215a3bb38fbSZbigniew Kurzynski { 216a3bb38fbSZbigniew Kurzynski installedCerts.erase(certIt); 2172f3563ccSZbigniew Lukwinski storageUpdate(); 2182f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 219a3bb38fbSZbigniew Kurzynski } 220a3bb38fbSZbigniew Kurzynski else 221a3bb38fbSZbigniew Kurzynski { 222a3bb38fbSZbigniew Kurzynski log<level::ERR>("Certificate does not exist", 2232f3563ccSZbigniew Lukwinski entry("ID=%s", certificate->getCertId().c_str())); 2242f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 2252f3563ccSZbigniew Lukwinski } 2262f3563ccSZbigniew Lukwinski } 2272f3563ccSZbigniew Lukwinski 2282f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate, 2292f3563ccSZbigniew Lukwinski const std::string& filePath) 2302f3563ccSZbigniew Lukwinski { 2312f3563ccSZbigniew Lukwinski if (isCertificateUnique(filePath, certificate)) 2322f3563ccSZbigniew Lukwinski { 2332f3563ccSZbigniew Lukwinski certificate->install(filePath); 2342f3563ccSZbigniew Lukwinski storageUpdate(); 2352f3563ccSZbigniew Lukwinski reloadOrReset(unitToRestart); 2362f3563ccSZbigniew Lukwinski } 2372f3563ccSZbigniew Lukwinski else 2382f3563ccSZbigniew Lukwinski { 239*cf06ccdcSNan Zhou elog<NotAllowed>(NotAllowedReason("Certificate already exist")); 240a3bb38fbSZbigniew Kurzynski } 241a3bb38fbSZbigniew Kurzynski } 242a3bb38fbSZbigniew Kurzynski 243f4682712SMarri Devender Rao std::string Manager::generateCSR( 244f4682712SMarri Devender Rao std::vector<std::string> alternativeNames, std::string challengePassword, 245f4682712SMarri Devender Rao std::string city, std::string commonName, std::string contactPerson, 246f4682712SMarri Devender Rao std::string country, std::string email, std::string givenName, 247f4682712SMarri Devender Rao std::string initials, int64_t keyBitLength, std::string keyCurveId, 248f4682712SMarri Devender Rao std::string keyPairAlgorithm, std::vector<std::string> keyUsage, 249f4682712SMarri Devender Rao std::string organization, std::string organizationalUnit, std::string state, 250f4682712SMarri Devender Rao std::string surname, std::string unstructuredName) 251f4682712SMarri Devender Rao { 252f4682712SMarri Devender Rao // We support only one CSR. 253f4682712SMarri Devender Rao csrPtr.reset(nullptr); 254f4682712SMarri Devender Rao auto pid = fork(); 255f4682712SMarri Devender Rao if (pid == -1) 256f4682712SMarri Devender Rao { 257f4682712SMarri Devender Rao log<level::ERR>("Error occurred during forking process"); 258f4682712SMarri Devender Rao report<InternalFailure>(); 259f4682712SMarri Devender Rao } 260f4682712SMarri Devender Rao else if (pid == 0) 261f4682712SMarri Devender Rao { 262f4682712SMarri Devender Rao try 263f4682712SMarri Devender Rao { 264f4682712SMarri Devender Rao generateCSRHelper(alternativeNames, challengePassword, city, 265f4682712SMarri Devender Rao commonName, contactPerson, country, email, 266f4682712SMarri Devender Rao givenName, initials, keyBitLength, keyCurveId, 267f4682712SMarri Devender Rao keyPairAlgorithm, keyUsage, organization, 268f4682712SMarri Devender Rao organizationalUnit, state, surname, 269f4682712SMarri Devender Rao unstructuredName); 270f4682712SMarri Devender Rao exit(EXIT_SUCCESS); 271f4682712SMarri Devender Rao } 272f4682712SMarri Devender Rao catch (const InternalFailure& e) 273f4682712SMarri Devender Rao { 274f4682712SMarri Devender Rao // commit the error reported in child process and exit 275f4682712SMarri Devender Rao // Callback method from SDEvent Loop looks for exit status 276f4682712SMarri Devender Rao exit(EXIT_FAILURE); 277f4682712SMarri Devender Rao commit<InternalFailure>(); 278f4682712SMarri Devender Rao } 279d2393f23SRamesh Iyyar catch (const InvalidArgument& e) 280d2393f23SRamesh Iyyar { 281d2393f23SRamesh Iyyar // commit the error reported in child process and exit 282d2393f23SRamesh Iyyar // Callback method from SDEvent Loop looks for exit status 283d2393f23SRamesh Iyyar exit(EXIT_FAILURE); 284d2393f23SRamesh Iyyar commit<InvalidArgument>(); 285d2393f23SRamesh Iyyar } 286f4682712SMarri Devender Rao } 287f4682712SMarri Devender Rao else 288f4682712SMarri Devender Rao { 289f4682712SMarri Devender Rao using namespace sdeventplus::source; 290f4682712SMarri Devender Rao Child::Callback callback = [this](Child& eventSource, 291f4682712SMarri Devender Rao const siginfo_t* si) { 292f4682712SMarri Devender Rao eventSource.set_enabled(Enabled::On); 293f4682712SMarri Devender Rao if (si->si_status != 0) 294f4682712SMarri Devender Rao { 295f4682712SMarri Devender Rao this->createCSRObject(Status::FAILURE); 296f4682712SMarri Devender Rao } 297f4682712SMarri Devender Rao else 298f4682712SMarri Devender Rao { 299f4682712SMarri Devender Rao this->createCSRObject(Status::SUCCESS); 300f4682712SMarri Devender Rao } 301f4682712SMarri Devender Rao }; 302f4682712SMarri Devender Rao try 303f4682712SMarri Devender Rao { 304f4682712SMarri Devender Rao sigset_t ss; 305f4682712SMarri Devender Rao if (sigemptyset(&ss) < 0) 306f4682712SMarri Devender Rao { 307f4682712SMarri Devender Rao log<level::ERR>("Unable to initialize signal set"); 308f4682712SMarri Devender Rao elog<InternalFailure>(); 309f4682712SMarri Devender Rao } 310f4682712SMarri Devender Rao if (sigaddset(&ss, SIGCHLD) < 0) 311f4682712SMarri Devender Rao { 312f4682712SMarri Devender Rao log<level::ERR>("Unable to add signal to signal set"); 313f4682712SMarri Devender Rao elog<InternalFailure>(); 314f4682712SMarri Devender Rao } 315f4682712SMarri Devender Rao 316f4682712SMarri Devender Rao // Block SIGCHLD first, so that the event loop can handle it 317cfb5802aSNan Zhou if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0) 318f4682712SMarri Devender Rao { 319f4682712SMarri Devender Rao log<level::ERR>("Unable to block signal"); 320f4682712SMarri Devender Rao elog<InternalFailure>(); 321f4682712SMarri Devender Rao } 322f4682712SMarri Devender Rao if (childPtr) 323f4682712SMarri Devender Rao { 324f4682712SMarri Devender Rao childPtr.reset(); 325f4682712SMarri Devender Rao } 326f4682712SMarri Devender Rao childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED, 327f4682712SMarri Devender Rao std::move(callback)); 328f4682712SMarri Devender Rao } 329f4682712SMarri Devender Rao catch (const InternalFailure& e) 330f4682712SMarri Devender Rao { 331f4682712SMarri Devender Rao commit<InternalFailure>(); 332f4682712SMarri Devender Rao } 333f4682712SMarri Devender Rao } 334f4682712SMarri Devender Rao auto csrObjectPath = objectPath + '/' + "csr"; 335f4682712SMarri Devender Rao return csrObjectPath; 336f4682712SMarri Devender Rao } 337f4682712SMarri Devender Rao 338db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates() 339ffad1ef1SMarri Devender Rao { 340db029c95SKowalski, Kamil return installedCerts; 341ffad1ef1SMarri Devender Rao } 342ffad1ef1SMarri Devender Rao 343f4682712SMarri Devender Rao void Manager::generateCSRHelper( 344f4682712SMarri Devender Rao std::vector<std::string> alternativeNames, std::string challengePassword, 345f4682712SMarri Devender Rao std::string city, std::string commonName, std::string contactPerson, 346f4682712SMarri Devender Rao std::string country, std::string email, std::string givenName, 347f4682712SMarri Devender Rao std::string initials, int64_t keyBitLength, std::string keyCurveId, 348f4682712SMarri Devender Rao std::string keyPairAlgorithm, std::vector<std::string> keyUsage, 349f4682712SMarri Devender Rao std::string organization, std::string organizationalUnit, std::string state, 350f4682712SMarri Devender Rao std::string surname, std::string unstructuredName) 351f4682712SMarri Devender Rao { 352f4682712SMarri Devender Rao int ret = 0; 353f4682712SMarri Devender Rao 354f4682712SMarri Devender Rao // set version of x509 req 355f4682712SMarri Devender Rao int nVersion = 1; 356f4682712SMarri Devender Rao // TODO: Issue#6 need to make version number configurable 357*cf06ccdcSNan Zhou X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free); 358f4682712SMarri Devender Rao ret = X509_REQ_set_version(x509Req.get(), nVersion); 359f4682712SMarri Devender Rao if (ret == 0) 360f4682712SMarri Devender Rao { 361bf3cf751SNan Zhou log<level::ERR>("Error occurred during X509_REQ_set_version call"); 362f4682712SMarri Devender Rao elog<InternalFailure>(); 363f4682712SMarri Devender Rao } 364f4682712SMarri Devender Rao 365f4682712SMarri Devender Rao // set subject of x509 req 366f4682712SMarri Devender Rao X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get()); 367f4682712SMarri Devender Rao 368f4682712SMarri Devender Rao if (!alternativeNames.empty()) 369f4682712SMarri Devender Rao { 370f4682712SMarri Devender Rao for (auto& name : alternativeNames) 371f4682712SMarri Devender Rao { 372f4682712SMarri Devender Rao addEntry(x509Name, "subjectAltName", name); 373f4682712SMarri Devender Rao } 374f4682712SMarri Devender Rao } 375f4682712SMarri Devender Rao addEntry(x509Name, "challengePassword", challengePassword); 376f4682712SMarri Devender Rao addEntry(x509Name, "L", city); 377f4682712SMarri Devender Rao addEntry(x509Name, "CN", commonName); 378f4682712SMarri Devender Rao addEntry(x509Name, "name", contactPerson); 379f4682712SMarri Devender Rao addEntry(x509Name, "C", country); 380f4682712SMarri Devender Rao addEntry(x509Name, "emailAddress", email); 381f4682712SMarri Devender Rao addEntry(x509Name, "GN", givenName); 382f4682712SMarri Devender Rao addEntry(x509Name, "initials", initials); 383f4682712SMarri Devender Rao addEntry(x509Name, "algorithm", keyPairAlgorithm); 384f4682712SMarri Devender Rao if (!keyUsage.empty()) 385f4682712SMarri Devender Rao { 386f4682712SMarri Devender Rao for (auto& usage : keyUsage) 387f4682712SMarri Devender Rao { 3887641105dSMarri Devender Rao if (isExtendedKeyUsage(usage)) 3897641105dSMarri Devender Rao { 3907641105dSMarri Devender Rao addEntry(x509Name, "extendedKeyUsage", usage); 3917641105dSMarri Devender Rao } 3927641105dSMarri Devender Rao else 3937641105dSMarri Devender Rao { 394f4682712SMarri Devender Rao addEntry(x509Name, "keyUsage", usage); 395f4682712SMarri Devender Rao } 396f4682712SMarri Devender Rao } 3977641105dSMarri Devender Rao } 398f4682712SMarri Devender Rao addEntry(x509Name, "O", organization); 399dc91fb61SJayanth Othayoth addEntry(x509Name, "OU", organizationalUnit); 400f4682712SMarri Devender Rao addEntry(x509Name, "ST", state); 401f4682712SMarri Devender Rao addEntry(x509Name, "SN", surname); 402f4682712SMarri Devender Rao addEntry(x509Name, "unstructuredName", unstructuredName); 403f4682712SMarri Devender Rao 404*cf06ccdcSNan Zhou EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free); 4058a09b52aSRamesh Iyyar 4068a09b52aSRamesh Iyyar log<level::INFO>("Given Key pair algorithm", 4078a09b52aSRamesh Iyyar entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str())); 4088a09b52aSRamesh Iyyar 4098a09b52aSRamesh Iyyar // Used EC algorithm as default if user did not give algorithm type. 4108a09b52aSRamesh Iyyar if (keyPairAlgorithm == "RSA") 411c6e58c7eSRamesh Iyyar pKey = getRSAKeyPair(keyBitLength); 4128a09b52aSRamesh Iyyar else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty())) 413c6e58c7eSRamesh Iyyar pKey = generateECKeyPair(keyCurveId); 4148a09b52aSRamesh Iyyar else 4158a09b52aSRamesh Iyyar { 4168a09b52aSRamesh Iyyar log<level::ERR>("Given Key pair algorithm is not supported. Supporting " 4178a09b52aSRamesh Iyyar "RSA and EC only"); 4188a09b52aSRamesh Iyyar elog<InvalidArgument>( 4198a09b52aSRamesh Iyyar Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"), 4208a09b52aSRamesh Iyyar Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str())); 4218a09b52aSRamesh Iyyar } 4228a09b52aSRamesh Iyyar 4238a09b52aSRamesh Iyyar ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get()); 4248a09b52aSRamesh Iyyar if (ret == 0) 4258a09b52aSRamesh Iyyar { 426bf3cf751SNan Zhou log<level::ERR>("Error occurred while setting Public key"); 4278a09b52aSRamesh Iyyar elog<InternalFailure>(); 4288a09b52aSRamesh Iyyar } 4298a09b52aSRamesh Iyyar 4308a09b52aSRamesh Iyyar // Write private key to file 431718eef37SNan Zhou writePrivateKey(pKey, defaultPrivateKeyFileName); 432f4682712SMarri Devender Rao 433f4682712SMarri Devender Rao // set sign key of x509 req 434f4682712SMarri Devender Rao ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256()); 4358a09b52aSRamesh Iyyar if (ret == 0) 436f4682712SMarri Devender Rao { 437bf3cf751SNan Zhou log<level::ERR>("Error occurred while signing key of x509"); 438f4682712SMarri Devender Rao elog<InternalFailure>(); 439f4682712SMarri Devender Rao } 4408a09b52aSRamesh Iyyar 441f4682712SMarri Devender Rao log<level::INFO>("Writing CSR to file"); 442718eef37SNan Zhou fs::path csrFilePath = certParentInstallPath / defaultCSRFileName; 443c6e58c7eSRamesh Iyyar writeCSR(csrFilePath.string(), x509Req); 444f4682712SMarri Devender Rao } 445f4682712SMarri Devender Rao 4467641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage) 4477641105dSMarri Devender Rao { 4487641105dSMarri Devender Rao const static std::array<const char*, 6> usageList = { 4497641105dSMarri Devender Rao "ServerAuthentication", "ClientAuthentication", "OCSPSigning", 4507641105dSMarri Devender Rao "Timestamping", "CodeSigning", "EmailProtection"}; 4517641105dSMarri Devender Rao auto it = std::find_if( 4527641105dSMarri Devender Rao usageList.begin(), usageList.end(), 4537641105dSMarri Devender Rao [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); }); 4547641105dSMarri Devender Rao return it != usageList.end(); 4557641105dSMarri Devender Rao } 456*cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength) 457f4682712SMarri Devender Rao { 4588a09b52aSRamesh Iyyar int64_t keyBitLen = keyBitLength; 459f4682712SMarri Devender Rao // set keybit length to default value if not set 4608a09b52aSRamesh Iyyar if (keyBitLen <= 0) 461f4682712SMarri Devender Rao { 4628a09b52aSRamesh Iyyar log<level::INFO>( 4638a09b52aSRamesh Iyyar "KeyBitLength is not given.Hence, using default KeyBitLength", 464*cf06ccdcSNan Zhou entry("DEFAULTKEYBITLENGTH=%d", defaultKeyBitLength)); 465*cf06ccdcSNan Zhou keyBitLen = defaultKeyBitLength; 466f4682712SMarri Devender Rao } 46726fb83efSPatrick Williams 46826fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 46926fb83efSPatrick Williams 47026fb83efSPatrick Williams // generate rsa key 471*cf06ccdcSNan Zhou BignumPtr bne(BN_new(), ::BN_free); 47226fb83efSPatrick Williams auto ret = BN_set_word(bne.get(), RSA_F4); 47326fb83efSPatrick Williams if (ret == 0) 47426fb83efSPatrick Williams { 475bf3cf751SNan Zhou log<level::ERR>("Error occurred during BN_set_word call"); 47626fb83efSPatrick Williams elog<InternalFailure>(); 47726fb83efSPatrick Williams } 478762da74eSNan Zhou using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>; 479762da74eSNan Zhou RSAPtr rsa(RSA_new(), ::RSA_free); 480762da74eSNan Zhou ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr); 481f4682712SMarri Devender Rao if (ret != 1) 482f4682712SMarri Devender Rao { 483bf3cf751SNan Zhou log<level::ERR>("Error occurred during RSA_generate_key_ex call", 4848a09b52aSRamesh Iyyar entry("KEYBITLENGTH=%PRIu64", keyBitLen)); 485f4682712SMarri Devender Rao elog<InternalFailure>(); 486f4682712SMarri Devender Rao } 487f4682712SMarri Devender Rao 488f4682712SMarri Devender Rao // set public key of x509 req 489*cf06ccdcSNan Zhou EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 490762da74eSNan Zhou ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get()); 491f4682712SMarri Devender Rao if (ret == 0) 492f4682712SMarri Devender Rao { 493bf3cf751SNan Zhou log<level::ERR>("Error occurred during assign rsa key into EVP"); 494f4682712SMarri Devender Rao elog<InternalFailure>(); 495f4682712SMarri Devender Rao } 496762da74eSNan Zhou // Now |rsa| is managed by |pKey| 497762da74eSNan Zhou rsa.release(); 4988a09b52aSRamesh Iyyar return pKey; 49926fb83efSPatrick Williams 50026fb83efSPatrick Williams #else 50126fb83efSPatrick Williams auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 50226fb83efSPatrick Williams EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free); 50326fb83efSPatrick Williams if (!ctx) 50426fb83efSPatrick Williams { 505bf3cf751SNan Zhou log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm"); 50626fb83efSPatrick Williams elog<InternalFailure>(); 50726fb83efSPatrick Williams } 50826fb83efSPatrick Williams 50926fb83efSPatrick Williams if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) || 51026fb83efSPatrick Williams (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0)) 51126fb83efSPatrick Williams 51226fb83efSPatrick Williams { 513bf3cf751SNan Zhou log<level::ERR>("Error occurred initializing keygen context"); 51426fb83efSPatrick Williams elog<InternalFailure>(); 51526fb83efSPatrick Williams } 51626fb83efSPatrick Williams 51726fb83efSPatrick Williams EVP_PKEY* pKey = nullptr; 51826fb83efSPatrick Williams if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 51926fb83efSPatrick Williams { 520bf3cf751SNan Zhou log<level::ERR>("Error occurred during generate EC key"); 52126fb83efSPatrick Williams elog<InternalFailure>(); 52226fb83efSPatrick Williams } 52326fb83efSPatrick Williams 52426fb83efSPatrick Williams return {pKey, &::EVP_PKEY_free}; 52526fb83efSPatrick Williams #endif 5268a09b52aSRamesh Iyyar } 5278a09b52aSRamesh Iyyar 528*cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId) 5298a09b52aSRamesh Iyyar { 5308a09b52aSRamesh Iyyar std::string curId(curveId); 5318a09b52aSRamesh Iyyar 5328a09b52aSRamesh Iyyar if (curId.empty()) 5338a09b52aSRamesh Iyyar { 5348a09b52aSRamesh Iyyar log<level::INFO>( 5358a09b52aSRamesh Iyyar "KeyCurveId is not given. Hence using default curve id", 536*cf06ccdcSNan Zhou entry("DEFAULTKEYCURVEID=%s", defaultKeyCurveID)); 537*cf06ccdcSNan Zhou curId = defaultKeyCurveID; 5388a09b52aSRamesh Iyyar } 5398a09b52aSRamesh Iyyar 5408a09b52aSRamesh Iyyar int ecGrp = OBJ_txt2nid(curId.c_str()); 5418a09b52aSRamesh Iyyar if (ecGrp == NID_undef) 5428a09b52aSRamesh Iyyar { 5438a09b52aSRamesh Iyyar log<level::ERR>( 544bf3cf751SNan Zhou "Error occurred during convert the curve id string format into NID", 5458a09b52aSRamesh Iyyar entry("KEYCURVEID=%s", curId.c_str())); 5468a09b52aSRamesh Iyyar elog<InternalFailure>(); 5478a09b52aSRamesh Iyyar } 5488a09b52aSRamesh Iyyar 54926fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L) 55026fb83efSPatrick Williams 5518a09b52aSRamesh Iyyar EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp); 5528a09b52aSRamesh Iyyar 553cfb5802aSNan Zhou if (ecKey == nullptr) 5548a09b52aSRamesh Iyyar { 5558a09b52aSRamesh Iyyar log<level::ERR>( 556bf3cf751SNan Zhou "Error occurred during create the EC_Key object from NID", 5578a09b52aSRamesh Iyyar entry("ECGROUP=%d", ecGrp)); 5588a09b52aSRamesh Iyyar elog<InternalFailure>(); 5598a09b52aSRamesh Iyyar } 5608a09b52aSRamesh Iyyar 5618a09b52aSRamesh Iyyar // If you want to save a key and later load it with 5628a09b52aSRamesh Iyyar // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE 5638a09b52aSRamesh Iyyar // flag on the key. 5648a09b52aSRamesh Iyyar EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE); 5658a09b52aSRamesh Iyyar 5668a09b52aSRamesh Iyyar int ret = EC_KEY_generate_key(ecKey); 5678a09b52aSRamesh Iyyar 5688a09b52aSRamesh Iyyar if (ret == 0) 5698a09b52aSRamesh Iyyar { 5708a09b52aSRamesh Iyyar EC_KEY_free(ecKey); 571bf3cf751SNan Zhou log<level::ERR>("Error occurred during generate EC key"); 5728a09b52aSRamesh Iyyar elog<InternalFailure>(); 5738a09b52aSRamesh Iyyar } 5748a09b52aSRamesh Iyyar 575*cf06ccdcSNan Zhou EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); 5768a09b52aSRamesh Iyyar ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey); 5778a09b52aSRamesh Iyyar if (ret == 0) 5788a09b52aSRamesh Iyyar { 5798a09b52aSRamesh Iyyar EC_KEY_free(ecKey); 580bf3cf751SNan Zhou log<level::ERR>("Error occurred during assign EC Key into EVP"); 5818a09b52aSRamesh Iyyar elog<InternalFailure>(); 5828a09b52aSRamesh Iyyar } 5838a09b52aSRamesh Iyyar 5848a09b52aSRamesh Iyyar return pKey; 58526fb83efSPatrick Williams 58626fb83efSPatrick Williams #else 58726fb83efSPatrick Williams auto holder_of_key = [](EVP_PKEY* key) { 58826fb83efSPatrick Williams return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{ 58926fb83efSPatrick Williams key, &::EVP_PKEY_free}; 59026fb83efSPatrick Williams }; 59126fb83efSPatrick Williams 59226fb83efSPatrick Williams // Create context to set up curve parameters. 59326fb83efSPatrick Williams auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>( 59426fb83efSPatrick Williams EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free); 59526fb83efSPatrick Williams if (!ctx) 59626fb83efSPatrick Williams { 597bf3cf751SNan Zhou log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params"); 59826fb83efSPatrick Williams elog<InternalFailure>(); 59926fb83efSPatrick Williams } 60026fb83efSPatrick Williams 60126fb83efSPatrick Williams // Set up curve parameters. 60226fb83efSPatrick Williams EVP_PKEY* params = nullptr; 60326fb83efSPatrick Williams 60426fb83efSPatrick Williams if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) || 60526fb83efSPatrick Williams (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <= 60626fb83efSPatrick Williams 0) || 60726fb83efSPatrick Williams (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) || 60826fb83efSPatrick Williams (EVP_PKEY_paramgen(ctx.get(), ¶ms) <= 0)) 60926fb83efSPatrick Williams { 610bf3cf751SNan Zhou log<level::ERR>("Error occurred setting curve parameters"); 61126fb83efSPatrick Williams elog<InternalFailure>(); 61226fb83efSPatrick Williams } 61326fb83efSPatrick Williams 61426fb83efSPatrick Williams // Move parameters to RAII holder. 61526fb83efSPatrick Williams auto pparms = holder_of_key(params); 61626fb83efSPatrick Williams 61726fb83efSPatrick Williams // Create new context for key. 61826fb83efSPatrick Williams ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr)); 61926fb83efSPatrick Williams 62026fb83efSPatrick Williams if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0)) 62126fb83efSPatrick Williams { 622bf3cf751SNan Zhou log<level::ERR>("Error occurred initializing keygen context"); 62326fb83efSPatrick Williams elog<InternalFailure>(); 62426fb83efSPatrick Williams } 62526fb83efSPatrick Williams 62626fb83efSPatrick Williams EVP_PKEY* pKey = nullptr; 62726fb83efSPatrick Williams if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0) 62826fb83efSPatrick Williams { 629bf3cf751SNan Zhou log<level::ERR>("Error occurred during generate EC key"); 63026fb83efSPatrick Williams elog<InternalFailure>(); 63126fb83efSPatrick Williams } 63226fb83efSPatrick Williams 63326fb83efSPatrick Williams return holder_of_key(pKey); 63426fb83efSPatrick Williams #endif 6358a09b52aSRamesh Iyyar } 6368a09b52aSRamesh Iyyar 637*cf06ccdcSNan Zhou void Manager::writePrivateKey(const EVPPkeyPtr& pKey, 638c6e58c7eSRamesh Iyyar const std::string& privKeyFileName) 6398a09b52aSRamesh Iyyar { 6408a09b52aSRamesh Iyyar log<level::INFO>("Writing private key to file"); 641f4682712SMarri Devender Rao // write private key to file 642c6e58c7eSRamesh Iyyar fs::path privKeyPath = certParentInstallPath / privKeyFileName; 643f4682712SMarri Devender Rao 644f4682712SMarri Devender Rao FILE* fp = std::fopen(privKeyPath.c_str(), "w"); 645cfb5802aSNan Zhou if (fp == nullptr) 646f4682712SMarri Devender Rao { 647bf3cf751SNan Zhou log<level::ERR>("Error occurred creating private key file"); 648f4682712SMarri Devender Rao elog<InternalFailure>(); 649f4682712SMarri Devender Rao } 650cfb5802aSNan Zhou int ret = 651cfb5802aSNan Zhou PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr); 652f4682712SMarri Devender Rao std::fclose(fp); 653f4682712SMarri Devender Rao if (ret == 0) 654f4682712SMarri Devender Rao { 655bf3cf751SNan Zhou log<level::ERR>("Error occurred while writing private key to file"); 656f4682712SMarri Devender Rao elog<InternalFailure>(); 657f4682712SMarri Devender Rao } 658f4682712SMarri Devender Rao } 659f4682712SMarri Devender Rao 660f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field, 661f4682712SMarri Devender Rao const std::string& bytes) 662f4682712SMarri Devender Rao { 663f4682712SMarri Devender Rao if (bytes.empty()) 664f4682712SMarri Devender Rao { 665f4682712SMarri Devender Rao return; 666f4682712SMarri Devender Rao } 667f4682712SMarri Devender Rao int ret = X509_NAME_add_entry_by_txt( 668f4682712SMarri Devender Rao x509Name, field, MBSTRING_ASC, 669f4682712SMarri Devender Rao reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0); 670f4682712SMarri Devender Rao if (ret != 1) 671f4682712SMarri Devender Rao { 672f4682712SMarri Devender Rao log<level::ERR>("Unable to set entry", entry("FIELD=%s", field), 673f4682712SMarri Devender Rao entry("VALUE=%s", bytes.c_str())); 674f4682712SMarri Devender Rao elog<InternalFailure>(); 675f4682712SMarri Devender Rao } 676f4682712SMarri Devender Rao } 677f4682712SMarri Devender Rao 678f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status) 679f4682712SMarri Devender Rao { 680f4682712SMarri Devender Rao if (csrPtr) 681f4682712SMarri Devender Rao { 682f4682712SMarri Devender Rao csrPtr.reset(nullptr); 683f4682712SMarri Devender Rao } 684f4682712SMarri Devender Rao auto csrObjectPath = objectPath + '/' + "csr"; 685f4682712SMarri Devender Rao csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(), 686f4682712SMarri Devender Rao certInstallPath.c_str(), status); 687f4682712SMarri Devender Rao } 688f4682712SMarri Devender Rao 689*cf06ccdcSNan Zhou void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req) 690f4682712SMarri Devender Rao { 691f4682712SMarri Devender Rao if (fs::exists(filePath)) 692f4682712SMarri Devender Rao { 693f4682712SMarri Devender Rao log<level::INFO>("Removing the existing file", 694f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 695f4682712SMarri Devender Rao if (!fs::remove(filePath.c_str())) 696f4682712SMarri Devender Rao { 697f4682712SMarri Devender Rao log<level::ERR>("Unable to remove the file", 698f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 699f4682712SMarri Devender Rao elog<InternalFailure>(); 700f4682712SMarri Devender Rao } 701f4682712SMarri Devender Rao } 702f4682712SMarri Devender Rao 703cfb5802aSNan Zhou FILE* fp = nullptr; 704f4682712SMarri Devender Rao 705cfb5802aSNan Zhou if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr) 706f4682712SMarri Devender Rao { 707f4682712SMarri Devender Rao log<level::ERR>("Error opening the file to write the CSR", 708f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 709f4682712SMarri Devender Rao elog<InternalFailure>(); 710f4682712SMarri Devender Rao } 711f4682712SMarri Devender Rao 712f4682712SMarri Devender Rao int rc = PEM_write_X509_REQ(fp, x509Req.get()); 713f4682712SMarri Devender Rao if (!rc) 714f4682712SMarri Devender Rao { 715f4682712SMarri Devender Rao log<level::ERR>("PEM write routine failed", 716f4682712SMarri Devender Rao entry("FILENAME=%s", filePath.c_str())); 717f4682712SMarri Devender Rao std::fclose(fp); 718f4682712SMarri Devender Rao elog<InternalFailure>(); 719f4682712SMarri Devender Rao } 720f4682712SMarri Devender Rao std::fclose(fp); 721f4682712SMarri Devender Rao } 722f4682712SMarri Devender Rao 723db029c95SKowalski, Kamil void Manager::createCertificates() 724db029c95SKowalski, Kamil { 725db029c95SKowalski, Kamil auto certObjectPath = objectPath + '/'; 726db029c95SKowalski, Kamil 727*cf06ccdcSNan Zhou if (certType == CertificateType::Authority) 728db029c95SKowalski, Kamil { 729fe590c4eSZbigniew Lukwinski // Check whether install path is a directory. 730db029c95SKowalski, Kamil if (!fs::is_directory(certInstallPath)) 731db029c95SKowalski, Kamil { 732db029c95SKowalski, Kamil log<level::ERR>("Certificate installation path exists and it is " 733db029c95SKowalski, Kamil "not a directory"); 734db029c95SKowalski, Kamil elog<InternalFailure>(); 735db029c95SKowalski, Kamil return; 736db029c95SKowalski, Kamil } 737db029c95SKowalski, Kamil 738db029c95SKowalski, Kamil for (auto& path : fs::directory_iterator(certInstallPath)) 739ffad1ef1SMarri Devender Rao { 740ffad1ef1SMarri Devender Rao try 741ffad1ef1SMarri Devender Rao { 7422f3563ccSZbigniew Lukwinski // Assume here any regular file located in certificate directory 7432f3563ccSZbigniew Lukwinski // contains certificates body. Do not want to use soft links 7442f3563ccSZbigniew Lukwinski // would add value. 7452f3563ccSZbigniew Lukwinski if (fs::is_regular_file(path)) 7462f3563ccSZbigniew Lukwinski { 747db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 748db029c95SKowalski, Kamil bus, certObjectPath + std::to_string(certIdCounter++), 749*cf06ccdcSNan Zhou certType, certInstallPath, path.path(), 750*cf06ccdcSNan Zhou certWatchPtr.get(), *this)); 7512f3563ccSZbigniew Lukwinski } 752ffad1ef1SMarri Devender Rao } 753ffad1ef1SMarri Devender Rao catch (const InternalFailure& e) 754ffad1ef1SMarri Devender Rao { 755ffad1ef1SMarri Devender Rao report<InternalFailure>(); 756ffad1ef1SMarri Devender Rao } 757ffad1ef1SMarri Devender Rao catch (const InvalidCertificate& e) 758ffad1ef1SMarri Devender Rao { 759*cf06ccdcSNan Zhou report<InvalidCertificate>(InvalidCertificateReason( 760*cf06ccdcSNan Zhou "Existing certificate file is corrupted")); 761ffad1ef1SMarri Devender Rao } 762ffad1ef1SMarri Devender Rao } 763db029c95SKowalski, Kamil } 764db029c95SKowalski, Kamil else if (fs::exists(certInstallPath)) 765db029c95SKowalski, Kamil { 766db029c95SKowalski, Kamil try 767db029c95SKowalski, Kamil { 768db029c95SKowalski, Kamil installedCerts.emplace_back(std::make_unique<Certificate>( 7692f3563ccSZbigniew Lukwinski bus, certObjectPath + '1', certType, certInstallPath, 770*cf06ccdcSNan Zhou certInstallPath, certWatchPtr.get(), *this)); 771db029c95SKowalski, Kamil } 772db029c95SKowalski, Kamil catch (const InternalFailure& e) 773db029c95SKowalski, Kamil { 774db029c95SKowalski, Kamil report<InternalFailure>(); 775db029c95SKowalski, Kamil } 776db029c95SKowalski, Kamil catch (const InvalidCertificate& e) 777db029c95SKowalski, Kamil { 778*cf06ccdcSNan Zhou report<InvalidCertificate>(InvalidCertificateReason( 779*cf06ccdcSNan Zhou "Existing certificate file is corrupted")); 780db029c95SKowalski, Kamil } 781db029c95SKowalski, Kamil } 782db029c95SKowalski, Kamil } 783c6e58c7eSRamesh Iyyar 784c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile() 785c6e58c7eSRamesh Iyyar { 786c6e58c7eSRamesh Iyyar fs::path rsaPrivateKeyFileName = 787718eef37SNan Zhou certParentInstallPath / defaultRSAPrivateKeyFileName; 788c6e58c7eSRamesh Iyyar 789c6e58c7eSRamesh Iyyar try 790c6e58c7eSRamesh Iyyar { 791c6e58c7eSRamesh Iyyar if (!fs::exists(rsaPrivateKeyFileName)) 792c6e58c7eSRamesh Iyyar { 793*cf06ccdcSNan Zhou writePrivateKey(generateRSAKeyPair(supportedKeyBitLength), 794718eef37SNan Zhou defaultRSAPrivateKeyFileName); 795c6e58c7eSRamesh Iyyar } 796c6e58c7eSRamesh Iyyar } 797c6e58c7eSRamesh Iyyar catch (const InternalFailure& e) 798c6e58c7eSRamesh Iyyar { 799c6e58c7eSRamesh Iyyar report<InternalFailure>(); 800c6e58c7eSRamesh Iyyar } 801c6e58c7eSRamesh Iyyar } 802c6e58c7eSRamesh Iyyar 803*cf06ccdcSNan Zhou EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength) 804c6e58c7eSRamesh Iyyar { 805*cf06ccdcSNan Zhou if (keyBitLength != supportedKeyBitLength) 806c6e58c7eSRamesh Iyyar { 807c6e58c7eSRamesh Iyyar log<level::ERR>( 808c6e58c7eSRamesh Iyyar "Given Key bit length is not supported", 809c6e58c7eSRamesh Iyyar entry("GIVENKEYBITLENGTH=%d", keyBitLength), 810*cf06ccdcSNan Zhou entry("SUPPORTEDKEYBITLENGTH=%d", supportedKeyBitLength)); 811c6e58c7eSRamesh Iyyar elog<InvalidArgument>( 812c6e58c7eSRamesh Iyyar Argument::ARGUMENT_NAME("KEYBITLENGTH"), 813c6e58c7eSRamesh Iyyar Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str())); 814c6e58c7eSRamesh Iyyar } 815c6e58c7eSRamesh Iyyar fs::path rsaPrivateKeyFileName = 816718eef37SNan Zhou certParentInstallPath / defaultRSAPrivateKeyFileName; 817c6e58c7eSRamesh Iyyar 818c6e58c7eSRamesh Iyyar FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r"); 819c6e58c7eSRamesh Iyyar if (!privateKeyFile) 820c6e58c7eSRamesh Iyyar { 821c6e58c7eSRamesh Iyyar log<level::ERR>("Unable to open RSA private key file to read", 822c6e58c7eSRamesh Iyyar entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()), 823c6e58c7eSRamesh Iyyar entry("ERRORREASON=%s", strerror(errno))); 824c6e58c7eSRamesh Iyyar elog<InternalFailure>(); 825c6e58c7eSRamesh Iyyar } 826c6e58c7eSRamesh Iyyar 827*cf06ccdcSNan Zhou EVPPkeyPtr privateKey( 828c6e58c7eSRamesh Iyyar PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr), 829c6e58c7eSRamesh Iyyar ::EVP_PKEY_free); 830c6e58c7eSRamesh Iyyar std::fclose(privateKeyFile); 831c6e58c7eSRamesh Iyyar 832c6e58c7eSRamesh Iyyar if (!privateKey) 833c6e58c7eSRamesh Iyyar { 834bf3cf751SNan Zhou log<level::ERR>("Error occurred during PEM_read_PrivateKey call"); 835c6e58c7eSRamesh Iyyar elog<InternalFailure>(); 836c6e58c7eSRamesh Iyyar } 837c6e58c7eSRamesh Iyyar return privateKey; 838c6e58c7eSRamesh Iyyar } 8392f3563ccSZbigniew Lukwinski 8402f3563ccSZbigniew Lukwinski void Manager::storageUpdate() 8412f3563ccSZbigniew Lukwinski { 842*cf06ccdcSNan Zhou if (certType == CertificateType::Authority) 8432f3563ccSZbigniew Lukwinski { 8442f3563ccSZbigniew Lukwinski // Remove symbolic links in the certificate directory 8452f3563ccSZbigniew Lukwinski for (auto& certPath : fs::directory_iterator(certInstallPath)) 8462f3563ccSZbigniew Lukwinski { 8472f3563ccSZbigniew Lukwinski try 8482f3563ccSZbigniew Lukwinski { 8492f3563ccSZbigniew Lukwinski if (fs::is_symlink(certPath)) 8502f3563ccSZbigniew Lukwinski { 8512f3563ccSZbigniew Lukwinski fs::remove(certPath); 8522f3563ccSZbigniew Lukwinski } 8532f3563ccSZbigniew Lukwinski } 8542f3563ccSZbigniew Lukwinski catch (const std::exception& e) 8552f3563ccSZbigniew Lukwinski { 8562f3563ccSZbigniew Lukwinski log<level::ERR>( 8572f3563ccSZbigniew Lukwinski "Failed to remove symlink for certificate", 8582f3563ccSZbigniew Lukwinski entry("ERR=%s", e.what()), 8592f3563ccSZbigniew Lukwinski entry("SYMLINK=%s", certPath.path().string().c_str())); 8602f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 8612f3563ccSZbigniew Lukwinski } 8622f3563ccSZbigniew Lukwinski } 8632f3563ccSZbigniew Lukwinski } 8642f3563ccSZbigniew Lukwinski 8652f3563ccSZbigniew Lukwinski for (const auto& cert : installedCerts) 8662f3563ccSZbigniew Lukwinski { 8672f3563ccSZbigniew Lukwinski cert->storageUpdate(); 8682f3563ccSZbigniew Lukwinski } 8692f3563ccSZbigniew Lukwinski } 8702f3563ccSZbigniew Lukwinski 871*cf06ccdcSNan Zhou void Manager::reloadOrReset(const std::string& unit) 8722f3563ccSZbigniew Lukwinski { 8732f3563ccSZbigniew Lukwinski if (!unit.empty()) 8742f3563ccSZbigniew Lukwinski { 8752f3563ccSZbigniew Lukwinski try 8762f3563ccSZbigniew Lukwinski { 877*cf06ccdcSNan Zhou constexpr auto defaultSystemdService = "org.freedesktop.systemd1"; 878*cf06ccdcSNan Zhou constexpr auto defaultSystemdObjectPath = 879*cf06ccdcSNan Zhou "/org/freedesktop/systemd1"; 880*cf06ccdcSNan Zhou constexpr auto defaultSystemdInterface = 8812f3563ccSZbigniew Lukwinski "org.freedesktop.systemd1.Manager"; 882*cf06ccdcSNan Zhou auto method = bus.new_method_call( 883*cf06ccdcSNan Zhou defaultSystemdService, defaultSystemdObjectPath, 884*cf06ccdcSNan Zhou defaultSystemdInterface, "ReloadOrRestartUnit"); 8852f3563ccSZbigniew Lukwinski method.append(unit, "replace"); 8862f3563ccSZbigniew Lukwinski bus.call_noreply(method); 8872f3563ccSZbigniew Lukwinski } 888ca128117SPatrick Williams catch (const sdbusplus::exception::exception& e) 8892f3563ccSZbigniew Lukwinski { 8902f3563ccSZbigniew Lukwinski log<level::ERR>("Failed to reload or restart service", 8912f3563ccSZbigniew Lukwinski entry("ERR=%s", e.what()), 8922f3563ccSZbigniew Lukwinski entry("UNIT=%s", unit.c_str())); 8932f3563ccSZbigniew Lukwinski elog<InternalFailure>(); 8942f3563ccSZbigniew Lukwinski } 8952f3563ccSZbigniew Lukwinski } 8962f3563ccSZbigniew Lukwinski } 8972f3563ccSZbigniew Lukwinski 8982f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath, 8992f3563ccSZbigniew Lukwinski const Certificate* const certToDrop) 9002f3563ccSZbigniew Lukwinski { 9012f3563ccSZbigniew Lukwinski if (std::any_of( 9022f3563ccSZbigniew Lukwinski installedCerts.begin(), installedCerts.end(), 9032f3563ccSZbigniew Lukwinski [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) { 9042f3563ccSZbigniew Lukwinski return cert.get() != certToDrop && cert->isSame(filePath); 9052f3563ccSZbigniew Lukwinski })) 9062f3563ccSZbigniew Lukwinski { 9072f3563ccSZbigniew Lukwinski return false; 9082f3563ccSZbigniew Lukwinski } 9092f3563ccSZbigniew Lukwinski else 9102f3563ccSZbigniew Lukwinski { 9112f3563ccSZbigniew Lukwinski return true; 9122f3563ccSZbigniew Lukwinski } 9132f3563ccSZbigniew Lukwinski } 9142f3563ccSZbigniew Lukwinski 915e1289adfSNan Zhou } // namespace phosphor::certs 916