xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 78357b0a3c96678c2a8ce6de2e5d493cbc6e3d9b)
1014be0bfSNan Zhou #include "config.h"
2014be0bfSNan Zhou 
3cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
4cfbc8dc8SJayanth Othayoth 
56ec13c8fSNan Zhou #include "x509_utils.hpp"
66ec13c8fSNan Zhou 
7014be0bfSNan Zhou #include <openssl/asn1.h>
8014be0bfSNan Zhou #include <openssl/bn.h>
9014be0bfSNan Zhou #include <openssl/ec.h>
1026fb83efSPatrick Williams #include <openssl/evp.h>
11014be0bfSNan Zhou #include <openssl/obj_mac.h>
12014be0bfSNan Zhou #include <openssl/objects.h>
13014be0bfSNan Zhou #include <openssl/opensslv.h>
14f4682712SMarri Devender Rao #include <openssl/pem.h>
15014be0bfSNan Zhou #include <openssl/rsa.h>
16f4682712SMarri Devender Rao #include <unistd.h>
17f4682712SMarri Devender Rao 
18a3bb38fbSZbigniew Kurzynski #include <algorithm>
19014be0bfSNan Zhou #include <array>
20014be0bfSNan Zhou #include <cerrno>
21014be0bfSNan Zhou #include <chrono>
22014be0bfSNan Zhou #include <csignal>
23014be0bfSNan Zhou #include <cstdio>
24014be0bfSNan Zhou #include <cstdlib>
25014be0bfSNan Zhou #include <cstring>
26014be0bfSNan Zhou #include <exception>
276ec13c8fSNan Zhou #include <fstream>
286ceec40bSMarri Devender Rao #include <phosphor-logging/elog-errors.hpp>
29014be0bfSNan Zhou #include <phosphor-logging/elog.hpp>
30014be0bfSNan Zhou #include <phosphor-logging/log.hpp>
31014be0bfSNan Zhou #include <sdbusplus/bus.hpp>
32014be0bfSNan Zhou #include <sdbusplus/exception.hpp>
33014be0bfSNan Zhou #include <sdbusplus/message.hpp>
34014be0bfSNan Zhou #include <sdeventplus/source/base.hpp>
35014be0bfSNan Zhou #include <sdeventplus/source/child.hpp>
36014be0bfSNan Zhou #include <utility>
3713bf74e4SMarri Devender Rao #include <xyz/openbmc_project/Certs/error.hpp>
38cfbc8dc8SJayanth Othayoth #include <xyz/openbmc_project/Common/error.hpp>
392f3563ccSZbigniew Lukwinski 
40e1289adfSNan Zhou namespace phosphor::certs
41cfbc8dc8SJayanth Othayoth {
42cf06ccdcSNan Zhou namespace
43cf06ccdcSNan Zhou {
44cf06ccdcSNan Zhou namespace fs = std::filesystem;
45cf06ccdcSNan Zhou using ::phosphor::logging::commit;
46cf06ccdcSNan Zhou using ::phosphor::logging::elog;
47cf06ccdcSNan Zhou using ::phosphor::logging::entry;
48cf06ccdcSNan Zhou using ::phosphor::logging::level;
49cf06ccdcSNan Zhou using ::phosphor::logging::log;
50cf06ccdcSNan Zhou using ::phosphor::logging::report;
51cfbc8dc8SJayanth Othayoth 
52cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
53cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
54cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
55cf06ccdcSNan Zhou using NotAllowedReason =
56cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
57cf06ccdcSNan Zhou using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
58cf06ccdcSNan Zhou     Certs::InvalidCertificate::REASON;
59cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
60cf06ccdcSNan Zhou using Argument =
61cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
62c6e58c7eSRamesh Iyyar 
63cf06ccdcSNan Zhou // RAII support for openSSL functions.
64cf06ccdcSNan Zhou using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
65cf06ccdcSNan Zhou using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
66cf06ccdcSNan Zhou using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
676ec13c8fSNan Zhou using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
68cf06ccdcSNan Zhou 
69cf06ccdcSNan Zhou constexpr int supportedKeyBitLength = 2048;
70cf06ccdcSNan Zhou constexpr int defaultKeyBitLength = 2048;
71cf06ccdcSNan Zhou // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
72cf06ccdcSNan Zhou constexpr auto defaultKeyCurveID = "secp224r1";
736ec13c8fSNan Zhou // PEM certificate block markers, defined in go/rfc/7468.
746ec13c8fSNan Zhou constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
756ec13c8fSNan Zhou constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
766ec13c8fSNan Zhou 
776ec13c8fSNan Zhou /**
786ec13c8fSNan Zhou  * @brief Splits the given authorities list file and returns an array of
796ec13c8fSNan Zhou  * individual PEM encoded x509 certificate.
806ec13c8fSNan Zhou  *
816ec13c8fSNan Zhou  * @param[in] sourceFilePath - Path to the authorities list file.
826ec13c8fSNan Zhou  *
836ec13c8fSNan Zhou  * @return An array of individual PEM encoded x509 certificate
846ec13c8fSNan Zhou  */
856ec13c8fSNan Zhou std::vector<std::string> splitCertificates(const std::string& sourceFilePath)
866ec13c8fSNan Zhou {
876ec13c8fSNan Zhou     std::ifstream inputCertFileStream;
886ec13c8fSNan Zhou     inputCertFileStream.exceptions(
896ec13c8fSNan Zhou         std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
906ec13c8fSNan Zhou 
916ec13c8fSNan Zhou     std::stringstream pemStream;
926ec13c8fSNan Zhou     std::vector<std::string> certificatesList;
936ec13c8fSNan Zhou     try
946ec13c8fSNan Zhou     {
956ec13c8fSNan Zhou         inputCertFileStream.open(sourceFilePath);
966ec13c8fSNan Zhou         pemStream << inputCertFileStream.rdbuf();
976ec13c8fSNan Zhou         inputCertFileStream.close();
986ec13c8fSNan Zhou     }
996ec13c8fSNan Zhou     catch (const std::exception& e)
1006ec13c8fSNan Zhou     {
1016ec13c8fSNan Zhou         log<level::ERR>("Failed to read certificates list",
1026ec13c8fSNan Zhou                         entry("ERR=%s", e.what()),
1036ec13c8fSNan Zhou                         entry("SRC=%s", sourceFilePath.c_str()));
1046ec13c8fSNan Zhou         elog<InternalFailure>();
1056ec13c8fSNan Zhou     }
1066ec13c8fSNan Zhou     std::string pem = pemStream.str();
1076ec13c8fSNan Zhou     size_t begin = 0;
1086ec13c8fSNan Zhou     // |begin| points to the current start position for searching the next
1096ec13c8fSNan Zhou     // |beginCertificate| block. When we find the beginning of the certificate,
1106ec13c8fSNan Zhou     // we extract the content between the beginning and the end of the current
1116ec13c8fSNan Zhou     // certificate. And finally we move |begin| to the end of the current
1126ec13c8fSNan Zhou     // certificate to start searching the next potential certificate.
1136ec13c8fSNan Zhou     for (begin = pem.find(beginCertificate, begin); begin != std::string::npos;
1146ec13c8fSNan Zhou          begin = pem.find(beginCertificate, begin))
1156ec13c8fSNan Zhou     {
1166ec13c8fSNan Zhou         size_t end = pem.find(endCertificate, begin);
1176ec13c8fSNan Zhou         if (end == std::string::npos)
1186ec13c8fSNan Zhou         {
1196ec13c8fSNan Zhou             log<level::ERR>(
1206ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END");
1216ec13c8fSNan Zhou             elog<InvalidCertificate>(InvalidCertificateReason(
1226ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END"));
1236ec13c8fSNan Zhou         }
1246ec13c8fSNan Zhou         end += endCertificate.size();
1256ec13c8fSNan Zhou         certificatesList.emplace_back(pem.substr(begin, end - begin));
1266ec13c8fSNan Zhou         begin = end;
1276ec13c8fSNan Zhou     }
1286ec13c8fSNan Zhou     return certificatesList;
1296ec13c8fSNan Zhou }
1306ec13c8fSNan Zhou 
131cf06ccdcSNan Zhou } // namespace
132f4682712SMarri Devender Rao 
133f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
134cf06ccdcSNan Zhou                  const char* path, CertificateType type,
135cf06ccdcSNan Zhou                  const std::string& unit, const std::string& installPath) :
136cf06ccdcSNan Zhou     internal::ManagerInterface(bus, path),
137f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
138c6e58c7eSRamesh Iyyar     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
139c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
140cfbc8dc8SJayanth Othayoth {
141db5c6fc8SMarri Devender Rao     try
142db5c6fc8SMarri Devender Rao     {
143fe590c4eSZbigniew Lukwinski         // Create certificate directory if not existing.
144bf3cf751SNan Zhou         // Set correct certificate directory permissions.
145fe590c4eSZbigniew Lukwinski         fs::path certDirectory;
146b57d75e2SMarri Devender Rao         try
147b57d75e2SMarri Devender Rao         {
148cf06ccdcSNan Zhou             if (certType == CertificateType::Authority)
149b57d75e2SMarri Devender Rao             {
150fe590c4eSZbigniew Lukwinski                 certDirectory = certInstallPath;
151b57d75e2SMarri Devender Rao             }
152fe590c4eSZbigniew Lukwinski             else
153fe590c4eSZbigniew Lukwinski             {
154fe590c4eSZbigniew Lukwinski                 certDirectory = certParentInstallPath;
155fe590c4eSZbigniew Lukwinski             }
156fe590c4eSZbigniew Lukwinski 
157fe590c4eSZbigniew Lukwinski             if (!fs::exists(certDirectory))
158fe590c4eSZbigniew Lukwinski             {
159fe590c4eSZbigniew Lukwinski                 fs::create_directories(certDirectory);
160fe590c4eSZbigniew Lukwinski             }
161fe590c4eSZbigniew Lukwinski 
162667286e4SMarri Devender Rao             auto permission = fs::perms::owner_read | fs::perms::owner_write |
163667286e4SMarri Devender Rao                               fs::perms::owner_exec;
164db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
165db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
1662f3563ccSZbigniew Lukwinski             storageUpdate();
167b57d75e2SMarri Devender Rao         }
16871957992SPatrick Williams         catch (const fs::filesystem_error& e)
169b57d75e2SMarri Devender Rao         {
170db5c6fc8SMarri Devender Rao             log<level::ERR>(
171db5c6fc8SMarri Devender Rao                 "Failed to create directory", entry("ERR=%s", e.what()),
172b57d75e2SMarri Devender Rao                 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
173b57d75e2SMarri Devender Rao             report<InternalFailure>();
174b57d75e2SMarri Devender Rao         }
175b57d75e2SMarri Devender Rao 
176c6e58c7eSRamesh Iyyar         // Generating RSA private key file if certificate type is server/client
177cf06ccdcSNan Zhou         if (certType != CertificateType::Authority)
178c6e58c7eSRamesh Iyyar         {
179c6e58c7eSRamesh Iyyar             createRSAPrivateKeyFile();
180c6e58c7eSRamesh Iyyar         }
181c6e58c7eSRamesh Iyyar 
182ffad1ef1SMarri Devender Rao         // restore any existing certificates
183db029c95SKowalski, Kamil         createCertificates();
184ffad1ef1SMarri Devender Rao 
185ffad1ef1SMarri Devender Rao         // watch is not required for authority certificates
186cf06ccdcSNan Zhou         if (certType != CertificateType::Authority)
187ffad1ef1SMarri Devender Rao         {
188ffad1ef1SMarri Devender Rao             // watch for certificate file create/replace
189ffad1ef1SMarri Devender Rao             certWatchPtr = std::make_unique<
190ffad1ef1SMarri Devender Rao                 Watch>(event, certInstallPath, [this]() {
191bf7c588cSMarri Devender Rao                 try
192bf7c588cSMarri Devender Rao                 {
193ffad1ef1SMarri Devender Rao                     // if certificate file existing update it
194db029c95SKowalski, Kamil                     if (!installedCerts.empty())
195ffad1ef1SMarri Devender Rao                     {
196db5c6fc8SMarri Devender Rao                         log<level::INFO>("Inotify callback to update "
197db5c6fc8SMarri Devender Rao                                          "certificate properties");
198db029c95SKowalski, Kamil                         installedCerts[0]->populateProperties();
199ffad1ef1SMarri Devender Rao                     }
200ffad1ef1SMarri Devender Rao                     else
201ffad1ef1SMarri Devender Rao                     {
202ffad1ef1SMarri Devender Rao                         log<level::INFO>(
203ffad1ef1SMarri Devender Rao                             "Inotify callback to create certificate object");
204db029c95SKowalski, Kamil                         createCertificates();
205ffad1ef1SMarri Devender Rao                     }
206bf7c588cSMarri Devender Rao                 }
207bf7c588cSMarri Devender Rao                 catch (const InternalFailure& e)
208bf7c588cSMarri Devender Rao                 {
209ffad1ef1SMarri Devender Rao                     commit<InternalFailure>();
210bf7c588cSMarri Devender Rao                 }
211bf7c588cSMarri Devender Rao                 catch (const InvalidCertificate& e)
212bf7c588cSMarri Devender Rao                 {
213ffad1ef1SMarri Devender Rao                     commit<InvalidCertificate>();
214bf7c588cSMarri Devender Rao                 }
215ffad1ef1SMarri Devender Rao             });
216bf7c588cSMarri Devender Rao         }
217db029c95SKowalski, Kamil         else
218db029c95SKowalski, Kamil         {
219db5c6fc8SMarri Devender Rao             try
220db5c6fc8SMarri Devender Rao             {
221db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
222db5c6fc8SMarri Devender Rao                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
223db029c95SKowalski, Kamil                 {
224db029c95SKowalski, Kamil                     log<level::NOTICE>(
225db029c95SKowalski, Kamil                         "Legacy certificate detected, will be installed from: ",
226db5c6fc8SMarri Devender Rao                         entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
227db5c6fc8SMarri Devender Rao                     install(singleCertPath);
228db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
229db029c95SKowalski, Kamil                     {
230db029c95SKowalski, Kamil                         log<level::ERR>(
231db029c95SKowalski, Kamil                             "Unable to remove old certificate from: ",
232db5c6fc8SMarri Devender Rao                             entry("SINGLE_CERTPATH=%s",
233db5c6fc8SMarri Devender Rao                                   singleCertPath.c_str()));
234db029c95SKowalski, Kamil                         elog<InternalFailure>();
235db029c95SKowalski, Kamil                     }
236db029c95SKowalski, Kamil                 }
237db029c95SKowalski, Kamil             }
238db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
239db5c6fc8SMarri Devender Rao             {
240db5c6fc8SMarri Devender Rao                 log<level::ERR>("Error in restoring legacy certificate",
241db5c6fc8SMarri Devender Rao                                 entry("ERROR_STR=%s", ex.what()));
242db5c6fc8SMarri Devender Rao             }
243db5c6fc8SMarri Devender Rao         }
244db5c6fc8SMarri Devender Rao     }
24571957992SPatrick Williams     catch (const std::exception& ex)
246db5c6fc8SMarri Devender Rao     {
247db5c6fc8SMarri Devender Rao         log<level::ERR>("Error in certificate manager constructor",
248db5c6fc8SMarri Devender Rao                         entry("ERROR_STR=%s", ex.what()));
249db5c6fc8SMarri Devender Rao     }
250dd74bd20SJayanth Othayoth }
251589159f2SJayanth Othayoth 
25206a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath)
253cfbc8dc8SJayanth Othayoth {
254cf06ccdcSNan Zhou     if (certType != CertificateType::Authority && !installedCerts.empty())
2551396511dSMarri Devender Rao     {
256cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
2571396511dSMarri Devender Rao     }
258cf06ccdcSNan Zhou     else if (certType == CertificateType::Authority &&
259718eef37SNan Zhou              installedCerts.size() >= maxNumAuthorityCertificates)
2603b07b77aSZbigniew Lukwinski     {
261cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
2623b07b77aSZbigniew Lukwinski     }
263ffad1ef1SMarri Devender Rao 
2642f3563ccSZbigniew Lukwinski     std::string certObjectPath;
2652f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath))
2662f3563ccSZbigniew Lukwinski     {
2672f3563ccSZbigniew Lukwinski         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
268db029c95SKowalski, Kamil         installedCerts.emplace_back(std::make_unique<Certificate>(
2692f3563ccSZbigniew Lukwinski             bus, certObjectPath, certType, certInstallPath, filePath,
270cf06ccdcSNan Zhou             certWatchPtr.get(), *this));
2712f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
2722f3563ccSZbigniew Lukwinski         certIdCounter++;
2732f3563ccSZbigniew Lukwinski     }
2742f3563ccSZbigniew Lukwinski     else
2752f3563ccSZbigniew Lukwinski     {
276cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
2772f3563ccSZbigniew Lukwinski     }
2782f3563ccSZbigniew Lukwinski 
27906a69d7bSZbigniew Kurzynski     return certObjectPath;
280589159f2SJayanth Othayoth }
281ae70b3daSDeepak Kodihalli 
2826ec13c8fSNan Zhou std::vector<sdbusplus::message::object_path>
2836ec13c8fSNan Zhou     Manager::installAll(const std::string filePath)
2846ec13c8fSNan Zhou {
2856ec13c8fSNan Zhou     if (certType != CertificateType::Authority)
2866ec13c8fSNan Zhou     {
2876ec13c8fSNan Zhou         elog<NotAllowed>(
2886ec13c8fSNan Zhou             NotAllowedReason("The InstallAll interface is only allowed for "
2896ec13c8fSNan Zhou                              "Authority certificates"));
2906ec13c8fSNan Zhou     }
2916ec13c8fSNan Zhou 
2926ec13c8fSNan Zhou     if (!installedCerts.empty())
2936ec13c8fSNan Zhou     {
2946ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason(
2956ec13c8fSNan Zhou             "There are already root certificates; Call DeleteAll then "
2966ec13c8fSNan Zhou             "InstallAll, or use ReplaceAll"));
2976ec13c8fSNan Zhou     }
2986ec13c8fSNan Zhou 
2996ec13c8fSNan Zhou     fs::path sourceFile(filePath);
3006ec13c8fSNan Zhou     if (!fs::exists(sourceFile))
3016ec13c8fSNan Zhou     {
3026ec13c8fSNan Zhou         log<level::ERR>("File is Missing", entry("FILE=%s", filePath.c_str()));
3036ec13c8fSNan Zhou         elog<InternalFailure>();
3046ec13c8fSNan Zhou     }
3056ec13c8fSNan Zhou     std::vector<std::string> authorities = splitCertificates(sourceFile);
3066ec13c8fSNan Zhou     if (authorities.size() > maxNumAuthorityCertificates)
3076ec13c8fSNan Zhou     {
3086ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
3096ec13c8fSNan Zhou     }
3106ec13c8fSNan Zhou 
311*78357b0aSNan Zhou     log<level::INFO>("Starts authority list install");
312*78357b0aSNan Zhou 
3136ec13c8fSNan Zhou     fs::path authorityStore(certInstallPath);
3146ec13c8fSNan Zhou     fs::path authoritiesListFile =
3156ec13c8fSNan Zhou         authorityStore / defaultAuthoritiesListFileName;
3166ec13c8fSNan Zhou 
3176ec13c8fSNan Zhou     // Atomically install all the certificates
3186ec13c8fSNan Zhou     fs::path tempPath = Certificate::generateUniqueFilePath(authorityStore);
3196ec13c8fSNan Zhou     fs::create_directory(tempPath);
3206ec13c8fSNan Zhou     // Copies the authorities list
3216ec13c8fSNan Zhou     Certificate::copyCertificate(sourceFile,
3226ec13c8fSNan Zhou                                  tempPath / defaultAuthoritiesListFileName);
3236ec13c8fSNan Zhou     std::vector<std::unique_ptr<Certificate>> tempCertificates;
3246ec13c8fSNan Zhou     uint64_t tempCertIdCounter = certIdCounter;
3256ec13c8fSNan Zhou     X509StorePtr x509Store = getX509Store(sourceFile);
3266ec13c8fSNan Zhou     for (const auto& authority : authorities)
3276ec13c8fSNan Zhou     {
3286ec13c8fSNan Zhou         std::string certObjectPath =
3296ec13c8fSNan Zhou             objectPath + '/' + std::to_string(tempCertIdCounter);
3306ec13c8fSNan Zhou         tempCertificates.emplace_back(std::make_unique<Certificate>(
3316ec13c8fSNan Zhou             bus, certObjectPath, certType, tempPath, *x509Store, authority,
3326ec13c8fSNan Zhou             certWatchPtr.get(), *this));
3336ec13c8fSNan Zhou         tempCertIdCounter++;
3346ec13c8fSNan Zhou     }
3356ec13c8fSNan Zhou 
3366ec13c8fSNan Zhou     // We are good now, issue swap
3376ec13c8fSNan Zhou     installedCerts = std::move(tempCertificates);
3386ec13c8fSNan Zhou     certIdCounter = tempCertIdCounter;
3396ec13c8fSNan Zhou     // Rename all the certificates including the authorities list
3406ec13c8fSNan Zhou     for (const fs::path& f : fs::directory_iterator(tempPath))
3416ec13c8fSNan Zhou     {
3426ec13c8fSNan Zhou         if (fs::is_symlink(f))
3436ec13c8fSNan Zhou         {
3446ec13c8fSNan Zhou             continue;
3456ec13c8fSNan Zhou         }
3466ec13c8fSNan Zhou         fs::rename(/*from=*/f, /*to=*/certInstallPath / f.filename());
3476ec13c8fSNan Zhou     }
3486ec13c8fSNan Zhou     // Update file locations and create symbol links
3496ec13c8fSNan Zhou     for (const auto& cert : installedCerts)
3506ec13c8fSNan Zhou     {
3516ec13c8fSNan Zhou         cert->setCertInstallPath(certInstallPath);
3526ec13c8fSNan Zhou         cert->setCertFilePath(certInstallPath /
3536ec13c8fSNan Zhou                               fs::path(cert->getCertFilePath()).filename());
3546ec13c8fSNan Zhou         cert->storageUpdate();
3556ec13c8fSNan Zhou     }
3566ec13c8fSNan Zhou     // Remove the temporary folder
3576ec13c8fSNan Zhou     fs::remove_all(tempPath);
3586ec13c8fSNan Zhou 
3596ec13c8fSNan Zhou     std::vector<sdbusplus::message::object_path> objects;
3606ec13c8fSNan Zhou     for (const auto& certificate : installedCerts)
3616ec13c8fSNan Zhou     {
3626ec13c8fSNan Zhou         objects.emplace_back(certificate->getObjectPath());
3636ec13c8fSNan Zhou     }
3646ec13c8fSNan Zhou 
365*78357b0aSNan Zhou     log<level::INFO>("Finishes authority list install; reload units starts");
3666ec13c8fSNan Zhou     reloadOrReset(unitToRestart);
3676ec13c8fSNan Zhou     return objects;
3686ec13c8fSNan Zhou }
3696ec13c8fSNan Zhou 
3706ec13c8fSNan Zhou std::vector<sdbusplus::message::object_path>
3716ec13c8fSNan Zhou     Manager::replaceAll(std::string filePath)
3726ec13c8fSNan Zhou {
3736ec13c8fSNan Zhou     installedCerts.clear();
3746ec13c8fSNan Zhou     certIdCounter = 1;
3756ec13c8fSNan Zhou     storageUpdate();
3766ec13c8fSNan Zhou     return installAll(std::move(filePath));
3776ec13c8fSNan Zhou }
3786ec13c8fSNan Zhou 
379a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
380ae70b3daSDeepak Kodihalli {
3816ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
3826ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
3836ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
3846ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
3856ceec40bSMarri Devender Rao     // deletion of certificates
386db029c95SKowalski, Kamil     installedCerts.clear();
3876ec13c8fSNan Zhou     // If the authorities list exists, delete it as well
3886ec13c8fSNan Zhou     if (certType == CertificateType::Authority)
3896ec13c8fSNan Zhou     {
3906ec13c8fSNan Zhou         if (fs::path authoritiesList =
3916ec13c8fSNan Zhou                 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
3926ec13c8fSNan Zhou             fs::exists(authoritiesList))
3936ec13c8fSNan Zhou         {
3946ec13c8fSNan Zhou             fs::remove(authoritiesList);
3956ec13c8fSNan Zhou         }
3966ec13c8fSNan Zhou     }
3976ec13c8fSNan Zhou     certIdCounter = 1;
3982f3563ccSZbigniew Lukwinski     storageUpdate();
3992f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
400ae70b3daSDeepak Kodihalli }
401f4682712SMarri Devender Rao 
4022f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
403a3bb38fbSZbigniew Kurzynski {
404a3bb38fbSZbigniew Kurzynski     std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
405a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
4062f3563ccSZbigniew Lukwinski                      [certificate](std::unique_ptr<Certificate> const& cert) {
4072f3563ccSZbigniew Lukwinski                          return (cert.get() == certificate);
408a3bb38fbSZbigniew Kurzynski                      });
409a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
410a3bb38fbSZbigniew Kurzynski     {
411a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
4122f3563ccSZbigniew Lukwinski         storageUpdate();
4132f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
414a3bb38fbSZbigniew Kurzynski     }
415a3bb38fbSZbigniew Kurzynski     else
416a3bb38fbSZbigniew Kurzynski     {
417a3bb38fbSZbigniew Kurzynski         log<level::ERR>("Certificate does not exist",
4182f3563ccSZbigniew Lukwinski                         entry("ID=%s", certificate->getCertId().c_str()));
4192f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
4202f3563ccSZbigniew Lukwinski     }
4212f3563ccSZbigniew Lukwinski }
4222f3563ccSZbigniew Lukwinski 
4232f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
4242f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
4252f3563ccSZbigniew Lukwinski {
4262f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
4272f3563ccSZbigniew Lukwinski     {
4282f3563ccSZbigniew Lukwinski         certificate->install(filePath);
4292f3563ccSZbigniew Lukwinski         storageUpdate();
4302f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
4312f3563ccSZbigniew Lukwinski     }
4322f3563ccSZbigniew Lukwinski     else
4332f3563ccSZbigniew Lukwinski     {
434cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
435a3bb38fbSZbigniew Kurzynski     }
436a3bb38fbSZbigniew Kurzynski }
437a3bb38fbSZbigniew Kurzynski 
438f4682712SMarri Devender Rao std::string Manager::generateCSR(
439f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
440f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
441f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
442f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
443f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
444f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
445f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
446f4682712SMarri Devender Rao {
447f4682712SMarri Devender Rao     // We support only one CSR.
448f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
449f4682712SMarri Devender Rao     auto pid = fork();
450f4682712SMarri Devender Rao     if (pid == -1)
451f4682712SMarri Devender Rao     {
452f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
453f4682712SMarri Devender Rao         report<InternalFailure>();
454f4682712SMarri Devender Rao     }
455f4682712SMarri Devender Rao     else if (pid == 0)
456f4682712SMarri Devender Rao     {
457f4682712SMarri Devender Rao         try
458f4682712SMarri Devender Rao         {
459f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
460f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
461f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
462f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
463f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
464f4682712SMarri Devender Rao                               unstructuredName);
465f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
466f4682712SMarri Devender Rao         }
467f4682712SMarri Devender Rao         catch (const InternalFailure& e)
468f4682712SMarri Devender Rao         {
469f4682712SMarri Devender Rao             // commit the error reported in child process and exit
470f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
471f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
472f4682712SMarri Devender Rao             commit<InternalFailure>();
473f4682712SMarri Devender Rao         }
474d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
475d2393f23SRamesh Iyyar         {
476d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
477d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
478d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
479d2393f23SRamesh Iyyar             commit<InvalidArgument>();
480d2393f23SRamesh Iyyar         }
481f4682712SMarri Devender Rao     }
482f4682712SMarri Devender Rao     else
483f4682712SMarri Devender Rao     {
484f4682712SMarri Devender Rao         using namespace sdeventplus::source;
485f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
486f4682712SMarri Devender Rao                                           const siginfo_t* si) {
487f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
488f4682712SMarri Devender Rao             if (si->si_status != 0)
489f4682712SMarri Devender Rao             {
490f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
491f4682712SMarri Devender Rao             }
492f4682712SMarri Devender Rao             else
493f4682712SMarri Devender Rao             {
494f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
495f4682712SMarri Devender Rao             }
496f4682712SMarri Devender Rao         };
497f4682712SMarri Devender Rao         try
498f4682712SMarri Devender Rao         {
499f4682712SMarri Devender Rao             sigset_t ss;
500f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
501f4682712SMarri Devender Rao             {
502f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
503f4682712SMarri Devender Rao                 elog<InternalFailure>();
504f4682712SMarri Devender Rao             }
505f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
506f4682712SMarri Devender Rao             {
507f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
508f4682712SMarri Devender Rao                 elog<InternalFailure>();
509f4682712SMarri Devender Rao             }
510f4682712SMarri Devender Rao 
511f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
512cfb5802aSNan Zhou             if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
513f4682712SMarri Devender Rao             {
514f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
515f4682712SMarri Devender Rao                 elog<InternalFailure>();
516f4682712SMarri Devender Rao             }
517f4682712SMarri Devender Rao             if (childPtr)
518f4682712SMarri Devender Rao             {
519f4682712SMarri Devender Rao                 childPtr.reset();
520f4682712SMarri Devender Rao             }
521f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
522f4682712SMarri Devender Rao                                                std::move(callback));
523f4682712SMarri Devender Rao         }
524f4682712SMarri Devender Rao         catch (const InternalFailure& e)
525f4682712SMarri Devender Rao         {
526f4682712SMarri Devender Rao             commit<InternalFailure>();
527f4682712SMarri Devender Rao         }
528f4682712SMarri Devender Rao     }
529f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
530f4682712SMarri Devender Rao     return csrObjectPath;
531f4682712SMarri Devender Rao }
532f4682712SMarri Devender Rao 
533db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
534ffad1ef1SMarri Devender Rao {
535db029c95SKowalski, Kamil     return installedCerts;
536ffad1ef1SMarri Devender Rao }
537ffad1ef1SMarri Devender Rao 
538f4682712SMarri Devender Rao void Manager::generateCSRHelper(
539f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
540f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
541f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
542f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
543f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
544f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
545f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
546f4682712SMarri Devender Rao {
547f4682712SMarri Devender Rao     int ret = 0;
548f4682712SMarri Devender Rao 
549f4682712SMarri Devender Rao     // set version of x509 req
550f4682712SMarri Devender Rao     int nVersion = 1;
551f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
552cf06ccdcSNan Zhou     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
553f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
554f4682712SMarri Devender Rao     if (ret == 0)
555f4682712SMarri Devender Rao     {
556bf3cf751SNan Zhou         log<level::ERR>("Error occurred during X509_REQ_set_version call");
557f4682712SMarri Devender Rao         elog<InternalFailure>();
558f4682712SMarri Devender Rao     }
559f4682712SMarri Devender Rao 
560f4682712SMarri Devender Rao     // set subject of x509 req
561f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
562f4682712SMarri Devender Rao 
563f4682712SMarri Devender Rao     if (!alternativeNames.empty())
564f4682712SMarri Devender Rao     {
565f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
566f4682712SMarri Devender Rao         {
567f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
568f4682712SMarri Devender Rao         }
569f4682712SMarri Devender Rao     }
570f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
571f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
572f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
573f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
574f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
575f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
576f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
577f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
578f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
579f4682712SMarri Devender Rao     if (!keyUsage.empty())
580f4682712SMarri Devender Rao     {
581f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
582f4682712SMarri Devender Rao         {
5837641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
5847641105dSMarri Devender Rao             {
5857641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
5867641105dSMarri Devender Rao             }
5877641105dSMarri Devender Rao             else
5887641105dSMarri Devender Rao             {
589f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
590f4682712SMarri Devender Rao             }
591f4682712SMarri Devender Rao         }
5927641105dSMarri Devender Rao     }
593f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
594dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
595f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
596f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
597f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
598f4682712SMarri Devender Rao 
599cf06ccdcSNan Zhou     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
6008a09b52aSRamesh Iyyar 
6018a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
6028a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
6038a09b52aSRamesh Iyyar 
6048a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
6058a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
606c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
6078a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
608c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
6098a09b52aSRamesh Iyyar     else
6108a09b52aSRamesh Iyyar     {
6118a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
6128a09b52aSRamesh Iyyar                         "RSA and EC only");
6138a09b52aSRamesh Iyyar         elog<InvalidArgument>(
6148a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
6158a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
6168a09b52aSRamesh Iyyar     }
6178a09b52aSRamesh Iyyar 
6188a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
6198a09b52aSRamesh Iyyar     if (ret == 0)
6208a09b52aSRamesh Iyyar     {
621bf3cf751SNan Zhou         log<level::ERR>("Error occurred while setting Public key");
6228a09b52aSRamesh Iyyar         elog<InternalFailure>();
6238a09b52aSRamesh Iyyar     }
6248a09b52aSRamesh Iyyar 
6258a09b52aSRamesh Iyyar     // Write private key to file
626718eef37SNan Zhou     writePrivateKey(pKey, defaultPrivateKeyFileName);
627f4682712SMarri Devender Rao 
628f4682712SMarri Devender Rao     // set sign key of x509 req
629f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
6308a09b52aSRamesh Iyyar     if (ret == 0)
631f4682712SMarri Devender Rao     {
632bf3cf751SNan Zhou         log<level::ERR>("Error occurred while signing key of x509");
633f4682712SMarri Devender Rao         elog<InternalFailure>();
634f4682712SMarri Devender Rao     }
6358a09b52aSRamesh Iyyar 
636f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
637718eef37SNan Zhou     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
638c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
639f4682712SMarri Devender Rao }
640f4682712SMarri Devender Rao 
6417641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
6427641105dSMarri Devender Rao {
6437641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
6447641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
6457641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
6467641105dSMarri Devender Rao     auto it = std::find_if(
6477641105dSMarri Devender Rao         usageList.begin(), usageList.end(),
6487641105dSMarri Devender Rao         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
6497641105dSMarri Devender Rao     return it != usageList.end();
6507641105dSMarri Devender Rao }
651cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
652f4682712SMarri Devender Rao {
6538a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
654f4682712SMarri Devender Rao     // set keybit length to default value if not set
6558a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
656f4682712SMarri Devender Rao     {
6578a09b52aSRamesh Iyyar         log<level::INFO>(
6588a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
659cf06ccdcSNan Zhou             entry("DEFAULTKEYBITLENGTH=%d", defaultKeyBitLength));
660cf06ccdcSNan Zhou         keyBitLen = defaultKeyBitLength;
661f4682712SMarri Devender Rao     }
66226fb83efSPatrick Williams 
66326fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
66426fb83efSPatrick Williams 
66526fb83efSPatrick Williams     // generate rsa key
666cf06ccdcSNan Zhou     BignumPtr bne(BN_new(), ::BN_free);
66726fb83efSPatrick Williams     auto ret = BN_set_word(bne.get(), RSA_F4);
66826fb83efSPatrick Williams     if (ret == 0)
66926fb83efSPatrick Williams     {
670bf3cf751SNan Zhou         log<level::ERR>("Error occurred during BN_set_word call");
67126fb83efSPatrick Williams         elog<InternalFailure>();
67226fb83efSPatrick Williams     }
673762da74eSNan Zhou     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
674762da74eSNan Zhou     RSAPtr rsa(RSA_new(), ::RSA_free);
675762da74eSNan Zhou     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
676f4682712SMarri Devender Rao     if (ret != 1)
677f4682712SMarri Devender Rao     {
678bf3cf751SNan Zhou         log<level::ERR>("Error occurred during RSA_generate_key_ex call",
6798a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
680f4682712SMarri Devender Rao         elog<InternalFailure>();
681f4682712SMarri Devender Rao     }
682f4682712SMarri Devender Rao 
683f4682712SMarri Devender Rao     // set public key of x509 req
684cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
685762da74eSNan Zhou     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
686f4682712SMarri Devender Rao     if (ret == 0)
687f4682712SMarri Devender Rao     {
688bf3cf751SNan Zhou         log<level::ERR>("Error occurred during assign rsa key into EVP");
689f4682712SMarri Devender Rao         elog<InternalFailure>();
690f4682712SMarri Devender Rao     }
691762da74eSNan Zhou     // Now |rsa| is managed by |pKey|
692762da74eSNan Zhou     rsa.release();
6938a09b52aSRamesh Iyyar     return pKey;
69426fb83efSPatrick Williams 
69526fb83efSPatrick Williams #else
69626fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
69726fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
69826fb83efSPatrick Williams     if (!ctx)
69926fb83efSPatrick Williams     {
700bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm");
70126fb83efSPatrick Williams         elog<InternalFailure>();
70226fb83efSPatrick Williams     }
70326fb83efSPatrick Williams 
70426fb83efSPatrick Williams     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
70526fb83efSPatrick Williams         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
70626fb83efSPatrick Williams 
70726fb83efSPatrick Williams     {
708bf3cf751SNan Zhou         log<level::ERR>("Error occurred initializing keygen context");
70926fb83efSPatrick Williams         elog<InternalFailure>();
71026fb83efSPatrick Williams     }
71126fb83efSPatrick Williams 
71226fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
71326fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
71426fb83efSPatrick Williams     {
715bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
71626fb83efSPatrick Williams         elog<InternalFailure>();
71726fb83efSPatrick Williams     }
71826fb83efSPatrick Williams 
71926fb83efSPatrick Williams     return {pKey, &::EVP_PKEY_free};
72026fb83efSPatrick Williams #endif
7218a09b52aSRamesh Iyyar }
7228a09b52aSRamesh Iyyar 
723cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
7248a09b52aSRamesh Iyyar {
7258a09b52aSRamesh Iyyar     std::string curId(curveId);
7268a09b52aSRamesh Iyyar 
7278a09b52aSRamesh Iyyar     if (curId.empty())
7288a09b52aSRamesh Iyyar     {
7298a09b52aSRamesh Iyyar         log<level::INFO>(
7308a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
731cf06ccdcSNan Zhou             entry("DEFAULTKEYCURVEID=%s", defaultKeyCurveID));
732cf06ccdcSNan Zhou         curId = defaultKeyCurveID;
7338a09b52aSRamesh Iyyar     }
7348a09b52aSRamesh Iyyar 
7358a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
7368a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
7378a09b52aSRamesh Iyyar     {
7388a09b52aSRamesh Iyyar         log<level::ERR>(
739bf3cf751SNan Zhou             "Error occurred during convert the curve id string format into NID",
7408a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
7418a09b52aSRamesh Iyyar         elog<InternalFailure>();
7428a09b52aSRamesh Iyyar     }
7438a09b52aSRamesh Iyyar 
74426fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
74526fb83efSPatrick Williams 
7468a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
7478a09b52aSRamesh Iyyar 
748cfb5802aSNan Zhou     if (ecKey == nullptr)
7498a09b52aSRamesh Iyyar     {
7508a09b52aSRamesh Iyyar         log<level::ERR>(
751bf3cf751SNan Zhou             "Error occurred during create the EC_Key object from NID",
7528a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
7538a09b52aSRamesh Iyyar         elog<InternalFailure>();
7548a09b52aSRamesh Iyyar     }
7558a09b52aSRamesh Iyyar 
7568a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
7578a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
7588a09b52aSRamesh Iyyar     // flag on the key.
7598a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
7608a09b52aSRamesh Iyyar 
7618a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
7628a09b52aSRamesh Iyyar 
7638a09b52aSRamesh Iyyar     if (ret == 0)
7648a09b52aSRamesh Iyyar     {
7658a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
766bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
7678a09b52aSRamesh Iyyar         elog<InternalFailure>();
7688a09b52aSRamesh Iyyar     }
7698a09b52aSRamesh Iyyar 
770cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
7718a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
7728a09b52aSRamesh Iyyar     if (ret == 0)
7738a09b52aSRamesh Iyyar     {
7748a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
775bf3cf751SNan Zhou         log<level::ERR>("Error occurred during assign EC Key into EVP");
7768a09b52aSRamesh Iyyar         elog<InternalFailure>();
7778a09b52aSRamesh Iyyar     }
7788a09b52aSRamesh Iyyar 
7798a09b52aSRamesh Iyyar     return pKey;
78026fb83efSPatrick Williams 
78126fb83efSPatrick Williams #else
78226fb83efSPatrick Williams     auto holder_of_key = [](EVP_PKEY* key) {
78326fb83efSPatrick Williams         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
78426fb83efSPatrick Williams             key, &::EVP_PKEY_free};
78526fb83efSPatrick Williams     };
78626fb83efSPatrick Williams 
78726fb83efSPatrick Williams     // Create context to set up curve parameters.
78826fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
78926fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
79026fb83efSPatrick Williams     if (!ctx)
79126fb83efSPatrick Williams     {
792bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params");
79326fb83efSPatrick Williams         elog<InternalFailure>();
79426fb83efSPatrick Williams     }
79526fb83efSPatrick Williams 
79626fb83efSPatrick Williams     // Set up curve parameters.
79726fb83efSPatrick Williams     EVP_PKEY* params = nullptr;
79826fb83efSPatrick Williams 
79926fb83efSPatrick Williams     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
80026fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
80126fb83efSPatrick Williams          0) ||
80226fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
80326fb83efSPatrick Williams         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
80426fb83efSPatrick Williams     {
805bf3cf751SNan Zhou         log<level::ERR>("Error occurred setting curve parameters");
80626fb83efSPatrick Williams         elog<InternalFailure>();
80726fb83efSPatrick Williams     }
80826fb83efSPatrick Williams 
80926fb83efSPatrick Williams     // Move parameters to RAII holder.
81026fb83efSPatrick Williams     auto pparms = holder_of_key(params);
81126fb83efSPatrick Williams 
81226fb83efSPatrick Williams     // Create new context for key.
81326fb83efSPatrick Williams     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
81426fb83efSPatrick Williams 
81526fb83efSPatrick Williams     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
81626fb83efSPatrick Williams     {
817bf3cf751SNan Zhou         log<level::ERR>("Error occurred initializing keygen context");
81826fb83efSPatrick Williams         elog<InternalFailure>();
81926fb83efSPatrick Williams     }
82026fb83efSPatrick Williams 
82126fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
82226fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
82326fb83efSPatrick Williams     {
824bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
82526fb83efSPatrick Williams         elog<InternalFailure>();
82626fb83efSPatrick Williams     }
82726fb83efSPatrick Williams 
82826fb83efSPatrick Williams     return holder_of_key(pKey);
82926fb83efSPatrick Williams #endif
8308a09b52aSRamesh Iyyar }
8318a09b52aSRamesh Iyyar 
832cf06ccdcSNan Zhou void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
833c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
8348a09b52aSRamesh Iyyar {
8358a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
836f4682712SMarri Devender Rao     // write private key to file
837c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
838f4682712SMarri Devender Rao 
839f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
840cfb5802aSNan Zhou     if (fp == nullptr)
841f4682712SMarri Devender Rao     {
842bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating private key file");
843f4682712SMarri Devender Rao         elog<InternalFailure>();
844f4682712SMarri Devender Rao     }
845cfb5802aSNan Zhou     int ret =
846cfb5802aSNan Zhou         PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr);
847f4682712SMarri Devender Rao     std::fclose(fp);
848f4682712SMarri Devender Rao     if (ret == 0)
849f4682712SMarri Devender Rao     {
850bf3cf751SNan Zhou         log<level::ERR>("Error occurred while writing private key to file");
851f4682712SMarri Devender Rao         elog<InternalFailure>();
852f4682712SMarri Devender Rao     }
853f4682712SMarri Devender Rao }
854f4682712SMarri Devender Rao 
855f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
856f4682712SMarri Devender Rao                        const std::string& bytes)
857f4682712SMarri Devender Rao {
858f4682712SMarri Devender Rao     if (bytes.empty())
859f4682712SMarri Devender Rao     {
860f4682712SMarri Devender Rao         return;
861f4682712SMarri Devender Rao     }
862f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
863f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
864f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
865f4682712SMarri Devender Rao     if (ret != 1)
866f4682712SMarri Devender Rao     {
867f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
868f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
869f4682712SMarri Devender Rao         elog<InternalFailure>();
870f4682712SMarri Devender Rao     }
871f4682712SMarri Devender Rao }
872f4682712SMarri Devender Rao 
873f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
874f4682712SMarri Devender Rao {
875f4682712SMarri Devender Rao     if (csrPtr)
876f4682712SMarri Devender Rao     {
877f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
878f4682712SMarri Devender Rao     }
879f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
880f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
881f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
882f4682712SMarri Devender Rao }
883f4682712SMarri Devender Rao 
884cf06ccdcSNan Zhou void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
885f4682712SMarri Devender Rao {
886f4682712SMarri Devender Rao     if (fs::exists(filePath))
887f4682712SMarri Devender Rao     {
888f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
889f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
890f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
891f4682712SMarri Devender Rao         {
892f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
893f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
894f4682712SMarri Devender Rao             elog<InternalFailure>();
895f4682712SMarri Devender Rao         }
896f4682712SMarri Devender Rao     }
897f4682712SMarri Devender Rao 
898cfb5802aSNan Zhou     FILE* fp = nullptr;
899f4682712SMarri Devender Rao 
900cfb5802aSNan Zhou     if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
901f4682712SMarri Devender Rao     {
902f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
903f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
904f4682712SMarri Devender Rao         elog<InternalFailure>();
905f4682712SMarri Devender Rao     }
906f4682712SMarri Devender Rao 
907f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
908f4682712SMarri Devender Rao     if (!rc)
909f4682712SMarri Devender Rao     {
910f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
911f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
912f4682712SMarri Devender Rao         std::fclose(fp);
913f4682712SMarri Devender Rao         elog<InternalFailure>();
914f4682712SMarri Devender Rao     }
915f4682712SMarri Devender Rao     std::fclose(fp);
916f4682712SMarri Devender Rao }
917f4682712SMarri Devender Rao 
918db029c95SKowalski, Kamil void Manager::createCertificates()
919db029c95SKowalski, Kamil {
920db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
921db029c95SKowalski, Kamil 
922cf06ccdcSNan Zhou     if (certType == CertificateType::Authority)
923db029c95SKowalski, Kamil     {
924fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
925db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
926db029c95SKowalski, Kamil         {
927db029c95SKowalski, Kamil             log<level::ERR>("Certificate installation path exists and it is "
928db029c95SKowalski, Kamil                             "not a directory");
929db029c95SKowalski, Kamil             elog<InternalFailure>();
9306ec13c8fSNan Zhou         }
9316ec13c8fSNan Zhou 
9326ec13c8fSNan Zhou         // If the authorities list exists, recover from it and return
9336ec13c8fSNan Zhou         if (fs::path authoritiesListFilePath =
9346ec13c8fSNan Zhou                 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
9356ec13c8fSNan Zhou             fs::exists(authoritiesListFilePath))
9366ec13c8fSNan Zhou         {
9376ec13c8fSNan Zhou             // remove all other files and directories
9386ec13c8fSNan Zhou             for (auto& path : fs::directory_iterator(certInstallPath))
9396ec13c8fSNan Zhou             {
9406ec13c8fSNan Zhou                 if (path.path() != authoritiesListFilePath)
9416ec13c8fSNan Zhou                 {
9426ec13c8fSNan Zhou                     fs::remove_all(path);
9436ec13c8fSNan Zhou                 }
9446ec13c8fSNan Zhou             }
9456ec13c8fSNan Zhou             installAll(authoritiesListFilePath);
946db029c95SKowalski, Kamil             return;
947db029c95SKowalski, Kamil         }
948db029c95SKowalski, Kamil 
949db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
950ffad1ef1SMarri Devender Rao         {
951ffad1ef1SMarri Devender Rao             try
952ffad1ef1SMarri Devender Rao             {
9532f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
9542f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
9552f3563ccSZbigniew Lukwinski                 // would add value.
9562f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
9572f3563ccSZbigniew Lukwinski                 {
958db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
959db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
960cf06ccdcSNan Zhou                         certType, certInstallPath, path.path(),
961cf06ccdcSNan Zhou                         certWatchPtr.get(), *this));
9622f3563ccSZbigniew Lukwinski                 }
963ffad1ef1SMarri Devender Rao             }
964ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
965ffad1ef1SMarri Devender Rao             {
966ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
967ffad1ef1SMarri Devender Rao             }
968ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
969ffad1ef1SMarri Devender Rao             {
970cf06ccdcSNan Zhou                 report<InvalidCertificate>(InvalidCertificateReason(
971cf06ccdcSNan Zhou                     "Existing certificate file is corrupted"));
972ffad1ef1SMarri Devender Rao             }
973ffad1ef1SMarri Devender Rao         }
974db029c95SKowalski, Kamil     }
975db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
976db029c95SKowalski, Kamil     {
977db029c95SKowalski, Kamil         try
978db029c95SKowalski, Kamil         {
979db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
9802f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
981cf06ccdcSNan Zhou                 certInstallPath, certWatchPtr.get(), *this));
982db029c95SKowalski, Kamil         }
983db029c95SKowalski, Kamil         catch (const InternalFailure& e)
984db029c95SKowalski, Kamil         {
985db029c95SKowalski, Kamil             report<InternalFailure>();
986db029c95SKowalski, Kamil         }
987db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
988db029c95SKowalski, Kamil         {
989cf06ccdcSNan Zhou             report<InvalidCertificate>(InvalidCertificateReason(
990cf06ccdcSNan Zhou                 "Existing certificate file is corrupted"));
991db029c95SKowalski, Kamil         }
992db029c95SKowalski, Kamil     }
993db029c95SKowalski, Kamil }
994c6e58c7eSRamesh Iyyar 
995c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
996c6e58c7eSRamesh Iyyar {
997c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
998718eef37SNan Zhou         certParentInstallPath / defaultRSAPrivateKeyFileName;
999c6e58c7eSRamesh Iyyar 
1000c6e58c7eSRamesh Iyyar     try
1001c6e58c7eSRamesh Iyyar     {
1002c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
1003c6e58c7eSRamesh Iyyar         {
1004cf06ccdcSNan Zhou             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
1005718eef37SNan Zhou                             defaultRSAPrivateKeyFileName);
1006c6e58c7eSRamesh Iyyar         }
1007c6e58c7eSRamesh Iyyar     }
1008c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
1009c6e58c7eSRamesh Iyyar     {
1010c6e58c7eSRamesh Iyyar         report<InternalFailure>();
1011c6e58c7eSRamesh Iyyar     }
1012c6e58c7eSRamesh Iyyar }
1013c6e58c7eSRamesh Iyyar 
1014cf06ccdcSNan Zhou EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
1015c6e58c7eSRamesh Iyyar {
1016cf06ccdcSNan Zhou     if (keyBitLength != supportedKeyBitLength)
1017c6e58c7eSRamesh Iyyar     {
1018c6e58c7eSRamesh Iyyar         log<level::ERR>(
1019c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
1020c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
1021cf06ccdcSNan Zhou             entry("SUPPORTEDKEYBITLENGTH=%d", supportedKeyBitLength));
1022c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
1023c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1024c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1025c6e58c7eSRamesh Iyyar     }
1026c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
1027718eef37SNan Zhou         certParentInstallPath / defaultRSAPrivateKeyFileName;
1028c6e58c7eSRamesh Iyyar 
1029c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1030c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
1031c6e58c7eSRamesh Iyyar     {
1032c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
1033c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
1034c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
1035c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1036c6e58c7eSRamesh Iyyar     }
1037c6e58c7eSRamesh Iyyar 
1038cf06ccdcSNan Zhou     EVPPkeyPtr privateKey(
1039c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1040c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
1041c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
1042c6e58c7eSRamesh Iyyar 
1043c6e58c7eSRamesh Iyyar     if (!privateKey)
1044c6e58c7eSRamesh Iyyar     {
1045bf3cf751SNan Zhou         log<level::ERR>("Error occurred during PEM_read_PrivateKey call");
1046c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1047c6e58c7eSRamesh Iyyar     }
1048c6e58c7eSRamesh Iyyar     return privateKey;
1049c6e58c7eSRamesh Iyyar }
10502f3563ccSZbigniew Lukwinski 
10512f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
10522f3563ccSZbigniew Lukwinski {
1053cf06ccdcSNan Zhou     if (certType == CertificateType::Authority)
10542f3563ccSZbigniew Lukwinski     {
10552f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
10562f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
10572f3563ccSZbigniew Lukwinski         {
10582f3563ccSZbigniew Lukwinski             try
10592f3563ccSZbigniew Lukwinski             {
10602f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
10612f3563ccSZbigniew Lukwinski                 {
10622f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
10632f3563ccSZbigniew Lukwinski                 }
10642f3563ccSZbigniew Lukwinski             }
10652f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
10662f3563ccSZbigniew Lukwinski             {
10672f3563ccSZbigniew Lukwinski                 log<level::ERR>(
10682f3563ccSZbigniew Lukwinski                     "Failed to remove symlink for certificate",
10692f3563ccSZbigniew Lukwinski                     entry("ERR=%s", e.what()),
10702f3563ccSZbigniew Lukwinski                     entry("SYMLINK=%s", certPath.path().string().c_str()));
10712f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
10722f3563ccSZbigniew Lukwinski             }
10732f3563ccSZbigniew Lukwinski         }
10742f3563ccSZbigniew Lukwinski     }
10752f3563ccSZbigniew Lukwinski 
10762f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
10772f3563ccSZbigniew Lukwinski     {
10782f3563ccSZbigniew Lukwinski         cert->storageUpdate();
10792f3563ccSZbigniew Lukwinski     }
10802f3563ccSZbigniew Lukwinski }
10812f3563ccSZbigniew Lukwinski 
1082cf06ccdcSNan Zhou void Manager::reloadOrReset(const std::string& unit)
10832f3563ccSZbigniew Lukwinski {
10842f3563ccSZbigniew Lukwinski     if (!unit.empty())
10852f3563ccSZbigniew Lukwinski     {
10862f3563ccSZbigniew Lukwinski         try
10872f3563ccSZbigniew Lukwinski         {
1088cf06ccdcSNan Zhou             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1089cf06ccdcSNan Zhou             constexpr auto defaultSystemdObjectPath =
1090cf06ccdcSNan Zhou                 "/org/freedesktop/systemd1";
1091cf06ccdcSNan Zhou             constexpr auto defaultSystemdInterface =
10922f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
1093cf06ccdcSNan Zhou             auto method = bus.new_method_call(
1094cf06ccdcSNan Zhou                 defaultSystemdService, defaultSystemdObjectPath,
1095cf06ccdcSNan Zhou                 defaultSystemdInterface, "ReloadOrRestartUnit");
10962f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
10972f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
10982f3563ccSZbigniew Lukwinski         }
1099ca128117SPatrick Williams         catch (const sdbusplus::exception::exception& e)
11002f3563ccSZbigniew Lukwinski         {
11012f3563ccSZbigniew Lukwinski             log<level::ERR>("Failed to reload or restart service",
11022f3563ccSZbigniew Lukwinski                             entry("ERR=%s", e.what()),
11032f3563ccSZbigniew Lukwinski                             entry("UNIT=%s", unit.c_str()));
11042f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
11052f3563ccSZbigniew Lukwinski         }
11062f3563ccSZbigniew Lukwinski     }
11072f3563ccSZbigniew Lukwinski }
11082f3563ccSZbigniew Lukwinski 
11092f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
11102f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
11112f3563ccSZbigniew Lukwinski {
11122f3563ccSZbigniew Lukwinski     if (std::any_of(
11132f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
11142f3563ccSZbigniew Lukwinski             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
11152f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
11162f3563ccSZbigniew Lukwinski             }))
11172f3563ccSZbigniew Lukwinski     {
11182f3563ccSZbigniew Lukwinski         return false;
11192f3563ccSZbigniew Lukwinski     }
11202f3563ccSZbigniew Lukwinski     else
11212f3563ccSZbigniew Lukwinski     {
11222f3563ccSZbigniew Lukwinski         return true;
11232f3563ccSZbigniew Lukwinski     }
11242f3563ccSZbigniew Lukwinski }
11252f3563ccSZbigniew Lukwinski 
1126e1289adfSNan Zhou } // namespace phosphor::certs
1127