xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision a2f68d8b7955970d8c4dd986a1a226a616f0e0aa)
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>
108dbcc72dSAndrew Geissler #include <openssl/err.h>
1126fb83efSPatrick Williams #include <openssl/evp.h>
12014be0bfSNan Zhou #include <openssl/obj_mac.h>
13014be0bfSNan Zhou #include <openssl/objects.h>
14014be0bfSNan Zhou #include <openssl/opensslv.h>
15f4682712SMarri Devender Rao #include <openssl/pem.h>
16014be0bfSNan Zhou #include <openssl/rsa.h>
17f4682712SMarri Devender Rao #include <unistd.h>
18f4682712SMarri Devender Rao 
19223e4604SPatrick Williams #include <phosphor-logging/elog-errors.hpp>
20223e4604SPatrick Williams #include <phosphor-logging/elog.hpp>
21f2646271SRavi Teja #include <phosphor-logging/lg2.hpp>
22223e4604SPatrick Williams #include <sdbusplus/bus.hpp>
23223e4604SPatrick Williams #include <sdbusplus/exception.hpp>
24223e4604SPatrick Williams #include <sdbusplus/message.hpp>
25223e4604SPatrick Williams #include <sdeventplus/source/base.hpp>
26223e4604SPatrick Williams #include <sdeventplus/source/child.hpp>
27223e4604SPatrick Williams #include <xyz/openbmc_project/Certs/error.hpp>
28223e4604SPatrick Williams #include <xyz/openbmc_project/Common/error.hpp>
29223e4604SPatrick Williams 
30a3bb38fbSZbigniew Kurzynski #include <algorithm>
31014be0bfSNan Zhou #include <array>
32014be0bfSNan Zhou #include <cerrno>
33014be0bfSNan Zhou #include <chrono>
34014be0bfSNan Zhou #include <csignal>
35014be0bfSNan Zhou #include <cstdio>
36014be0bfSNan Zhou #include <cstdlib>
37014be0bfSNan Zhou #include <cstring>
38014be0bfSNan Zhou #include <exception>
396ec13c8fSNan Zhou #include <fstream>
40014be0bfSNan Zhou #include <utility>
412f3563ccSZbigniew Lukwinski 
42e1289adfSNan Zhou namespace phosphor::certs
43cfbc8dc8SJayanth Othayoth {
44cf06ccdcSNan Zhou namespace
45cf06ccdcSNan Zhou {
46cf06ccdcSNan Zhou namespace fs = std::filesystem;
47cf06ccdcSNan Zhou using ::phosphor::logging::commit;
48cf06ccdcSNan Zhou using ::phosphor::logging::elog;
49cf06ccdcSNan Zhou using ::phosphor::logging::report;
50cfbc8dc8SJayanth Othayoth 
51cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
52cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
53cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
54cf06ccdcSNan Zhou using NotAllowedReason =
55cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
56cf06ccdcSNan Zhou using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
57cf06ccdcSNan Zhou     Certs::InvalidCertificate::REASON;
58cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
59cf06ccdcSNan Zhou using Argument =
60cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
61c6e58c7eSRamesh Iyyar 
62cf06ccdcSNan Zhou // RAII support for openSSL functions.
63cf06ccdcSNan Zhou using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
64cf06ccdcSNan Zhou using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
65cf06ccdcSNan Zhou using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
666ec13c8fSNan Zhou using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
67cf06ccdcSNan Zhou 
68cf06ccdcSNan Zhou constexpr int supportedKeyBitLength = 2048;
69cf06ccdcSNan Zhou constexpr int defaultKeyBitLength = 2048;
70cf06ccdcSNan Zhou // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
71cf06ccdcSNan Zhou constexpr auto defaultKeyCurveID = "secp224r1";
726ec13c8fSNan Zhou // PEM certificate block markers, defined in go/rfc/7468.
736ec13c8fSNan Zhou constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
746ec13c8fSNan Zhou constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
756ec13c8fSNan Zhou 
766ec13c8fSNan Zhou /**
776ec13c8fSNan Zhou  * @brief Splits the given authorities list file and returns an array of
786ec13c8fSNan Zhou  * individual PEM encoded x509 certificate.
796ec13c8fSNan Zhou  *
806ec13c8fSNan Zhou  * @param[in] sourceFilePath - Path to the authorities list file.
816ec13c8fSNan Zhou  *
826ec13c8fSNan Zhou  * @return An array of individual PEM encoded x509 certificate
836ec13c8fSNan Zhou  */
846ec13c8fSNan Zhou std::vector<std::string> splitCertificates(const std::string& sourceFilePath)
856ec13c8fSNan Zhou {
866ec13c8fSNan Zhou     std::ifstream inputCertFileStream;
876ec13c8fSNan Zhou     inputCertFileStream.exceptions(
886ec13c8fSNan Zhou         std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
896ec13c8fSNan Zhou 
906ec13c8fSNan Zhou     std::stringstream pemStream;
916ec13c8fSNan Zhou     std::vector<std::string> certificatesList;
926ec13c8fSNan Zhou     try
936ec13c8fSNan Zhou     {
946ec13c8fSNan Zhou         inputCertFileStream.open(sourceFilePath);
956ec13c8fSNan Zhou         pemStream << inputCertFileStream.rdbuf();
966ec13c8fSNan Zhou         inputCertFileStream.close();
976ec13c8fSNan Zhou     }
986ec13c8fSNan Zhou     catch (const std::exception& e)
996ec13c8fSNan Zhou     {
100f2646271SRavi Teja         lg2::error("Failed to read certificates list, ERR:{ERR}, SRC:{SRC}",
101f2646271SRavi Teja                    "ERR", e, "SRC", sourceFilePath);
1026ec13c8fSNan Zhou         elog<InternalFailure>();
1036ec13c8fSNan Zhou     }
1046ec13c8fSNan Zhou     std::string pem = pemStream.str();
1056ec13c8fSNan Zhou     size_t begin = 0;
1066ec13c8fSNan Zhou     // |begin| points to the current start position for searching the next
1076ec13c8fSNan Zhou     // |beginCertificate| block. When we find the beginning of the certificate,
1086ec13c8fSNan Zhou     // we extract the content between the beginning and the end of the current
1096ec13c8fSNan Zhou     // certificate. And finally we move |begin| to the end of the current
1106ec13c8fSNan Zhou     // certificate to start searching the next potential certificate.
1116ec13c8fSNan Zhou     for (begin = pem.find(beginCertificate, begin); begin != std::string::npos;
1126ec13c8fSNan Zhou          begin = pem.find(beginCertificate, begin))
1136ec13c8fSNan Zhou     {
1146ec13c8fSNan Zhou         size_t end = pem.find(endCertificate, begin);
1156ec13c8fSNan Zhou         if (end == std::string::npos)
1166ec13c8fSNan Zhou         {
117f2646271SRavi Teja             lg2::error(
1186ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END");
1196ec13c8fSNan Zhou             elog<InvalidCertificate>(InvalidCertificateReason(
1206ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END"));
1216ec13c8fSNan Zhou         }
1226ec13c8fSNan Zhou         end += endCertificate.size();
1236ec13c8fSNan Zhou         certificatesList.emplace_back(pem.substr(begin, end - begin));
1246ec13c8fSNan Zhou         begin = end;
1256ec13c8fSNan Zhou     }
1266ec13c8fSNan Zhou     return certificatesList;
1276ec13c8fSNan Zhou }
1286ec13c8fSNan Zhou 
129cf06ccdcSNan Zhou } // namespace
130f4682712SMarri Devender Rao 
131b3dbfb37SPatrick Williams Manager::Manager(sdbusplus::bus_t& bus, sdeventplus::Event& event,
132cf06ccdcSNan Zhou                  const char* path, CertificateType type,
133cf06ccdcSNan Zhou                  const std::string& unit, const std::string& installPath) :
134*a2f68d8bSPatrick Williams     internal::ManagerInterface(bus, path), bus(bus), event(event),
135*a2f68d8bSPatrick Williams     objectPath(path), certType(type), unitToRestart(std::move(unit)),
136*a2f68d8bSPatrick Williams     certInstallPath(std::move(installPath)),
137c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
138cfbc8dc8SJayanth Othayoth {
139db5c6fc8SMarri Devender Rao     try
140db5c6fc8SMarri Devender Rao     {
141fe590c4eSZbigniew Lukwinski         // Create certificate directory if not existing.
142bf3cf751SNan Zhou         // Set correct certificate directory permissions.
143fe590c4eSZbigniew Lukwinski         fs::path certDirectory;
144b57d75e2SMarri Devender Rao         try
145b57d75e2SMarri Devender Rao         {
146e3d47cd4SNan Zhou             if (certType == CertificateType::authority)
147b57d75e2SMarri Devender Rao             {
148fe590c4eSZbigniew Lukwinski                 certDirectory = certInstallPath;
149b57d75e2SMarri Devender Rao             }
150fe590c4eSZbigniew Lukwinski             else
151fe590c4eSZbigniew Lukwinski             {
152fe590c4eSZbigniew Lukwinski                 certDirectory = certParentInstallPath;
153fe590c4eSZbigniew Lukwinski             }
154fe590c4eSZbigniew Lukwinski 
155fe590c4eSZbigniew Lukwinski             if (!fs::exists(certDirectory))
156fe590c4eSZbigniew Lukwinski             {
157fe590c4eSZbigniew Lukwinski                 fs::create_directories(certDirectory);
158fe590c4eSZbigniew Lukwinski             }
159fe590c4eSZbigniew Lukwinski 
160667286e4SMarri Devender Rao             auto permission = fs::perms::owner_read | fs::perms::owner_write |
161667286e4SMarri Devender Rao                               fs::perms::owner_exec;
162db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
163db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
1642f3563ccSZbigniew Lukwinski             storageUpdate();
165b57d75e2SMarri Devender Rao         }
16671957992SPatrick Williams         catch (const fs::filesystem_error& e)
167b57d75e2SMarri Devender Rao         {
168f2646271SRavi Teja             lg2::error(
169f2646271SRavi Teja                 "Failed to create directory, ERR:{ERR}, DIRECTORY:{DIRECTORY}",
170f2646271SRavi Teja                 "ERR", e, "DIRECTORY", certParentInstallPath);
171b57d75e2SMarri Devender Rao             report<InternalFailure>();
172b57d75e2SMarri Devender Rao         }
173b57d75e2SMarri Devender Rao 
174c6e58c7eSRamesh Iyyar         // Generating RSA private key file if certificate type is server/client
175e3d47cd4SNan Zhou         if (certType != CertificateType::authority)
176c6e58c7eSRamesh Iyyar         {
177c6e58c7eSRamesh Iyyar             createRSAPrivateKeyFile();
178c6e58c7eSRamesh Iyyar         }
179c6e58c7eSRamesh Iyyar 
180ffad1ef1SMarri Devender Rao         // restore any existing certificates
181db029c95SKowalski, Kamil         createCertificates();
182ffad1ef1SMarri Devender Rao 
183ffad1ef1SMarri Devender Rao         // watch is not required for authority certificates
184e3d47cd4SNan Zhou         if (certType != CertificateType::authority)
185ffad1ef1SMarri Devender Rao         {
186ffad1ef1SMarri Devender Rao             // watch for certificate file create/replace
187*a2f68d8bSPatrick Williams             certWatchPtr = std::make_unique<
188*a2f68d8bSPatrick Williams                 Watch>(event, certInstallPath, [this]() {
189bf7c588cSMarri Devender Rao                 try
190bf7c588cSMarri Devender Rao                 {
191ffad1ef1SMarri Devender Rao                     // if certificate file existing update it
192db029c95SKowalski, Kamil                     if (!installedCerts.empty())
193ffad1ef1SMarri Devender Rao                     {
194f2646271SRavi Teja                         lg2::info("Inotify callback to update "
195db5c6fc8SMarri Devender Rao                                   "certificate properties");
196db029c95SKowalski, Kamil                         installedCerts[0]->populateProperties();
197ffad1ef1SMarri Devender Rao                     }
198ffad1ef1SMarri Devender Rao                     else
199ffad1ef1SMarri Devender Rao                     {
200f2646271SRavi Teja                         lg2::info(
201ffad1ef1SMarri Devender Rao                             "Inotify callback to create certificate object");
202db029c95SKowalski, Kamil                         createCertificates();
203ffad1ef1SMarri Devender Rao                     }
204bf7c588cSMarri Devender Rao                 }
205bf7c588cSMarri Devender Rao                 catch (const InternalFailure& e)
206bf7c588cSMarri Devender Rao                 {
207ffad1ef1SMarri Devender Rao                     commit<InternalFailure>();
208bf7c588cSMarri Devender Rao                 }
209bf7c588cSMarri Devender Rao                 catch (const InvalidCertificate& e)
210bf7c588cSMarri Devender Rao                 {
211ffad1ef1SMarri Devender Rao                     commit<InvalidCertificate>();
212bf7c588cSMarri Devender Rao                 }
213ffad1ef1SMarri Devender Rao             });
214bf7c588cSMarri Devender Rao         }
215db029c95SKowalski, Kamil         else
216db029c95SKowalski, Kamil         {
217db5c6fc8SMarri Devender Rao             try
218db5c6fc8SMarri Devender Rao             {
219db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
220db5c6fc8SMarri Devender Rao                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
221db029c95SKowalski, Kamil                 {
222f2646271SRavi Teja                     lg2::notice(
223f2646271SRavi Teja                         "Legacy certificate detected, will be installed from,"
224f2646271SRavi Teja                         "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
225f2646271SRavi Teja                         "SINGLE_CERTPATH", singleCertPath);
226db5c6fc8SMarri Devender Rao                     install(singleCertPath);
227db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
228db029c95SKowalski, Kamil                     {
229f2646271SRavi Teja                         lg2::error("Unable to remove old certificate from,"
230f2646271SRavi Teja                                    "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
231f2646271SRavi Teja                                    "SINGLE_CERTPATH", singleCertPath);
232db029c95SKowalski, Kamil                         elog<InternalFailure>();
233db029c95SKowalski, Kamil                     }
234db029c95SKowalski, Kamil                 }
235db029c95SKowalski, Kamil             }
236db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
237db5c6fc8SMarri Devender Rao             {
238f2646271SRavi Teja                 lg2::error(
239f2646271SRavi Teja                     "Error in restoring legacy certificate, ERROR_STR:{ERROR_STR}",
240f2646271SRavi Teja                     "ERROR_STR", ex);
241db5c6fc8SMarri Devender Rao             }
242db5c6fc8SMarri Devender Rao         }
243db5c6fc8SMarri Devender Rao     }
24471957992SPatrick Williams     catch (const std::exception& ex)
245db5c6fc8SMarri Devender Rao     {
246f2646271SRavi Teja         lg2::error(
247f2646271SRavi Teja             "Error in certificate manager constructor, ERROR_STR:{ERROR_STR}",
248f2646271SRavi Teja             "ERROR_STR", ex);
249db5c6fc8SMarri Devender Rao     }
250dd74bd20SJayanth Othayoth }
251589159f2SJayanth Othayoth 
25206a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath)
253cfbc8dc8SJayanth Othayoth {
254e3d47cd4SNan Zhou     if (certType != CertificateType::authority && !installedCerts.empty())
2551396511dSMarri Devender Rao     {
256cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
2571396511dSMarri Devender Rao     }
258e3d47cd4SNan 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,
270698a5743SWilly Tu             certWatchPtr.get(), *this, /*restore=*/false));
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 {
285e3d47cd4SNan Zhou     if (certType != CertificateType::authority)
2866ec13c8fSNan Zhou     {
287*a2f68d8bSPatrick Williams         elog<NotAllowed>(NotAllowedReason(
288*a2f68d8bSPatrick Williams             "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     {
302f2646271SRavi Teja         lg2::error("File is Missing, FILE:{FILE}", "FILE", filePath);
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 
311f2646271SRavi Teja     lg2::info("Starts authority list install");
31278357b0aSNan Zhou 
3136ec13c8fSNan Zhou     fs::path authorityStore(certInstallPath);
314*a2f68d8bSPatrick Williams     fs::path authoritiesListFile =
315*a2f68d8bSPatrick Williams         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     {
328*a2f68d8bSPatrick Williams         std::string certObjectPath =
329*a2f68d8bSPatrick Williams             objectPath + '/' + std::to_string(tempCertIdCounter);
3306ec13c8fSNan Zhou         tempCertificates.emplace_back(std::make_unique<Certificate>(
3316ec13c8fSNan Zhou             bus, certObjectPath, certType, tempPath, *x509Store, authority,
332698a5743SWilly Tu             certWatchPtr.get(), *this, /*restore=*/false));
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);
352*a2f68d8bSPatrick Williams         cert->setCertFilePath(
353*a2f68d8bSPatrick Williams             certInstallPath / 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 
365f2646271SRavi Teja     lg2::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
388e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
3896ec13c8fSNan Zhou     {
390*a2f68d8bSPatrick Williams         if (fs::path authoritiesList =
391*a2f68d8bSPatrick Williams                 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 {
404223e4604SPatrick Williams     const std::vector<std::unique_ptr<Certificate>>::iterator& certIt =
405a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
406223e4604SPatrick Williams                      [certificate](const std::unique_ptr<Certificate>& 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     {
417f2646271SRavi Teja         lg2::error("Certificate does not exist, ID:{ID}", "ID",
418f2646271SRavi Teja                    certificate->getCertId());
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     {
428698a5743SWilly Tu         certificate->install(filePath, false);
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     {
452f2646271SRavi Teja         lg2::error("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         {
459*a2f68d8bSPatrick Williams             generateCSRHelper(
460*a2f68d8bSPatrick Williams                 alternativeNames, challengePassword, city, commonName,
461*a2f68d8bSPatrick Williams                 contactPerson, country, email, givenName, initials,
462*a2f68d8bSPatrick Williams                 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
463*a2f68d8bSPatrick Williams                 organization, 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;
485*a2f68d8bSPatrick Williams         Child::Callback callback =
486*a2f68d8bSPatrick Williams             [this](Child& eventSource, const siginfo_t* si) {
487f4682712SMarri Devender Rao                 eventSource.set_enabled(Enabled::On);
488f4682712SMarri Devender Rao                 if (si->si_status != 0)
489f4682712SMarri Devender Rao                 {
490e3d47cd4SNan Zhou                     this->createCSRObject(Status::failure);
491f4682712SMarri Devender Rao                 }
492f4682712SMarri Devender Rao                 else
493f4682712SMarri Devender Rao                 {
494e3d47cd4SNan Zhou                     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             {
502f2646271SRavi Teja                 lg2::error("Unable to initialize signal set");
503f4682712SMarri Devender Rao                 elog<InternalFailure>();
504f4682712SMarri Devender Rao             }
505f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
506f4682712SMarri Devender Rao             {
507f2646271SRavi Teja                 lg2::error("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             {
514f2646271SRavi Teja                 lg2::error("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 
549cf06ccdcSNan Zhou     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
550f4682712SMarri Devender Rao 
551f4682712SMarri Devender Rao     // set subject of x509 req
552f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
553f4682712SMarri Devender Rao 
554f4682712SMarri Devender Rao     if (!alternativeNames.empty())
555f4682712SMarri Devender Rao     {
556f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
557f4682712SMarri Devender Rao         {
558f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
559f4682712SMarri Devender Rao         }
560f4682712SMarri Devender Rao     }
561f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
562f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
563f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
564f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
565f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
566f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
567f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
568f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
569f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
570f4682712SMarri Devender Rao     if (!keyUsage.empty())
571f4682712SMarri Devender Rao     {
572f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
573f4682712SMarri Devender Rao         {
5747641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
5757641105dSMarri Devender Rao             {
5767641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
5777641105dSMarri Devender Rao             }
5787641105dSMarri Devender Rao             else
5797641105dSMarri Devender Rao             {
580f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
581f4682712SMarri Devender Rao             }
582f4682712SMarri Devender Rao         }
5837641105dSMarri Devender Rao     }
584f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
585dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
586f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
587f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
588f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
589f4682712SMarri Devender Rao 
590cf06ccdcSNan Zhou     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
5918a09b52aSRamesh Iyyar 
592f2646271SRavi Teja     lg2::info("Given Key pair algorithm, KEYPAIRALGORITHM:{KEYPAIRALGORITHM}",
593f2646271SRavi Teja               "KEYPAIRALGORITHM", keyPairAlgorithm);
5948a09b52aSRamesh Iyyar 
5958a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
5968a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
597c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
5988a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
599c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
6008a09b52aSRamesh Iyyar     else
6018a09b52aSRamesh Iyyar     {
602f2646271SRavi Teja         lg2::error("Given Key pair algorithm is not supported. Supporting "
6038a09b52aSRamesh Iyyar                    "RSA and EC only");
6048a09b52aSRamesh Iyyar         elog<InvalidArgument>(
6058a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
6068a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
6078a09b52aSRamesh Iyyar     }
6088a09b52aSRamesh Iyyar 
6098a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
6108a09b52aSRamesh Iyyar     if (ret == 0)
6118a09b52aSRamesh Iyyar     {
612f2646271SRavi Teja         lg2::error("Error occurred while setting Public key");
6138dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
6148a09b52aSRamesh Iyyar         elog<InternalFailure>();
6158a09b52aSRamesh Iyyar     }
6168a09b52aSRamesh Iyyar 
6178a09b52aSRamesh Iyyar     // Write private key to file
618718eef37SNan Zhou     writePrivateKey(pKey, defaultPrivateKeyFileName);
619f4682712SMarri Devender Rao 
620f4682712SMarri Devender Rao     // set sign key of x509 req
621f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
6228a09b52aSRamesh Iyyar     if (ret == 0)
623f4682712SMarri Devender Rao     {
624f2646271SRavi Teja         lg2::error("Error occurred while signing key of x509");
6258dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
626f4682712SMarri Devender Rao         elog<InternalFailure>();
627f4682712SMarri Devender Rao     }
6288a09b52aSRamesh Iyyar 
629f2646271SRavi Teja     lg2::info("Writing CSR to file");
630718eef37SNan Zhou     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
631c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
632f4682712SMarri Devender Rao }
633f4682712SMarri Devender Rao 
6347641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
6357641105dSMarri Devender Rao {
6367641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
6377641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
6387641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
639d96b81caSPatrick Williams     auto it = std::find_if(
640d96b81caSPatrick Williams         usageList.begin(), usageList.end(),
641d96b81caSPatrick Williams         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
6427641105dSMarri Devender Rao     return it != usageList.end();
6437641105dSMarri Devender Rao }
644cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
645f4682712SMarri Devender Rao {
6468a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
647f4682712SMarri Devender Rao     // set keybit length to default value if not set
6488a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
649f4682712SMarri Devender Rao     {
650f2646271SRavi Teja         lg2::info("KeyBitLength is not given.Hence, using default KeyBitLength:"
651f2646271SRavi Teja                   "{DEFAULTKEYBITLENGTH}",
652f2646271SRavi Teja                   "DEFAULTKEYBITLENGTH", defaultKeyBitLength);
653cf06ccdcSNan Zhou         keyBitLen = defaultKeyBitLength;
654f4682712SMarri Devender Rao     }
65526fb83efSPatrick Williams 
65626fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
65726fb83efSPatrick Williams 
65826fb83efSPatrick Williams     // generate rsa key
659cf06ccdcSNan Zhou     BignumPtr bne(BN_new(), ::BN_free);
66026fb83efSPatrick Williams     auto ret = BN_set_word(bne.get(), RSA_F4);
66126fb83efSPatrick Williams     if (ret == 0)
66226fb83efSPatrick Williams     {
663f2646271SRavi Teja         lg2::error("Error occurred during BN_set_word call");
6648dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
66526fb83efSPatrick Williams         elog<InternalFailure>();
66626fb83efSPatrick Williams     }
667762da74eSNan Zhou     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
668762da74eSNan Zhou     RSAPtr rsa(RSA_new(), ::RSA_free);
669762da74eSNan Zhou     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
670f4682712SMarri Devender Rao     if (ret != 1)
671f4682712SMarri Devender Rao     {
672f2646271SRavi Teja         lg2::error(
673f2646271SRavi Teja             "Error occurred during RSA_generate_key_ex call: {KEYBITLENGTH}",
674f2646271SRavi Teja             "KEYBITLENGTH", keyBitLen);
6758dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
676f4682712SMarri Devender Rao         elog<InternalFailure>();
677f4682712SMarri Devender Rao     }
678f4682712SMarri Devender Rao 
679f4682712SMarri Devender Rao     // set public key of x509 req
680cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
681762da74eSNan Zhou     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
682f4682712SMarri Devender Rao     if (ret == 0)
683f4682712SMarri Devender Rao     {
684f2646271SRavi Teja         lg2::error("Error occurred during assign rsa key into EVP");
6858dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
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     {
697f2646271SRavi Teja         lg2::error("Error occurred creating EVP_PKEY_CTX from algorithm");
6988dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
69926fb83efSPatrick Williams         elog<InternalFailure>();
70026fb83efSPatrick Williams     }
70126fb83efSPatrick Williams 
70226fb83efSPatrick Williams     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
70326fb83efSPatrick Williams         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
70426fb83efSPatrick Williams 
70526fb83efSPatrick Williams     {
706f2646271SRavi Teja         lg2::error("Error occurred initializing keygen context");
7078dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
70826fb83efSPatrick Williams         elog<InternalFailure>();
70926fb83efSPatrick Williams     }
71026fb83efSPatrick Williams 
71126fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
71226fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
71326fb83efSPatrick Williams     {
714f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
7158dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
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     {
729f2646271SRavi Teja         lg2::info("KeyCurveId is not given. Hence using default curve id,"
730f2646271SRavi Teja                   "DEFAULTKEYCURVEID:{DEFAULTKEYCURVEID}",
731f2646271SRavi Teja                   "DEFAULTKEYCURVEID", 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     {
738f2646271SRavi Teja         lg2::error(
739f2646271SRavi Teja             "Error occurred during convert the curve id string format into NID,"
740f2646271SRavi Teja             "KEYCURVEID:{KEYCURVEID}",
741f2646271SRavi Teja             "KEYCURVEID", curId);
7428a09b52aSRamesh Iyyar         elog<InternalFailure>();
7438a09b52aSRamesh Iyyar     }
7448a09b52aSRamesh Iyyar 
74526fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
74626fb83efSPatrick Williams 
7478a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
7488a09b52aSRamesh Iyyar 
749cfb5802aSNan Zhou     if (ecKey == nullptr)
7508a09b52aSRamesh Iyyar     {
751f2646271SRavi Teja         lg2::error(
752f2646271SRavi Teja             "Error occurred during create the EC_Key object from NID, ECGROUP:{ECGROUP}",
753f2646271SRavi Teja             "ECGROUP", ecGrp);
7548dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
7558a09b52aSRamesh Iyyar         elog<InternalFailure>();
7568a09b52aSRamesh Iyyar     }
7578a09b52aSRamesh Iyyar 
7588a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
7598a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
7608a09b52aSRamesh Iyyar     // flag on the key.
7618a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
7628a09b52aSRamesh Iyyar 
7638a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
7648a09b52aSRamesh Iyyar 
7658a09b52aSRamesh Iyyar     if (ret == 0)
7668a09b52aSRamesh Iyyar     {
7678a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
768f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
7698dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
7708a09b52aSRamesh Iyyar         elog<InternalFailure>();
7718a09b52aSRamesh Iyyar     }
7728a09b52aSRamesh Iyyar 
773cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
7748a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
7758a09b52aSRamesh Iyyar     if (ret == 0)
7768a09b52aSRamesh Iyyar     {
7778a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
778f2646271SRavi Teja         lg2::error("Error occurred during assign EC Key into EVP");
7798dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
7808a09b52aSRamesh Iyyar         elog<InternalFailure>();
7818a09b52aSRamesh Iyyar     }
7828a09b52aSRamesh Iyyar 
7838a09b52aSRamesh Iyyar     return pKey;
78426fb83efSPatrick Williams 
78526fb83efSPatrick Williams #else
786e3d47cd4SNan Zhou     auto holderOfKey = [](EVP_PKEY* key) {
78726fb83efSPatrick Williams         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
78826fb83efSPatrick Williams             key, &::EVP_PKEY_free};
78926fb83efSPatrick Williams     };
79026fb83efSPatrick Williams 
79126fb83efSPatrick Williams     // Create context to set up curve parameters.
79226fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
79326fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
79426fb83efSPatrick Williams     if (!ctx)
79526fb83efSPatrick Williams     {
796f2646271SRavi Teja         lg2::error("Error occurred creating EVP_PKEY_CTX for params");
7978dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
79826fb83efSPatrick Williams         elog<InternalFailure>();
79926fb83efSPatrick Williams     }
80026fb83efSPatrick Williams 
80126fb83efSPatrick Williams     // Set up curve parameters.
80226fb83efSPatrick Williams     EVP_PKEY* params = nullptr;
80326fb83efSPatrick Williams 
80426fb83efSPatrick Williams     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
80526fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
80626fb83efSPatrick Williams          0) ||
80726fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
80826fb83efSPatrick Williams         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
80926fb83efSPatrick Williams     {
810f2646271SRavi Teja         lg2::error("Error occurred setting curve parameters");
8118dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
81226fb83efSPatrick Williams         elog<InternalFailure>();
81326fb83efSPatrick Williams     }
81426fb83efSPatrick Williams 
81526fb83efSPatrick Williams     // Move parameters to RAII holder.
816e3d47cd4SNan Zhou     auto pparms = holderOfKey(params);
81726fb83efSPatrick Williams 
81826fb83efSPatrick Williams     // Create new context for key.
81926fb83efSPatrick Williams     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
82026fb83efSPatrick Williams 
82126fb83efSPatrick Williams     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
82226fb83efSPatrick Williams     {
823f2646271SRavi Teja         lg2::error("Error occurred initializing keygen context");
8248dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
82526fb83efSPatrick Williams         elog<InternalFailure>();
82626fb83efSPatrick Williams     }
82726fb83efSPatrick Williams 
82826fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
82926fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
83026fb83efSPatrick Williams     {
831f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
8328dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
83326fb83efSPatrick Williams         elog<InternalFailure>();
83426fb83efSPatrick Williams     }
83526fb83efSPatrick Williams 
836e3d47cd4SNan Zhou     return holderOfKey(pKey);
83726fb83efSPatrick Williams #endif
8388a09b52aSRamesh Iyyar }
8398a09b52aSRamesh Iyyar 
840cf06ccdcSNan Zhou void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
841c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
8428a09b52aSRamesh Iyyar {
843f2646271SRavi Teja     lg2::info("Writing private key to file");
844f4682712SMarri Devender Rao     // write private key to file
845c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
846f4682712SMarri Devender Rao 
847f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
848cfb5802aSNan Zhou     if (fp == nullptr)
849f4682712SMarri Devender Rao     {
850f2646271SRavi Teja         lg2::error("Error occurred creating private key file");
851f4682712SMarri Devender Rao         elog<InternalFailure>();
852f4682712SMarri Devender Rao     }
853*a2f68d8bSPatrick Williams     int ret =
854*a2f68d8bSPatrick Williams         PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr);
855f4682712SMarri Devender Rao     std::fclose(fp);
856f4682712SMarri Devender Rao     if (ret == 0)
857f4682712SMarri Devender Rao     {
858f2646271SRavi Teja         lg2::error("Error occurred while writing private key to file");
859f4682712SMarri Devender Rao         elog<InternalFailure>();
860f4682712SMarri Devender Rao     }
861f4682712SMarri Devender Rao }
862f4682712SMarri Devender Rao 
863f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
864f4682712SMarri Devender Rao                        const std::string& bytes)
865f4682712SMarri Devender Rao {
866f4682712SMarri Devender Rao     if (bytes.empty())
867f4682712SMarri Devender Rao     {
868f4682712SMarri Devender Rao         return;
869f4682712SMarri Devender Rao     }
870f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
871f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
872f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
873f4682712SMarri Devender Rao     if (ret != 1)
874f4682712SMarri Devender Rao     {
875f2646271SRavi Teja         lg2::error("Unable to set entry, FIELD:{FIELD}, VALUE:{VALUE}", "FIELD",
876f2646271SRavi Teja                    field, "VALUE", bytes);
8778dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
878f4682712SMarri Devender Rao         elog<InternalFailure>();
879f4682712SMarri Devender Rao     }
880f4682712SMarri Devender Rao }
881f4682712SMarri Devender Rao 
882f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
883f4682712SMarri Devender Rao {
884f4682712SMarri Devender Rao     if (csrPtr)
885f4682712SMarri Devender Rao     {
886f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
887f4682712SMarri Devender Rao     }
888f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
889f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
890f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
891f4682712SMarri Devender Rao }
892f4682712SMarri Devender Rao 
893cf06ccdcSNan Zhou void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
894f4682712SMarri Devender Rao {
895f4682712SMarri Devender Rao     if (fs::exists(filePath))
896f4682712SMarri Devender Rao     {
897f2646271SRavi Teja         lg2::info("Removing the existing file, FILENAME:{FILENAME}", "FILENAME",
898f2646271SRavi Teja                   filePath);
899f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
900f4682712SMarri Devender Rao         {
901f2646271SRavi Teja             lg2::error("Unable to remove the file, FILENAME:{FILENAME}",
902f2646271SRavi Teja                        "FILENAME", filePath);
903f4682712SMarri Devender Rao             elog<InternalFailure>();
904f4682712SMarri Devender Rao         }
905f4682712SMarri Devender Rao     }
906f4682712SMarri Devender Rao 
907cfb5802aSNan Zhou     FILE* fp = nullptr;
908f4682712SMarri Devender Rao 
909cfb5802aSNan Zhou     if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
910f4682712SMarri Devender Rao     {
911f2646271SRavi Teja         lg2::error(
912f2646271SRavi Teja             "Error opening the file to write the CSR, FILENAME:{FILENAME}",
913f2646271SRavi Teja             "FILENAME", filePath);
914f4682712SMarri Devender Rao         elog<InternalFailure>();
915f4682712SMarri Devender Rao     }
916f4682712SMarri Devender Rao 
917f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
918f4682712SMarri Devender Rao     if (!rc)
919f4682712SMarri Devender Rao     {
920f2646271SRavi Teja         lg2::error("PEM write routine failed, FILENAME:{FILENAME}", "FILENAME",
921f2646271SRavi Teja                    filePath);
922f4682712SMarri Devender Rao         std::fclose(fp);
923f4682712SMarri Devender Rao         elog<InternalFailure>();
924f4682712SMarri Devender Rao     }
925f4682712SMarri Devender Rao     std::fclose(fp);
926f4682712SMarri Devender Rao }
927f4682712SMarri Devender Rao 
928db029c95SKowalski, Kamil void Manager::createCertificates()
929db029c95SKowalski, Kamil {
930db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
931db029c95SKowalski, Kamil 
932e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
933db029c95SKowalski, Kamil     {
934fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
935db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
936db029c95SKowalski, Kamil         {
937f2646271SRavi Teja             lg2::error("Certificate installation path exists and it is "
938db029c95SKowalski, Kamil                        "not a directory");
939db029c95SKowalski, Kamil             elog<InternalFailure>();
9406ec13c8fSNan Zhou         }
9416ec13c8fSNan Zhou 
9426ec13c8fSNan Zhou         // If the authorities list exists, recover from it and return
943*a2f68d8bSPatrick Williams         if (fs::path authoritiesListFilePath =
944*a2f68d8bSPatrick Williams                 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
9456ec13c8fSNan Zhou             fs::exists(authoritiesListFilePath))
9466ec13c8fSNan Zhou         {
9476ec13c8fSNan Zhou             // remove all other files and directories
9486ec13c8fSNan Zhou             for (auto& path : fs::directory_iterator(certInstallPath))
9496ec13c8fSNan Zhou             {
9506ec13c8fSNan Zhou                 if (path.path() != authoritiesListFilePath)
9516ec13c8fSNan Zhou                 {
9526ec13c8fSNan Zhou                     fs::remove_all(path);
9536ec13c8fSNan Zhou                 }
9546ec13c8fSNan Zhou             }
9556ec13c8fSNan Zhou             installAll(authoritiesListFilePath);
956db029c95SKowalski, Kamil             return;
957db029c95SKowalski, Kamil         }
958db029c95SKowalski, Kamil 
959db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
960ffad1ef1SMarri Devender Rao         {
961ffad1ef1SMarri Devender Rao             try
962ffad1ef1SMarri Devender Rao             {
9632f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
9642f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
9652f3563ccSZbigniew Lukwinski                 // would add value.
9662f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
9672f3563ccSZbigniew Lukwinski                 {
968db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
969db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
970cf06ccdcSNan Zhou                         certType, certInstallPath, path.path(),
971698a5743SWilly Tu                         certWatchPtr.get(), *this, /*restore=*/true));
9722f3563ccSZbigniew Lukwinski                 }
973ffad1ef1SMarri Devender Rao             }
974ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
975ffad1ef1SMarri Devender Rao             {
976ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
977ffad1ef1SMarri Devender Rao             }
978ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
979ffad1ef1SMarri Devender Rao             {
980cf06ccdcSNan Zhou                 report<InvalidCertificate>(InvalidCertificateReason(
981cf06ccdcSNan Zhou                     "Existing certificate file is corrupted"));
982ffad1ef1SMarri Devender Rao             }
983ffad1ef1SMarri Devender Rao         }
984db029c95SKowalski, Kamil     }
985db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
986db029c95SKowalski, Kamil     {
987db029c95SKowalski, Kamil         try
988db029c95SKowalski, Kamil         {
989db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
9902f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
991698a5743SWilly Tu                 certInstallPath, certWatchPtr.get(), *this, /*restore=*/false));
992db029c95SKowalski, Kamil         }
993db029c95SKowalski, Kamil         catch (const InternalFailure& e)
994db029c95SKowalski, Kamil         {
995db029c95SKowalski, Kamil             report<InternalFailure>();
996db029c95SKowalski, Kamil         }
997db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
998db029c95SKowalski, Kamil         {
999cf06ccdcSNan Zhou             report<InvalidCertificate>(InvalidCertificateReason(
1000cf06ccdcSNan Zhou                 "Existing certificate file is corrupted"));
1001db029c95SKowalski, Kamil         }
1002db029c95SKowalski, Kamil     }
1003db029c95SKowalski, Kamil }
1004c6e58c7eSRamesh Iyyar 
1005c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
1006c6e58c7eSRamesh Iyyar {
1007*a2f68d8bSPatrick Williams     fs::path rsaPrivateKeyFileName =
1008*a2f68d8bSPatrick Williams         certParentInstallPath / defaultRSAPrivateKeyFileName;
1009c6e58c7eSRamesh Iyyar 
1010c6e58c7eSRamesh Iyyar     try
1011c6e58c7eSRamesh Iyyar     {
1012c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
1013c6e58c7eSRamesh Iyyar         {
1014cf06ccdcSNan Zhou             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
1015718eef37SNan Zhou                             defaultRSAPrivateKeyFileName);
1016c6e58c7eSRamesh Iyyar         }
1017c6e58c7eSRamesh Iyyar     }
1018c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
1019c6e58c7eSRamesh Iyyar     {
1020c6e58c7eSRamesh Iyyar         report<InternalFailure>();
1021c6e58c7eSRamesh Iyyar     }
1022c6e58c7eSRamesh Iyyar }
1023c6e58c7eSRamesh Iyyar 
1024cf06ccdcSNan Zhou EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
1025c6e58c7eSRamesh Iyyar {
1026cf06ccdcSNan Zhou     if (keyBitLength != supportedKeyBitLength)
1027c6e58c7eSRamesh Iyyar     {
1028f2646271SRavi Teja         lg2::error(
1029f2646271SRavi Teja             "Given Key bit length is not supported, GIVENKEYBITLENGTH:"
1030f2646271SRavi Teja             "{GIVENKEYBITLENGTH}, SUPPORTEDKEYBITLENGTH:{SUPPORTEDKEYBITLENGTH}",
1031f2646271SRavi Teja             "GIVENKEYBITLENGTH", keyBitLength, "SUPPORTEDKEYBITLENGTH",
1032f2646271SRavi Teja             supportedKeyBitLength);
1033c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
1034c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1035c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1036c6e58c7eSRamesh Iyyar     }
1037*a2f68d8bSPatrick Williams     fs::path rsaPrivateKeyFileName =
1038*a2f68d8bSPatrick Williams         certParentInstallPath / defaultRSAPrivateKeyFileName;
1039c6e58c7eSRamesh Iyyar 
1040c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1041c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
1042c6e58c7eSRamesh Iyyar     {
1043f2646271SRavi Teja         lg2::error(
1044f2646271SRavi Teja             "Unable to open RSA private key file to read, RSAKEYFILE:{RSAKEYFILE},"
1045f2646271SRavi Teja             "ERRORREASON:{ERRORREASON}",
1046f2646271SRavi Teja             "RSAKEYFILE", rsaPrivateKeyFileName, "ERRORREASON",
1047f2646271SRavi Teja             strerror(errno));
1048c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1049c6e58c7eSRamesh Iyyar     }
1050c6e58c7eSRamesh Iyyar 
1051cf06ccdcSNan Zhou     EVPPkeyPtr privateKey(
1052c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1053c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
1054c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
1055c6e58c7eSRamesh Iyyar 
1056c6e58c7eSRamesh Iyyar     if (!privateKey)
1057c6e58c7eSRamesh Iyyar     {
1058f2646271SRavi Teja         lg2::error("Error occurred during PEM_read_PrivateKey call");
1059c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1060c6e58c7eSRamesh Iyyar     }
1061c6e58c7eSRamesh Iyyar     return privateKey;
1062c6e58c7eSRamesh Iyyar }
10632f3563ccSZbigniew Lukwinski 
10642f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
10652f3563ccSZbigniew Lukwinski {
1066e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
10672f3563ccSZbigniew Lukwinski     {
10682f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
10692f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
10702f3563ccSZbigniew Lukwinski         {
10712f3563ccSZbigniew Lukwinski             try
10722f3563ccSZbigniew Lukwinski             {
10732f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
10742f3563ccSZbigniew Lukwinski                 {
10752f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
10762f3563ccSZbigniew Lukwinski                 }
10772f3563ccSZbigniew Lukwinski             }
10782f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
10792f3563ccSZbigniew Lukwinski             {
1080f2646271SRavi Teja                 lg2::error(
1081f2646271SRavi Teja                     "Failed to remove symlink for certificate, ERR:{ERR} SYMLINK:{SYMLINK}",
1082f2646271SRavi Teja                     "ERR", e, "SYMLINK", certPath.path().string());
10832f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
10842f3563ccSZbigniew Lukwinski             }
10852f3563ccSZbigniew Lukwinski         }
10862f3563ccSZbigniew Lukwinski     }
10872f3563ccSZbigniew Lukwinski 
10882f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
10892f3563ccSZbigniew Lukwinski     {
10902f3563ccSZbigniew Lukwinski         cert->storageUpdate();
10912f3563ccSZbigniew Lukwinski     }
10922f3563ccSZbigniew Lukwinski }
10932f3563ccSZbigniew Lukwinski 
1094cf06ccdcSNan Zhou void Manager::reloadOrReset(const std::string& unit)
10952f3563ccSZbigniew Lukwinski {
10962f3563ccSZbigniew Lukwinski     if (!unit.empty())
10972f3563ccSZbigniew Lukwinski     {
10982f3563ccSZbigniew Lukwinski         try
10992f3563ccSZbigniew Lukwinski         {
1100cf06ccdcSNan Zhou             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1101cf06ccdcSNan Zhou             constexpr auto defaultSystemdObjectPath =
1102cf06ccdcSNan Zhou                 "/org/freedesktop/systemd1";
1103cf06ccdcSNan Zhou             constexpr auto defaultSystemdInterface =
11042f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
1105cf06ccdcSNan Zhou             auto method = bus.new_method_call(
1106cf06ccdcSNan Zhou                 defaultSystemdService, defaultSystemdObjectPath,
1107cf06ccdcSNan Zhou                 defaultSystemdInterface, "ReloadOrRestartUnit");
11082f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
11092f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
11102f3563ccSZbigniew Lukwinski         }
1111b3dbfb37SPatrick Williams         catch (const sdbusplus::exception_t& e)
11122f3563ccSZbigniew Lukwinski         {
1113f2646271SRavi Teja             lg2::error(
1114f2646271SRavi Teja                 "Failed to reload or restart service, ERR:{ERR}, UNIT:{UNIT}",
1115f2646271SRavi Teja                 "ERR", e, "UNIT", unit);
11162f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
11172f3563ccSZbigniew Lukwinski         }
11182f3563ccSZbigniew Lukwinski     }
11192f3563ccSZbigniew Lukwinski }
11202f3563ccSZbigniew Lukwinski 
11212f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
11222f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
11232f3563ccSZbigniew Lukwinski {
11242f3563ccSZbigniew Lukwinski     if (std::any_of(
11252f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
1126223e4604SPatrick Williams             [&filePath, certToDrop](const std::unique_ptr<Certificate>& cert) {
11272f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
11282f3563ccSZbigniew Lukwinski             }))
11292f3563ccSZbigniew Lukwinski     {
11302f3563ccSZbigniew Lukwinski         return false;
11312f3563ccSZbigniew Lukwinski     }
11322f3563ccSZbigniew Lukwinski     else
11332f3563ccSZbigniew Lukwinski     {
11342f3563ccSZbigniew Lukwinski         return true;
11352f3563ccSZbigniew Lukwinski     }
11362f3563ccSZbigniew Lukwinski }
11372f3563ccSZbigniew Lukwinski 
1138e1289adfSNan Zhou } // namespace phosphor::certs
1139