xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 6ec13c8f759962d29c0ac3a69b64de705116065d)
1014be0bfSNan Zhou #include "config.h"
2014be0bfSNan Zhou 
3cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
4cfbc8dc8SJayanth Othayoth 
5*6ec13c8fSNan Zhou #include "x509_utils.hpp"
6*6ec13c8fSNan 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>
27*6ec13c8fSNan 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)>;
67*6ec13c8fSNan 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";
73*6ec13c8fSNan Zhou // PEM certificate block markers, defined in go/rfc/7468.
74*6ec13c8fSNan Zhou constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
75*6ec13c8fSNan Zhou constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
76*6ec13c8fSNan Zhou 
77*6ec13c8fSNan Zhou /**
78*6ec13c8fSNan Zhou  * @brief Splits the given authorities list file and returns an array of
79*6ec13c8fSNan Zhou  * individual PEM encoded x509 certificate.
80*6ec13c8fSNan Zhou  *
81*6ec13c8fSNan Zhou  * @param[in] sourceFilePath - Path to the authorities list file.
82*6ec13c8fSNan Zhou  *
83*6ec13c8fSNan Zhou  * @return An array of individual PEM encoded x509 certificate
84*6ec13c8fSNan Zhou  */
85*6ec13c8fSNan Zhou std::vector<std::string> splitCertificates(const std::string& sourceFilePath)
86*6ec13c8fSNan Zhou {
87*6ec13c8fSNan Zhou     std::ifstream inputCertFileStream;
88*6ec13c8fSNan Zhou     inputCertFileStream.exceptions(
89*6ec13c8fSNan Zhou         std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
90*6ec13c8fSNan Zhou 
91*6ec13c8fSNan Zhou     std::stringstream pemStream;
92*6ec13c8fSNan Zhou     std::vector<std::string> certificatesList;
93*6ec13c8fSNan Zhou     try
94*6ec13c8fSNan Zhou     {
95*6ec13c8fSNan Zhou         inputCertFileStream.open(sourceFilePath);
96*6ec13c8fSNan Zhou         pemStream << inputCertFileStream.rdbuf();
97*6ec13c8fSNan Zhou         inputCertFileStream.close();
98*6ec13c8fSNan Zhou     }
99*6ec13c8fSNan Zhou     catch (const std::exception& e)
100*6ec13c8fSNan Zhou     {
101*6ec13c8fSNan Zhou         log<level::ERR>("Failed to read certificates list",
102*6ec13c8fSNan Zhou                         entry("ERR=%s", e.what()),
103*6ec13c8fSNan Zhou                         entry("SRC=%s", sourceFilePath.c_str()));
104*6ec13c8fSNan Zhou         elog<InternalFailure>();
105*6ec13c8fSNan Zhou     }
106*6ec13c8fSNan Zhou     std::string pem = pemStream.str();
107*6ec13c8fSNan Zhou     size_t begin = 0;
108*6ec13c8fSNan Zhou     // |begin| points to the current start position for searching the next
109*6ec13c8fSNan Zhou     // |beginCertificate| block. When we find the beginning of the certificate,
110*6ec13c8fSNan Zhou     // we extract the content between the beginning and the end of the current
111*6ec13c8fSNan Zhou     // certificate. And finally we move |begin| to the end of the current
112*6ec13c8fSNan Zhou     // certificate to start searching the next potential certificate.
113*6ec13c8fSNan Zhou     for (begin = pem.find(beginCertificate, begin); begin != std::string::npos;
114*6ec13c8fSNan Zhou          begin = pem.find(beginCertificate, begin))
115*6ec13c8fSNan Zhou     {
116*6ec13c8fSNan Zhou         size_t end = pem.find(endCertificate, begin);
117*6ec13c8fSNan Zhou         if (end == std::string::npos)
118*6ec13c8fSNan Zhou         {
119*6ec13c8fSNan Zhou             log<level::ERR>(
120*6ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END");
121*6ec13c8fSNan Zhou             elog<InvalidCertificate>(InvalidCertificateReason(
122*6ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END"));
123*6ec13c8fSNan Zhou         }
124*6ec13c8fSNan Zhou         end += endCertificate.size();
125*6ec13c8fSNan Zhou         certificatesList.emplace_back(pem.substr(begin, end - begin));
126*6ec13c8fSNan Zhou         begin = end;
127*6ec13c8fSNan Zhou     }
128*6ec13c8fSNan Zhou     return certificatesList;
129*6ec13c8fSNan Zhou }
130*6ec13c8fSNan 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 
282*6ec13c8fSNan Zhou std::vector<sdbusplus::message::object_path>
283*6ec13c8fSNan Zhou     Manager::installAll(const std::string filePath)
284*6ec13c8fSNan Zhou {
285*6ec13c8fSNan Zhou     if (certType != CertificateType::Authority)
286*6ec13c8fSNan Zhou     {
287*6ec13c8fSNan Zhou         elog<NotAllowed>(
288*6ec13c8fSNan Zhou             NotAllowedReason("The InstallAll interface is only allowed for "
289*6ec13c8fSNan Zhou                              "Authority certificates"));
290*6ec13c8fSNan Zhou     }
291*6ec13c8fSNan Zhou 
292*6ec13c8fSNan Zhou     if (!installedCerts.empty())
293*6ec13c8fSNan Zhou     {
294*6ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason(
295*6ec13c8fSNan Zhou             "There are already root certificates; Call DeleteAll then "
296*6ec13c8fSNan Zhou             "InstallAll, or use ReplaceAll"));
297*6ec13c8fSNan Zhou     }
298*6ec13c8fSNan Zhou 
299*6ec13c8fSNan Zhou     fs::path sourceFile(filePath);
300*6ec13c8fSNan Zhou     if (!fs::exists(sourceFile))
301*6ec13c8fSNan Zhou     {
302*6ec13c8fSNan Zhou         log<level::ERR>("File is Missing", entry("FILE=%s", filePath.c_str()));
303*6ec13c8fSNan Zhou         elog<InternalFailure>();
304*6ec13c8fSNan Zhou     }
305*6ec13c8fSNan Zhou     std::vector<std::string> authorities = splitCertificates(sourceFile);
306*6ec13c8fSNan Zhou     if (authorities.size() > maxNumAuthorityCertificates)
307*6ec13c8fSNan Zhou     {
308*6ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
309*6ec13c8fSNan Zhou     }
310*6ec13c8fSNan Zhou 
311*6ec13c8fSNan Zhou     fs::path authorityStore(certInstallPath);
312*6ec13c8fSNan Zhou     fs::path authoritiesListFile =
313*6ec13c8fSNan Zhou         authorityStore / defaultAuthoritiesListFileName;
314*6ec13c8fSNan Zhou 
315*6ec13c8fSNan Zhou     // Atomically install all the certificates
316*6ec13c8fSNan Zhou     fs::path tempPath = Certificate::generateUniqueFilePath(authorityStore);
317*6ec13c8fSNan Zhou     fs::create_directory(tempPath);
318*6ec13c8fSNan Zhou     // Copies the authorities list
319*6ec13c8fSNan Zhou     Certificate::copyCertificate(sourceFile,
320*6ec13c8fSNan Zhou                                  tempPath / defaultAuthoritiesListFileName);
321*6ec13c8fSNan Zhou     std::vector<std::unique_ptr<Certificate>> tempCertificates;
322*6ec13c8fSNan Zhou     uint64_t tempCertIdCounter = certIdCounter;
323*6ec13c8fSNan Zhou     X509StorePtr x509Store = getX509Store(sourceFile);
324*6ec13c8fSNan Zhou     for (const auto& authority : authorities)
325*6ec13c8fSNan Zhou     {
326*6ec13c8fSNan Zhou         std::string certObjectPath =
327*6ec13c8fSNan Zhou             objectPath + '/' + std::to_string(tempCertIdCounter);
328*6ec13c8fSNan Zhou         tempCertificates.emplace_back(std::make_unique<Certificate>(
329*6ec13c8fSNan Zhou             bus, certObjectPath, certType, tempPath, *x509Store, authority,
330*6ec13c8fSNan Zhou             certWatchPtr.get(), *this));
331*6ec13c8fSNan Zhou         tempCertIdCounter++;
332*6ec13c8fSNan Zhou     }
333*6ec13c8fSNan Zhou 
334*6ec13c8fSNan Zhou     // We are good now, issue swap
335*6ec13c8fSNan Zhou     installedCerts = std::move(tempCertificates);
336*6ec13c8fSNan Zhou     certIdCounter = tempCertIdCounter;
337*6ec13c8fSNan Zhou     // Rename all the certificates including the authorities list
338*6ec13c8fSNan Zhou     for (const fs::path& f : fs::directory_iterator(tempPath))
339*6ec13c8fSNan Zhou     {
340*6ec13c8fSNan Zhou         if (fs::is_symlink(f))
341*6ec13c8fSNan Zhou         {
342*6ec13c8fSNan Zhou             continue;
343*6ec13c8fSNan Zhou         }
344*6ec13c8fSNan Zhou         fs::rename(/*from=*/f, /*to=*/certInstallPath / f.filename());
345*6ec13c8fSNan Zhou     }
346*6ec13c8fSNan Zhou     // Update file locations and create symbol links
347*6ec13c8fSNan Zhou     for (const auto& cert : installedCerts)
348*6ec13c8fSNan Zhou     {
349*6ec13c8fSNan Zhou         cert->setCertInstallPath(certInstallPath);
350*6ec13c8fSNan Zhou         cert->setCertFilePath(certInstallPath /
351*6ec13c8fSNan Zhou                               fs::path(cert->getCertFilePath()).filename());
352*6ec13c8fSNan Zhou         cert->storageUpdate();
353*6ec13c8fSNan Zhou     }
354*6ec13c8fSNan Zhou     // Remove the temporary folder
355*6ec13c8fSNan Zhou     fs::remove_all(tempPath);
356*6ec13c8fSNan Zhou 
357*6ec13c8fSNan Zhou     std::vector<sdbusplus::message::object_path> objects;
358*6ec13c8fSNan Zhou     for (const auto& certificate : installedCerts)
359*6ec13c8fSNan Zhou     {
360*6ec13c8fSNan Zhou         objects.emplace_back(certificate->getObjectPath());
361*6ec13c8fSNan Zhou     }
362*6ec13c8fSNan Zhou 
363*6ec13c8fSNan Zhou     reloadOrReset(unitToRestart);
364*6ec13c8fSNan Zhou     return objects;
365*6ec13c8fSNan Zhou }
366*6ec13c8fSNan Zhou 
367*6ec13c8fSNan Zhou std::vector<sdbusplus::message::object_path>
368*6ec13c8fSNan Zhou     Manager::replaceAll(std::string filePath)
369*6ec13c8fSNan Zhou {
370*6ec13c8fSNan Zhou     installedCerts.clear();
371*6ec13c8fSNan Zhou     certIdCounter = 1;
372*6ec13c8fSNan Zhou     storageUpdate();
373*6ec13c8fSNan Zhou     return installAll(std::move(filePath));
374*6ec13c8fSNan Zhou }
375*6ec13c8fSNan Zhou 
376a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
377ae70b3daSDeepak Kodihalli {
3786ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
3796ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
3806ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
3816ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
3826ceec40bSMarri Devender Rao     // deletion of certificates
383db029c95SKowalski, Kamil     installedCerts.clear();
384*6ec13c8fSNan Zhou     // If the authorities list exists, delete it as well
385*6ec13c8fSNan Zhou     if (certType == CertificateType::Authority)
386*6ec13c8fSNan Zhou     {
387*6ec13c8fSNan Zhou         if (fs::path authoritiesList =
388*6ec13c8fSNan Zhou                 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
389*6ec13c8fSNan Zhou             fs::exists(authoritiesList))
390*6ec13c8fSNan Zhou         {
391*6ec13c8fSNan Zhou             fs::remove(authoritiesList);
392*6ec13c8fSNan Zhou         }
393*6ec13c8fSNan Zhou     }
394*6ec13c8fSNan Zhou     certIdCounter = 1;
3952f3563ccSZbigniew Lukwinski     storageUpdate();
3962f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
397ae70b3daSDeepak Kodihalli }
398f4682712SMarri Devender Rao 
3992f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
400a3bb38fbSZbigniew Kurzynski {
401a3bb38fbSZbigniew Kurzynski     std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
402a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
4032f3563ccSZbigniew Lukwinski                      [certificate](std::unique_ptr<Certificate> const& cert) {
4042f3563ccSZbigniew Lukwinski                          return (cert.get() == certificate);
405a3bb38fbSZbigniew Kurzynski                      });
406a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
407a3bb38fbSZbigniew Kurzynski     {
408a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
4092f3563ccSZbigniew Lukwinski         storageUpdate();
4102f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
411a3bb38fbSZbigniew Kurzynski     }
412a3bb38fbSZbigniew Kurzynski     else
413a3bb38fbSZbigniew Kurzynski     {
414a3bb38fbSZbigniew Kurzynski         log<level::ERR>("Certificate does not exist",
4152f3563ccSZbigniew Lukwinski                         entry("ID=%s", certificate->getCertId().c_str()));
4162f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
4172f3563ccSZbigniew Lukwinski     }
4182f3563ccSZbigniew Lukwinski }
4192f3563ccSZbigniew Lukwinski 
4202f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
4212f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
4222f3563ccSZbigniew Lukwinski {
4232f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
4242f3563ccSZbigniew Lukwinski     {
4252f3563ccSZbigniew Lukwinski         certificate->install(filePath);
4262f3563ccSZbigniew Lukwinski         storageUpdate();
4272f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
4282f3563ccSZbigniew Lukwinski     }
4292f3563ccSZbigniew Lukwinski     else
4302f3563ccSZbigniew Lukwinski     {
431cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
432a3bb38fbSZbigniew Kurzynski     }
433a3bb38fbSZbigniew Kurzynski }
434a3bb38fbSZbigniew Kurzynski 
435f4682712SMarri Devender Rao std::string Manager::generateCSR(
436f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
437f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
438f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
439f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
440f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
441f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
442f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
443f4682712SMarri Devender Rao {
444f4682712SMarri Devender Rao     // We support only one CSR.
445f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
446f4682712SMarri Devender Rao     auto pid = fork();
447f4682712SMarri Devender Rao     if (pid == -1)
448f4682712SMarri Devender Rao     {
449f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
450f4682712SMarri Devender Rao         report<InternalFailure>();
451f4682712SMarri Devender Rao     }
452f4682712SMarri Devender Rao     else if (pid == 0)
453f4682712SMarri Devender Rao     {
454f4682712SMarri Devender Rao         try
455f4682712SMarri Devender Rao         {
456f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
457f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
458f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
459f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
460f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
461f4682712SMarri Devender Rao                               unstructuredName);
462f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
463f4682712SMarri Devender Rao         }
464f4682712SMarri Devender Rao         catch (const InternalFailure& e)
465f4682712SMarri Devender Rao         {
466f4682712SMarri Devender Rao             // commit the error reported in child process and exit
467f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
468f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
469f4682712SMarri Devender Rao             commit<InternalFailure>();
470f4682712SMarri Devender Rao         }
471d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
472d2393f23SRamesh Iyyar         {
473d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
474d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
475d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
476d2393f23SRamesh Iyyar             commit<InvalidArgument>();
477d2393f23SRamesh Iyyar         }
478f4682712SMarri Devender Rao     }
479f4682712SMarri Devender Rao     else
480f4682712SMarri Devender Rao     {
481f4682712SMarri Devender Rao         using namespace sdeventplus::source;
482f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
483f4682712SMarri Devender Rao                                           const siginfo_t* si) {
484f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
485f4682712SMarri Devender Rao             if (si->si_status != 0)
486f4682712SMarri Devender Rao             {
487f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
488f4682712SMarri Devender Rao             }
489f4682712SMarri Devender Rao             else
490f4682712SMarri Devender Rao             {
491f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
492f4682712SMarri Devender Rao             }
493f4682712SMarri Devender Rao         };
494f4682712SMarri Devender Rao         try
495f4682712SMarri Devender Rao         {
496f4682712SMarri Devender Rao             sigset_t ss;
497f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
498f4682712SMarri Devender Rao             {
499f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
500f4682712SMarri Devender Rao                 elog<InternalFailure>();
501f4682712SMarri Devender Rao             }
502f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
503f4682712SMarri Devender Rao             {
504f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
505f4682712SMarri Devender Rao                 elog<InternalFailure>();
506f4682712SMarri Devender Rao             }
507f4682712SMarri Devender Rao 
508f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
509cfb5802aSNan Zhou             if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
510f4682712SMarri Devender Rao             {
511f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
512f4682712SMarri Devender Rao                 elog<InternalFailure>();
513f4682712SMarri Devender Rao             }
514f4682712SMarri Devender Rao             if (childPtr)
515f4682712SMarri Devender Rao             {
516f4682712SMarri Devender Rao                 childPtr.reset();
517f4682712SMarri Devender Rao             }
518f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
519f4682712SMarri Devender Rao                                                std::move(callback));
520f4682712SMarri Devender Rao         }
521f4682712SMarri Devender Rao         catch (const InternalFailure& e)
522f4682712SMarri Devender Rao         {
523f4682712SMarri Devender Rao             commit<InternalFailure>();
524f4682712SMarri Devender Rao         }
525f4682712SMarri Devender Rao     }
526f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
527f4682712SMarri Devender Rao     return csrObjectPath;
528f4682712SMarri Devender Rao }
529f4682712SMarri Devender Rao 
530db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
531ffad1ef1SMarri Devender Rao {
532db029c95SKowalski, Kamil     return installedCerts;
533ffad1ef1SMarri Devender Rao }
534ffad1ef1SMarri Devender Rao 
535f4682712SMarri Devender Rao void Manager::generateCSRHelper(
536f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
537f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
538f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
539f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
540f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
541f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
542f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
543f4682712SMarri Devender Rao {
544f4682712SMarri Devender Rao     int ret = 0;
545f4682712SMarri Devender Rao 
546f4682712SMarri Devender Rao     // set version of x509 req
547f4682712SMarri Devender Rao     int nVersion = 1;
548f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
549cf06ccdcSNan Zhou     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
550f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
551f4682712SMarri Devender Rao     if (ret == 0)
552f4682712SMarri Devender Rao     {
553bf3cf751SNan Zhou         log<level::ERR>("Error occurred during X509_REQ_set_version call");
554f4682712SMarri Devender Rao         elog<InternalFailure>();
555f4682712SMarri Devender Rao     }
556f4682712SMarri Devender Rao 
557f4682712SMarri Devender Rao     // set subject of x509 req
558f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
559f4682712SMarri Devender Rao 
560f4682712SMarri Devender Rao     if (!alternativeNames.empty())
561f4682712SMarri Devender Rao     {
562f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
563f4682712SMarri Devender Rao         {
564f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
565f4682712SMarri Devender Rao         }
566f4682712SMarri Devender Rao     }
567f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
568f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
569f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
570f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
571f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
572f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
573f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
574f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
575f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
576f4682712SMarri Devender Rao     if (!keyUsage.empty())
577f4682712SMarri Devender Rao     {
578f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
579f4682712SMarri Devender Rao         {
5807641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
5817641105dSMarri Devender Rao             {
5827641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
5837641105dSMarri Devender Rao             }
5847641105dSMarri Devender Rao             else
5857641105dSMarri Devender Rao             {
586f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
587f4682712SMarri Devender Rao             }
588f4682712SMarri Devender Rao         }
5897641105dSMarri Devender Rao     }
590f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
591dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
592f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
593f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
594f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
595f4682712SMarri Devender Rao 
596cf06ccdcSNan Zhou     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
5978a09b52aSRamesh Iyyar 
5988a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
5998a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
6008a09b52aSRamesh Iyyar 
6018a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
6028a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
603c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
6048a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
605c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
6068a09b52aSRamesh Iyyar     else
6078a09b52aSRamesh Iyyar     {
6088a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
6098a09b52aSRamesh Iyyar                         "RSA and EC only");
6108a09b52aSRamesh Iyyar         elog<InvalidArgument>(
6118a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
6128a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
6138a09b52aSRamesh Iyyar     }
6148a09b52aSRamesh Iyyar 
6158a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
6168a09b52aSRamesh Iyyar     if (ret == 0)
6178a09b52aSRamesh Iyyar     {
618bf3cf751SNan Zhou         log<level::ERR>("Error occurred while setting Public key");
6198a09b52aSRamesh Iyyar         elog<InternalFailure>();
6208a09b52aSRamesh Iyyar     }
6218a09b52aSRamesh Iyyar 
6228a09b52aSRamesh Iyyar     // Write private key to file
623718eef37SNan Zhou     writePrivateKey(pKey, defaultPrivateKeyFileName);
624f4682712SMarri Devender Rao 
625f4682712SMarri Devender Rao     // set sign key of x509 req
626f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
6278a09b52aSRamesh Iyyar     if (ret == 0)
628f4682712SMarri Devender Rao     {
629bf3cf751SNan Zhou         log<level::ERR>("Error occurred while signing key of x509");
630f4682712SMarri Devender Rao         elog<InternalFailure>();
631f4682712SMarri Devender Rao     }
6328a09b52aSRamesh Iyyar 
633f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
634718eef37SNan Zhou     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
635c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
636f4682712SMarri Devender Rao }
637f4682712SMarri Devender Rao 
6387641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
6397641105dSMarri Devender Rao {
6407641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
6417641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
6427641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
6437641105dSMarri Devender Rao     auto it = std::find_if(
6447641105dSMarri Devender Rao         usageList.begin(), usageList.end(),
6457641105dSMarri Devender Rao         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
6467641105dSMarri Devender Rao     return it != usageList.end();
6477641105dSMarri Devender Rao }
648cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
649f4682712SMarri Devender Rao {
6508a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
651f4682712SMarri Devender Rao     // set keybit length to default value if not set
6528a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
653f4682712SMarri Devender Rao     {
6548a09b52aSRamesh Iyyar         log<level::INFO>(
6558a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
656cf06ccdcSNan Zhou             entry("DEFAULTKEYBITLENGTH=%d", defaultKeyBitLength));
657cf06ccdcSNan Zhou         keyBitLen = defaultKeyBitLength;
658f4682712SMarri Devender Rao     }
65926fb83efSPatrick Williams 
66026fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
66126fb83efSPatrick Williams 
66226fb83efSPatrick Williams     // generate rsa key
663cf06ccdcSNan Zhou     BignumPtr bne(BN_new(), ::BN_free);
66426fb83efSPatrick Williams     auto ret = BN_set_word(bne.get(), RSA_F4);
66526fb83efSPatrick Williams     if (ret == 0)
66626fb83efSPatrick Williams     {
667bf3cf751SNan Zhou         log<level::ERR>("Error occurred during BN_set_word call");
66826fb83efSPatrick Williams         elog<InternalFailure>();
66926fb83efSPatrick Williams     }
670762da74eSNan Zhou     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
671762da74eSNan Zhou     RSAPtr rsa(RSA_new(), ::RSA_free);
672762da74eSNan Zhou     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
673f4682712SMarri Devender Rao     if (ret != 1)
674f4682712SMarri Devender Rao     {
675bf3cf751SNan Zhou         log<level::ERR>("Error occurred during RSA_generate_key_ex call",
6768a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
677f4682712SMarri Devender Rao         elog<InternalFailure>();
678f4682712SMarri Devender Rao     }
679f4682712SMarri Devender Rao 
680f4682712SMarri Devender Rao     // set public key of x509 req
681cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
682762da74eSNan Zhou     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
683f4682712SMarri Devender Rao     if (ret == 0)
684f4682712SMarri Devender Rao     {
685bf3cf751SNan Zhou         log<level::ERR>("Error occurred during assign rsa key into EVP");
686f4682712SMarri Devender Rao         elog<InternalFailure>();
687f4682712SMarri Devender Rao     }
688762da74eSNan Zhou     // Now |rsa| is managed by |pKey|
689762da74eSNan Zhou     rsa.release();
6908a09b52aSRamesh Iyyar     return pKey;
69126fb83efSPatrick Williams 
69226fb83efSPatrick Williams #else
69326fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
69426fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
69526fb83efSPatrick Williams     if (!ctx)
69626fb83efSPatrick Williams     {
697bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm");
69826fb83efSPatrick Williams         elog<InternalFailure>();
69926fb83efSPatrick Williams     }
70026fb83efSPatrick Williams 
70126fb83efSPatrick Williams     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
70226fb83efSPatrick Williams         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
70326fb83efSPatrick Williams 
70426fb83efSPatrick Williams     {
705bf3cf751SNan Zhou         log<level::ERR>("Error occurred initializing keygen context");
70626fb83efSPatrick Williams         elog<InternalFailure>();
70726fb83efSPatrick Williams     }
70826fb83efSPatrick Williams 
70926fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
71026fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
71126fb83efSPatrick Williams     {
712bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
71326fb83efSPatrick Williams         elog<InternalFailure>();
71426fb83efSPatrick Williams     }
71526fb83efSPatrick Williams 
71626fb83efSPatrick Williams     return {pKey, &::EVP_PKEY_free};
71726fb83efSPatrick Williams #endif
7188a09b52aSRamesh Iyyar }
7198a09b52aSRamesh Iyyar 
720cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
7218a09b52aSRamesh Iyyar {
7228a09b52aSRamesh Iyyar     std::string curId(curveId);
7238a09b52aSRamesh Iyyar 
7248a09b52aSRamesh Iyyar     if (curId.empty())
7258a09b52aSRamesh Iyyar     {
7268a09b52aSRamesh Iyyar         log<level::INFO>(
7278a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
728cf06ccdcSNan Zhou             entry("DEFAULTKEYCURVEID=%s", defaultKeyCurveID));
729cf06ccdcSNan Zhou         curId = defaultKeyCurveID;
7308a09b52aSRamesh Iyyar     }
7318a09b52aSRamesh Iyyar 
7328a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
7338a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
7348a09b52aSRamesh Iyyar     {
7358a09b52aSRamesh Iyyar         log<level::ERR>(
736bf3cf751SNan Zhou             "Error occurred during convert the curve id string format into NID",
7378a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
7388a09b52aSRamesh Iyyar         elog<InternalFailure>();
7398a09b52aSRamesh Iyyar     }
7408a09b52aSRamesh Iyyar 
74126fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
74226fb83efSPatrick Williams 
7438a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
7448a09b52aSRamesh Iyyar 
745cfb5802aSNan Zhou     if (ecKey == nullptr)
7468a09b52aSRamesh Iyyar     {
7478a09b52aSRamesh Iyyar         log<level::ERR>(
748bf3cf751SNan Zhou             "Error occurred during create the EC_Key object from NID",
7498a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
7508a09b52aSRamesh Iyyar         elog<InternalFailure>();
7518a09b52aSRamesh Iyyar     }
7528a09b52aSRamesh Iyyar 
7538a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
7548a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
7558a09b52aSRamesh Iyyar     // flag on the key.
7568a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
7578a09b52aSRamesh Iyyar 
7588a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
7598a09b52aSRamesh Iyyar 
7608a09b52aSRamesh Iyyar     if (ret == 0)
7618a09b52aSRamesh Iyyar     {
7628a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
763bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
7648a09b52aSRamesh Iyyar         elog<InternalFailure>();
7658a09b52aSRamesh Iyyar     }
7668a09b52aSRamesh Iyyar 
767cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
7688a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
7698a09b52aSRamesh Iyyar     if (ret == 0)
7708a09b52aSRamesh Iyyar     {
7718a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
772bf3cf751SNan Zhou         log<level::ERR>("Error occurred during assign EC Key into EVP");
7738a09b52aSRamesh Iyyar         elog<InternalFailure>();
7748a09b52aSRamesh Iyyar     }
7758a09b52aSRamesh Iyyar 
7768a09b52aSRamesh Iyyar     return pKey;
77726fb83efSPatrick Williams 
77826fb83efSPatrick Williams #else
77926fb83efSPatrick Williams     auto holder_of_key = [](EVP_PKEY* key) {
78026fb83efSPatrick Williams         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
78126fb83efSPatrick Williams             key, &::EVP_PKEY_free};
78226fb83efSPatrick Williams     };
78326fb83efSPatrick Williams 
78426fb83efSPatrick Williams     // Create context to set up curve parameters.
78526fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
78626fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
78726fb83efSPatrick Williams     if (!ctx)
78826fb83efSPatrick Williams     {
789bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params");
79026fb83efSPatrick Williams         elog<InternalFailure>();
79126fb83efSPatrick Williams     }
79226fb83efSPatrick Williams 
79326fb83efSPatrick Williams     // Set up curve parameters.
79426fb83efSPatrick Williams     EVP_PKEY* params = nullptr;
79526fb83efSPatrick Williams 
79626fb83efSPatrick Williams     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
79726fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
79826fb83efSPatrick Williams          0) ||
79926fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
80026fb83efSPatrick Williams         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
80126fb83efSPatrick Williams     {
802bf3cf751SNan Zhou         log<level::ERR>("Error occurred setting curve parameters");
80326fb83efSPatrick Williams         elog<InternalFailure>();
80426fb83efSPatrick Williams     }
80526fb83efSPatrick Williams 
80626fb83efSPatrick Williams     // Move parameters to RAII holder.
80726fb83efSPatrick Williams     auto pparms = holder_of_key(params);
80826fb83efSPatrick Williams 
80926fb83efSPatrick Williams     // Create new context for key.
81026fb83efSPatrick Williams     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
81126fb83efSPatrick Williams 
81226fb83efSPatrick Williams     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
81326fb83efSPatrick Williams     {
814bf3cf751SNan Zhou         log<level::ERR>("Error occurred initializing keygen context");
81526fb83efSPatrick Williams         elog<InternalFailure>();
81626fb83efSPatrick Williams     }
81726fb83efSPatrick Williams 
81826fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
81926fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
82026fb83efSPatrick Williams     {
821bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
82226fb83efSPatrick Williams         elog<InternalFailure>();
82326fb83efSPatrick Williams     }
82426fb83efSPatrick Williams 
82526fb83efSPatrick Williams     return holder_of_key(pKey);
82626fb83efSPatrick Williams #endif
8278a09b52aSRamesh Iyyar }
8288a09b52aSRamesh Iyyar 
829cf06ccdcSNan Zhou void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
830c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
8318a09b52aSRamesh Iyyar {
8328a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
833f4682712SMarri Devender Rao     // write private key to file
834c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
835f4682712SMarri Devender Rao 
836f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
837cfb5802aSNan Zhou     if (fp == nullptr)
838f4682712SMarri Devender Rao     {
839bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating private key file");
840f4682712SMarri Devender Rao         elog<InternalFailure>();
841f4682712SMarri Devender Rao     }
842cfb5802aSNan Zhou     int ret =
843cfb5802aSNan Zhou         PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr);
844f4682712SMarri Devender Rao     std::fclose(fp);
845f4682712SMarri Devender Rao     if (ret == 0)
846f4682712SMarri Devender Rao     {
847bf3cf751SNan Zhou         log<level::ERR>("Error occurred while writing private key to file");
848f4682712SMarri Devender Rao         elog<InternalFailure>();
849f4682712SMarri Devender Rao     }
850f4682712SMarri Devender Rao }
851f4682712SMarri Devender Rao 
852f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
853f4682712SMarri Devender Rao                        const std::string& bytes)
854f4682712SMarri Devender Rao {
855f4682712SMarri Devender Rao     if (bytes.empty())
856f4682712SMarri Devender Rao     {
857f4682712SMarri Devender Rao         return;
858f4682712SMarri Devender Rao     }
859f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
860f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
861f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
862f4682712SMarri Devender Rao     if (ret != 1)
863f4682712SMarri Devender Rao     {
864f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
865f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
866f4682712SMarri Devender Rao         elog<InternalFailure>();
867f4682712SMarri Devender Rao     }
868f4682712SMarri Devender Rao }
869f4682712SMarri Devender Rao 
870f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
871f4682712SMarri Devender Rao {
872f4682712SMarri Devender Rao     if (csrPtr)
873f4682712SMarri Devender Rao     {
874f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
875f4682712SMarri Devender Rao     }
876f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
877f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
878f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
879f4682712SMarri Devender Rao }
880f4682712SMarri Devender Rao 
881cf06ccdcSNan Zhou void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
882f4682712SMarri Devender Rao {
883f4682712SMarri Devender Rao     if (fs::exists(filePath))
884f4682712SMarri Devender Rao     {
885f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
886f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
887f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
888f4682712SMarri Devender Rao         {
889f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
890f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
891f4682712SMarri Devender Rao             elog<InternalFailure>();
892f4682712SMarri Devender Rao         }
893f4682712SMarri Devender Rao     }
894f4682712SMarri Devender Rao 
895cfb5802aSNan Zhou     FILE* fp = nullptr;
896f4682712SMarri Devender Rao 
897cfb5802aSNan Zhou     if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
898f4682712SMarri Devender Rao     {
899f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
900f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
901f4682712SMarri Devender Rao         elog<InternalFailure>();
902f4682712SMarri Devender Rao     }
903f4682712SMarri Devender Rao 
904f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
905f4682712SMarri Devender Rao     if (!rc)
906f4682712SMarri Devender Rao     {
907f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
908f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
909f4682712SMarri Devender Rao         std::fclose(fp);
910f4682712SMarri Devender Rao         elog<InternalFailure>();
911f4682712SMarri Devender Rao     }
912f4682712SMarri Devender Rao     std::fclose(fp);
913f4682712SMarri Devender Rao }
914f4682712SMarri Devender Rao 
915db029c95SKowalski, Kamil void Manager::createCertificates()
916db029c95SKowalski, Kamil {
917db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
918db029c95SKowalski, Kamil 
919cf06ccdcSNan Zhou     if (certType == CertificateType::Authority)
920db029c95SKowalski, Kamil     {
921fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
922db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
923db029c95SKowalski, Kamil         {
924db029c95SKowalski, Kamil             log<level::ERR>("Certificate installation path exists and it is "
925db029c95SKowalski, Kamil                             "not a directory");
926db029c95SKowalski, Kamil             elog<InternalFailure>();
927*6ec13c8fSNan Zhou         }
928*6ec13c8fSNan Zhou 
929*6ec13c8fSNan Zhou         // If the authorities list exists, recover from it and return
930*6ec13c8fSNan Zhou         if (fs::path authoritiesListFilePath =
931*6ec13c8fSNan Zhou                 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
932*6ec13c8fSNan Zhou             fs::exists(authoritiesListFilePath))
933*6ec13c8fSNan Zhou         {
934*6ec13c8fSNan Zhou             // remove all other files and directories
935*6ec13c8fSNan Zhou             for (auto& path : fs::directory_iterator(certInstallPath))
936*6ec13c8fSNan Zhou             {
937*6ec13c8fSNan Zhou                 if (path.path() != authoritiesListFilePath)
938*6ec13c8fSNan Zhou                 {
939*6ec13c8fSNan Zhou                     fs::remove_all(path);
940*6ec13c8fSNan Zhou                 }
941*6ec13c8fSNan Zhou             }
942*6ec13c8fSNan Zhou             installAll(authoritiesListFilePath);
943db029c95SKowalski, Kamil             return;
944db029c95SKowalski, Kamil         }
945db029c95SKowalski, Kamil 
946db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
947ffad1ef1SMarri Devender Rao         {
948ffad1ef1SMarri Devender Rao             try
949ffad1ef1SMarri Devender Rao             {
9502f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
9512f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
9522f3563ccSZbigniew Lukwinski                 // would add value.
9532f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
9542f3563ccSZbigniew Lukwinski                 {
955db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
956db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
957cf06ccdcSNan Zhou                         certType, certInstallPath, path.path(),
958cf06ccdcSNan Zhou                         certWatchPtr.get(), *this));
9592f3563ccSZbigniew Lukwinski                 }
960ffad1ef1SMarri Devender Rao             }
961ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
962ffad1ef1SMarri Devender Rao             {
963ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
964ffad1ef1SMarri Devender Rao             }
965ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
966ffad1ef1SMarri Devender Rao             {
967cf06ccdcSNan Zhou                 report<InvalidCertificate>(InvalidCertificateReason(
968cf06ccdcSNan Zhou                     "Existing certificate file is corrupted"));
969ffad1ef1SMarri Devender Rao             }
970ffad1ef1SMarri Devender Rao         }
971db029c95SKowalski, Kamil     }
972db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
973db029c95SKowalski, Kamil     {
974db029c95SKowalski, Kamil         try
975db029c95SKowalski, Kamil         {
976db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
9772f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
978cf06ccdcSNan Zhou                 certInstallPath, certWatchPtr.get(), *this));
979db029c95SKowalski, Kamil         }
980db029c95SKowalski, Kamil         catch (const InternalFailure& e)
981db029c95SKowalski, Kamil         {
982db029c95SKowalski, Kamil             report<InternalFailure>();
983db029c95SKowalski, Kamil         }
984db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
985db029c95SKowalski, Kamil         {
986cf06ccdcSNan Zhou             report<InvalidCertificate>(InvalidCertificateReason(
987cf06ccdcSNan Zhou                 "Existing certificate file is corrupted"));
988db029c95SKowalski, Kamil         }
989db029c95SKowalski, Kamil     }
990db029c95SKowalski, Kamil }
991c6e58c7eSRamesh Iyyar 
992c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
993c6e58c7eSRamesh Iyyar {
994c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
995718eef37SNan Zhou         certParentInstallPath / defaultRSAPrivateKeyFileName;
996c6e58c7eSRamesh Iyyar 
997c6e58c7eSRamesh Iyyar     try
998c6e58c7eSRamesh Iyyar     {
999c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
1000c6e58c7eSRamesh Iyyar         {
1001cf06ccdcSNan Zhou             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
1002718eef37SNan Zhou                             defaultRSAPrivateKeyFileName);
1003c6e58c7eSRamesh Iyyar         }
1004c6e58c7eSRamesh Iyyar     }
1005c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
1006c6e58c7eSRamesh Iyyar     {
1007c6e58c7eSRamesh Iyyar         report<InternalFailure>();
1008c6e58c7eSRamesh Iyyar     }
1009c6e58c7eSRamesh Iyyar }
1010c6e58c7eSRamesh Iyyar 
1011cf06ccdcSNan Zhou EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
1012c6e58c7eSRamesh Iyyar {
1013cf06ccdcSNan Zhou     if (keyBitLength != supportedKeyBitLength)
1014c6e58c7eSRamesh Iyyar     {
1015c6e58c7eSRamesh Iyyar         log<level::ERR>(
1016c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
1017c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
1018cf06ccdcSNan Zhou             entry("SUPPORTEDKEYBITLENGTH=%d", supportedKeyBitLength));
1019c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
1020c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1021c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1022c6e58c7eSRamesh Iyyar     }
1023c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
1024718eef37SNan Zhou         certParentInstallPath / defaultRSAPrivateKeyFileName;
1025c6e58c7eSRamesh Iyyar 
1026c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1027c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
1028c6e58c7eSRamesh Iyyar     {
1029c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
1030c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
1031c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
1032c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1033c6e58c7eSRamesh Iyyar     }
1034c6e58c7eSRamesh Iyyar 
1035cf06ccdcSNan Zhou     EVPPkeyPtr privateKey(
1036c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1037c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
1038c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
1039c6e58c7eSRamesh Iyyar 
1040c6e58c7eSRamesh Iyyar     if (!privateKey)
1041c6e58c7eSRamesh Iyyar     {
1042bf3cf751SNan Zhou         log<level::ERR>("Error occurred during PEM_read_PrivateKey call");
1043c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1044c6e58c7eSRamesh Iyyar     }
1045c6e58c7eSRamesh Iyyar     return privateKey;
1046c6e58c7eSRamesh Iyyar }
10472f3563ccSZbigniew Lukwinski 
10482f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
10492f3563ccSZbigniew Lukwinski {
1050cf06ccdcSNan Zhou     if (certType == CertificateType::Authority)
10512f3563ccSZbigniew Lukwinski     {
10522f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
10532f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
10542f3563ccSZbigniew Lukwinski         {
10552f3563ccSZbigniew Lukwinski             try
10562f3563ccSZbigniew Lukwinski             {
10572f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
10582f3563ccSZbigniew Lukwinski                 {
10592f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
10602f3563ccSZbigniew Lukwinski                 }
10612f3563ccSZbigniew Lukwinski             }
10622f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
10632f3563ccSZbigniew Lukwinski             {
10642f3563ccSZbigniew Lukwinski                 log<level::ERR>(
10652f3563ccSZbigniew Lukwinski                     "Failed to remove symlink for certificate",
10662f3563ccSZbigniew Lukwinski                     entry("ERR=%s", e.what()),
10672f3563ccSZbigniew Lukwinski                     entry("SYMLINK=%s", certPath.path().string().c_str()));
10682f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
10692f3563ccSZbigniew Lukwinski             }
10702f3563ccSZbigniew Lukwinski         }
10712f3563ccSZbigniew Lukwinski     }
10722f3563ccSZbigniew Lukwinski 
10732f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
10742f3563ccSZbigniew Lukwinski     {
10752f3563ccSZbigniew Lukwinski         cert->storageUpdate();
10762f3563ccSZbigniew Lukwinski     }
10772f3563ccSZbigniew Lukwinski }
10782f3563ccSZbigniew Lukwinski 
1079cf06ccdcSNan Zhou void Manager::reloadOrReset(const std::string& unit)
10802f3563ccSZbigniew Lukwinski {
10812f3563ccSZbigniew Lukwinski     if (!unit.empty())
10822f3563ccSZbigniew Lukwinski     {
10832f3563ccSZbigniew Lukwinski         try
10842f3563ccSZbigniew Lukwinski         {
1085cf06ccdcSNan Zhou             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1086cf06ccdcSNan Zhou             constexpr auto defaultSystemdObjectPath =
1087cf06ccdcSNan Zhou                 "/org/freedesktop/systemd1";
1088cf06ccdcSNan Zhou             constexpr auto defaultSystemdInterface =
10892f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
1090cf06ccdcSNan Zhou             auto method = bus.new_method_call(
1091cf06ccdcSNan Zhou                 defaultSystemdService, defaultSystemdObjectPath,
1092cf06ccdcSNan Zhou                 defaultSystemdInterface, "ReloadOrRestartUnit");
10932f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
10942f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
10952f3563ccSZbigniew Lukwinski         }
1096ca128117SPatrick Williams         catch (const sdbusplus::exception::exception& e)
10972f3563ccSZbigniew Lukwinski         {
10982f3563ccSZbigniew Lukwinski             log<level::ERR>("Failed to reload or restart service",
10992f3563ccSZbigniew Lukwinski                             entry("ERR=%s", e.what()),
11002f3563ccSZbigniew Lukwinski                             entry("UNIT=%s", unit.c_str()));
11012f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
11022f3563ccSZbigniew Lukwinski         }
11032f3563ccSZbigniew Lukwinski     }
11042f3563ccSZbigniew Lukwinski }
11052f3563ccSZbigniew Lukwinski 
11062f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
11072f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
11082f3563ccSZbigniew Lukwinski {
11092f3563ccSZbigniew Lukwinski     if (std::any_of(
11102f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
11112f3563ccSZbigniew Lukwinski             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
11122f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
11132f3563ccSZbigniew Lukwinski             }))
11142f3563ccSZbigniew Lukwinski     {
11152f3563ccSZbigniew Lukwinski         return false;
11162f3563ccSZbigniew Lukwinski     }
11172f3563ccSZbigniew Lukwinski     else
11182f3563ccSZbigniew Lukwinski     {
11192f3563ccSZbigniew Lukwinski         return true;
11202f3563ccSZbigniew Lukwinski     }
11212f3563ccSZbigniew Lukwinski }
11222f3563ccSZbigniew Lukwinski 
1123e1289adfSNan Zhou } // namespace phosphor::certs
1124