xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision f2646271e5fc66e4c5f3f8bfd6eeb68b6be3f103)
1014be0bfSNan Zhou #include "config.h"
2014be0bfSNan Zhou 
3cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
4cfbc8dc8SJayanth Othayoth 
56ec13c8fSNan Zhou #include "x509_utils.hpp"
66ec13c8fSNan Zhou 
7014be0bfSNan Zhou #include <openssl/asn1.h>
8014be0bfSNan Zhou #include <openssl/bn.h>
9014be0bfSNan Zhou #include <openssl/ec.h>
1026fb83efSPatrick Williams #include <openssl/evp.h>
11014be0bfSNan Zhou #include <openssl/obj_mac.h>
12014be0bfSNan Zhou #include <openssl/objects.h>
13014be0bfSNan Zhou #include <openssl/opensslv.h>
14f4682712SMarri Devender Rao #include <openssl/pem.h>
15014be0bfSNan Zhou #include <openssl/rsa.h>
16f4682712SMarri Devender Rao #include <unistd.h>
17f4682712SMarri Devender Rao 
18223e4604SPatrick Williams #include <phosphor-logging/elog-errors.hpp>
19223e4604SPatrick Williams #include <phosphor-logging/elog.hpp>
20*f2646271SRavi Teja #include <phosphor-logging/lg2.hpp>
21223e4604SPatrick Williams #include <sdbusplus/bus.hpp>
22223e4604SPatrick Williams #include <sdbusplus/exception.hpp>
23223e4604SPatrick Williams #include <sdbusplus/message.hpp>
24223e4604SPatrick Williams #include <sdeventplus/source/base.hpp>
25223e4604SPatrick Williams #include <sdeventplus/source/child.hpp>
26223e4604SPatrick Williams #include <xyz/openbmc_project/Certs/error.hpp>
27223e4604SPatrick Williams #include <xyz/openbmc_project/Common/error.hpp>
28223e4604SPatrick Williams 
29a3bb38fbSZbigniew Kurzynski #include <algorithm>
30014be0bfSNan Zhou #include <array>
31014be0bfSNan Zhou #include <cerrno>
32014be0bfSNan Zhou #include <chrono>
33014be0bfSNan Zhou #include <csignal>
34014be0bfSNan Zhou #include <cstdio>
35014be0bfSNan Zhou #include <cstdlib>
36014be0bfSNan Zhou #include <cstring>
37014be0bfSNan Zhou #include <exception>
386ec13c8fSNan Zhou #include <fstream>
39014be0bfSNan Zhou #include <utility>
402f3563ccSZbigniew Lukwinski 
41e1289adfSNan Zhou namespace phosphor::certs
42cfbc8dc8SJayanth Othayoth {
43cf06ccdcSNan Zhou namespace
44cf06ccdcSNan Zhou {
45cf06ccdcSNan Zhou namespace fs = std::filesystem;
46cf06ccdcSNan Zhou using ::phosphor::logging::commit;
47cf06ccdcSNan Zhou using ::phosphor::logging::elog;
48cf06ccdcSNan Zhou using ::phosphor::logging::report;
49cfbc8dc8SJayanth Othayoth 
50cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
51cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
52cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
53cf06ccdcSNan Zhou using NotAllowedReason =
54cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
55cf06ccdcSNan Zhou using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
56cf06ccdcSNan Zhou     Certs::InvalidCertificate::REASON;
57cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
58cf06ccdcSNan Zhou using Argument =
59cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
60c6e58c7eSRamesh Iyyar 
61cf06ccdcSNan Zhou // RAII support for openSSL functions.
62cf06ccdcSNan Zhou using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
63cf06ccdcSNan Zhou using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
64cf06ccdcSNan Zhou using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
656ec13c8fSNan Zhou using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
66cf06ccdcSNan Zhou 
67cf06ccdcSNan Zhou constexpr int supportedKeyBitLength = 2048;
68cf06ccdcSNan Zhou constexpr int defaultKeyBitLength = 2048;
69cf06ccdcSNan Zhou // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
70cf06ccdcSNan Zhou constexpr auto defaultKeyCurveID = "secp224r1";
716ec13c8fSNan Zhou // PEM certificate block markers, defined in go/rfc/7468.
726ec13c8fSNan Zhou constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
736ec13c8fSNan Zhou constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
746ec13c8fSNan Zhou 
756ec13c8fSNan Zhou /**
766ec13c8fSNan Zhou  * @brief Splits the given authorities list file and returns an array of
776ec13c8fSNan Zhou  * individual PEM encoded x509 certificate.
786ec13c8fSNan Zhou  *
796ec13c8fSNan Zhou  * @param[in] sourceFilePath - Path to the authorities list file.
806ec13c8fSNan Zhou  *
816ec13c8fSNan Zhou  * @return An array of individual PEM encoded x509 certificate
826ec13c8fSNan Zhou  */
836ec13c8fSNan Zhou std::vector<std::string> splitCertificates(const std::string& sourceFilePath)
846ec13c8fSNan Zhou {
856ec13c8fSNan Zhou     std::ifstream inputCertFileStream;
866ec13c8fSNan Zhou     inputCertFileStream.exceptions(
876ec13c8fSNan Zhou         std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
886ec13c8fSNan Zhou 
896ec13c8fSNan Zhou     std::stringstream pemStream;
906ec13c8fSNan Zhou     std::vector<std::string> certificatesList;
916ec13c8fSNan Zhou     try
926ec13c8fSNan Zhou     {
936ec13c8fSNan Zhou         inputCertFileStream.open(sourceFilePath);
946ec13c8fSNan Zhou         pemStream << inputCertFileStream.rdbuf();
956ec13c8fSNan Zhou         inputCertFileStream.close();
966ec13c8fSNan Zhou     }
976ec13c8fSNan Zhou     catch (const std::exception& e)
986ec13c8fSNan Zhou     {
99*f2646271SRavi Teja         lg2::error("Failed to read certificates list, ERR:{ERR}, SRC:{SRC}",
100*f2646271SRavi Teja                    "ERR", e, "SRC", sourceFilePath);
1016ec13c8fSNan Zhou         elog<InternalFailure>();
1026ec13c8fSNan Zhou     }
1036ec13c8fSNan Zhou     std::string pem = pemStream.str();
1046ec13c8fSNan Zhou     size_t begin = 0;
1056ec13c8fSNan Zhou     // |begin| points to the current start position for searching the next
1066ec13c8fSNan Zhou     // |beginCertificate| block. When we find the beginning of the certificate,
1076ec13c8fSNan Zhou     // we extract the content between the beginning and the end of the current
1086ec13c8fSNan Zhou     // certificate. And finally we move |begin| to the end of the current
1096ec13c8fSNan Zhou     // certificate to start searching the next potential certificate.
1106ec13c8fSNan Zhou     for (begin = pem.find(beginCertificate, begin); begin != std::string::npos;
1116ec13c8fSNan Zhou          begin = pem.find(beginCertificate, begin))
1126ec13c8fSNan Zhou     {
1136ec13c8fSNan Zhou         size_t end = pem.find(endCertificate, begin);
1146ec13c8fSNan Zhou         if (end == std::string::npos)
1156ec13c8fSNan Zhou         {
116*f2646271SRavi Teja             lg2::error(
1176ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END");
1186ec13c8fSNan Zhou             elog<InvalidCertificate>(InvalidCertificateReason(
1196ec13c8fSNan Zhou                 "invalid PEM contains a BEGIN identifier without an END"));
1206ec13c8fSNan Zhou         }
1216ec13c8fSNan Zhou         end += endCertificate.size();
1226ec13c8fSNan Zhou         certificatesList.emplace_back(pem.substr(begin, end - begin));
1236ec13c8fSNan Zhou         begin = end;
1246ec13c8fSNan Zhou     }
1256ec13c8fSNan Zhou     return certificatesList;
1266ec13c8fSNan Zhou }
1276ec13c8fSNan Zhou 
128cf06ccdcSNan Zhou } // namespace
129f4682712SMarri Devender Rao 
130b3dbfb37SPatrick Williams Manager::Manager(sdbusplus::bus_t& bus, sdeventplus::Event& event,
131cf06ccdcSNan Zhou                  const char* path, CertificateType type,
132cf06ccdcSNan Zhou                  const std::string& unit, const std::string& installPath) :
133cf06ccdcSNan Zhou     internal::ManagerInterface(bus, path),
134f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
135c6e58c7eSRamesh Iyyar     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
136c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
137cfbc8dc8SJayanth Othayoth {
138db5c6fc8SMarri Devender Rao     try
139db5c6fc8SMarri Devender Rao     {
140fe590c4eSZbigniew Lukwinski         // Create certificate directory if not existing.
141bf3cf751SNan Zhou         // Set correct certificate directory permissions.
142fe590c4eSZbigniew Lukwinski         fs::path certDirectory;
143b57d75e2SMarri Devender Rao         try
144b57d75e2SMarri Devender Rao         {
145e3d47cd4SNan Zhou             if (certType == CertificateType::authority)
146b57d75e2SMarri Devender Rao             {
147fe590c4eSZbigniew Lukwinski                 certDirectory = certInstallPath;
148b57d75e2SMarri Devender Rao             }
149fe590c4eSZbigniew Lukwinski             else
150fe590c4eSZbigniew Lukwinski             {
151fe590c4eSZbigniew Lukwinski                 certDirectory = certParentInstallPath;
152fe590c4eSZbigniew Lukwinski             }
153fe590c4eSZbigniew Lukwinski 
154fe590c4eSZbigniew Lukwinski             if (!fs::exists(certDirectory))
155fe590c4eSZbigniew Lukwinski             {
156fe590c4eSZbigniew Lukwinski                 fs::create_directories(certDirectory);
157fe590c4eSZbigniew Lukwinski             }
158fe590c4eSZbigniew Lukwinski 
159667286e4SMarri Devender Rao             auto permission = fs::perms::owner_read | fs::perms::owner_write |
160667286e4SMarri Devender Rao                               fs::perms::owner_exec;
161db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
162db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
1632f3563ccSZbigniew Lukwinski             storageUpdate();
164b57d75e2SMarri Devender Rao         }
16571957992SPatrick Williams         catch (const fs::filesystem_error& e)
166b57d75e2SMarri Devender Rao         {
167*f2646271SRavi Teja             lg2::error(
168*f2646271SRavi Teja                 "Failed to create directory, ERR:{ERR}, DIRECTORY:{DIRECTORY}",
169*f2646271SRavi Teja                 "ERR", e, "DIRECTORY", certParentInstallPath);
170b57d75e2SMarri Devender Rao             report<InternalFailure>();
171b57d75e2SMarri Devender Rao         }
172b57d75e2SMarri Devender Rao 
173c6e58c7eSRamesh Iyyar         // Generating RSA private key file if certificate type is server/client
174e3d47cd4SNan Zhou         if (certType != CertificateType::authority)
175c6e58c7eSRamesh Iyyar         {
176c6e58c7eSRamesh Iyyar             createRSAPrivateKeyFile();
177c6e58c7eSRamesh Iyyar         }
178c6e58c7eSRamesh Iyyar 
179ffad1ef1SMarri Devender Rao         // restore any existing certificates
180db029c95SKowalski, Kamil         createCertificates();
181ffad1ef1SMarri Devender Rao 
182ffad1ef1SMarri Devender Rao         // watch is not required for authority certificates
183e3d47cd4SNan Zhou         if (certType != CertificateType::authority)
184ffad1ef1SMarri Devender Rao         {
185ffad1ef1SMarri Devender Rao             // watch for certificate file create/replace
186223e4604SPatrick Williams             certWatchPtr = std::make_unique<Watch>(event, certInstallPath,
187223e4604SPatrick Williams                                                    [this]() {
188bf7c588cSMarri Devender Rao                 try
189bf7c588cSMarri Devender Rao                 {
190ffad1ef1SMarri Devender Rao                     // if certificate file existing update it
191db029c95SKowalski, Kamil                     if (!installedCerts.empty())
192ffad1ef1SMarri Devender Rao                     {
193*f2646271SRavi Teja                         lg2::info("Inotify callback to update "
194db5c6fc8SMarri Devender Rao                                   "certificate properties");
195db029c95SKowalski, Kamil                         installedCerts[0]->populateProperties();
196ffad1ef1SMarri Devender Rao                     }
197ffad1ef1SMarri Devender Rao                     else
198ffad1ef1SMarri Devender Rao                     {
199*f2646271SRavi Teja                         lg2::info(
200ffad1ef1SMarri Devender Rao                             "Inotify callback to create certificate object");
201db029c95SKowalski, Kamil                         createCertificates();
202ffad1ef1SMarri Devender Rao                     }
203bf7c588cSMarri Devender Rao                 }
204bf7c588cSMarri Devender Rao                 catch (const InternalFailure& e)
205bf7c588cSMarri Devender Rao                 {
206ffad1ef1SMarri Devender Rao                     commit<InternalFailure>();
207bf7c588cSMarri Devender Rao                 }
208bf7c588cSMarri Devender Rao                 catch (const InvalidCertificate& e)
209bf7c588cSMarri Devender Rao                 {
210ffad1ef1SMarri Devender Rao                     commit<InvalidCertificate>();
211bf7c588cSMarri Devender Rao                 }
212ffad1ef1SMarri Devender Rao             });
213bf7c588cSMarri Devender Rao         }
214db029c95SKowalski, Kamil         else
215db029c95SKowalski, Kamil         {
216db5c6fc8SMarri Devender Rao             try
217db5c6fc8SMarri Devender Rao             {
218db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
219db5c6fc8SMarri Devender Rao                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
220db029c95SKowalski, Kamil                 {
221*f2646271SRavi Teja                     lg2::notice(
222*f2646271SRavi Teja                         "Legacy certificate detected, will be installed from,"
223*f2646271SRavi Teja                         "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
224*f2646271SRavi Teja                         "SINGLE_CERTPATH", singleCertPath);
225db5c6fc8SMarri Devender Rao                     install(singleCertPath);
226db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
227db029c95SKowalski, Kamil                     {
228*f2646271SRavi Teja                         lg2::error("Unable to remove old certificate from,"
229*f2646271SRavi Teja                                    "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
230*f2646271SRavi Teja                                    "SINGLE_CERTPATH", singleCertPath);
231db029c95SKowalski, Kamil                         elog<InternalFailure>();
232db029c95SKowalski, Kamil                     }
233db029c95SKowalski, Kamil                 }
234db029c95SKowalski, Kamil             }
235db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
236db5c6fc8SMarri Devender Rao             {
237*f2646271SRavi Teja                 lg2::error(
238*f2646271SRavi Teja                     "Error in restoring legacy certificate, ERROR_STR:{ERROR_STR}",
239*f2646271SRavi Teja                     "ERROR_STR", ex);
240db5c6fc8SMarri Devender Rao             }
241db5c6fc8SMarri Devender Rao         }
242db5c6fc8SMarri Devender Rao     }
24371957992SPatrick Williams     catch (const std::exception& ex)
244db5c6fc8SMarri Devender Rao     {
245*f2646271SRavi Teja         lg2::error(
246*f2646271SRavi Teja             "Error in certificate manager constructor, ERROR_STR:{ERROR_STR}",
247*f2646271SRavi Teja             "ERROR_STR", ex);
248db5c6fc8SMarri Devender Rao     }
249dd74bd20SJayanth Othayoth }
250589159f2SJayanth Othayoth 
25106a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath)
252cfbc8dc8SJayanth Othayoth {
253e3d47cd4SNan Zhou     if (certType != CertificateType::authority && !installedCerts.empty())
2541396511dSMarri Devender Rao     {
255cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
2561396511dSMarri Devender Rao     }
257e3d47cd4SNan Zhou     else if (certType == CertificateType::authority &&
258718eef37SNan Zhou              installedCerts.size() >= maxNumAuthorityCertificates)
2593b07b77aSZbigniew Lukwinski     {
260cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
2613b07b77aSZbigniew Lukwinski     }
262ffad1ef1SMarri Devender Rao 
2632f3563ccSZbigniew Lukwinski     std::string certObjectPath;
2642f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath))
2652f3563ccSZbigniew Lukwinski     {
2662f3563ccSZbigniew Lukwinski         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
267db029c95SKowalski, Kamil         installedCerts.emplace_back(std::make_unique<Certificate>(
2682f3563ccSZbigniew Lukwinski             bus, certObjectPath, certType, certInstallPath, filePath,
269698a5743SWilly Tu             certWatchPtr.get(), *this, /*restore=*/false));
2702f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
2712f3563ccSZbigniew Lukwinski         certIdCounter++;
2722f3563ccSZbigniew Lukwinski     }
2732f3563ccSZbigniew Lukwinski     else
2742f3563ccSZbigniew Lukwinski     {
275cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
2762f3563ccSZbigniew Lukwinski     }
2772f3563ccSZbigniew Lukwinski 
27806a69d7bSZbigniew Kurzynski     return certObjectPath;
279589159f2SJayanth Othayoth }
280ae70b3daSDeepak Kodihalli 
2816ec13c8fSNan Zhou std::vector<sdbusplus::message::object_path>
2826ec13c8fSNan Zhou     Manager::installAll(const std::string filePath)
2836ec13c8fSNan Zhou {
284e3d47cd4SNan Zhou     if (certType != CertificateType::authority)
2856ec13c8fSNan Zhou     {
2866ec13c8fSNan Zhou         elog<NotAllowed>(
2876ec13c8fSNan Zhou             NotAllowedReason("The InstallAll interface is only allowed for "
2886ec13c8fSNan Zhou                              "Authority certificates"));
2896ec13c8fSNan Zhou     }
2906ec13c8fSNan Zhou 
2916ec13c8fSNan Zhou     if (!installedCerts.empty())
2926ec13c8fSNan Zhou     {
2936ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason(
2946ec13c8fSNan Zhou             "There are already root certificates; Call DeleteAll then "
2956ec13c8fSNan Zhou             "InstallAll, or use ReplaceAll"));
2966ec13c8fSNan Zhou     }
2976ec13c8fSNan Zhou 
2986ec13c8fSNan Zhou     fs::path sourceFile(filePath);
2996ec13c8fSNan Zhou     if (!fs::exists(sourceFile))
3006ec13c8fSNan Zhou     {
301*f2646271SRavi Teja         lg2::error("File is Missing, FILE:{FILE}", "FILE", filePath);
3026ec13c8fSNan Zhou         elog<InternalFailure>();
3036ec13c8fSNan Zhou     }
3046ec13c8fSNan Zhou     std::vector<std::string> authorities = splitCertificates(sourceFile);
3056ec13c8fSNan Zhou     if (authorities.size() > maxNumAuthorityCertificates)
3066ec13c8fSNan Zhou     {
3076ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
3086ec13c8fSNan Zhou     }
3096ec13c8fSNan Zhou 
310*f2646271SRavi Teja     lg2::info("Starts authority list install");
31178357b0aSNan Zhou 
3126ec13c8fSNan Zhou     fs::path authorityStore(certInstallPath);
313223e4604SPatrick Williams     fs::path authoritiesListFile = authorityStore /
314223e4604SPatrick Williams                                    defaultAuthoritiesListFileName;
3156ec13c8fSNan Zhou 
3166ec13c8fSNan Zhou     // Atomically install all the certificates
3176ec13c8fSNan Zhou     fs::path tempPath = Certificate::generateUniqueFilePath(authorityStore);
3186ec13c8fSNan Zhou     fs::create_directory(tempPath);
3196ec13c8fSNan Zhou     // Copies the authorities list
3206ec13c8fSNan Zhou     Certificate::copyCertificate(sourceFile,
3216ec13c8fSNan Zhou                                  tempPath / defaultAuthoritiesListFileName);
3226ec13c8fSNan Zhou     std::vector<std::unique_ptr<Certificate>> tempCertificates;
3236ec13c8fSNan Zhou     uint64_t tempCertIdCounter = certIdCounter;
3246ec13c8fSNan Zhou     X509StorePtr x509Store = getX509Store(sourceFile);
3256ec13c8fSNan Zhou     for (const auto& authority : authorities)
3266ec13c8fSNan Zhou     {
327223e4604SPatrick Williams         std::string certObjectPath = objectPath + '/' +
328223e4604SPatrick Williams                                      std::to_string(tempCertIdCounter);
3296ec13c8fSNan Zhou         tempCertificates.emplace_back(std::make_unique<Certificate>(
3306ec13c8fSNan Zhou             bus, certObjectPath, certType, tempPath, *x509Store, authority,
331698a5743SWilly Tu             certWatchPtr.get(), *this, /*restore=*/false));
3326ec13c8fSNan Zhou         tempCertIdCounter++;
3336ec13c8fSNan Zhou     }
3346ec13c8fSNan Zhou 
3356ec13c8fSNan Zhou     // We are good now, issue swap
3366ec13c8fSNan Zhou     installedCerts = std::move(tempCertificates);
3376ec13c8fSNan Zhou     certIdCounter = tempCertIdCounter;
3386ec13c8fSNan Zhou     // Rename all the certificates including the authorities list
3396ec13c8fSNan Zhou     for (const fs::path& f : fs::directory_iterator(tempPath))
3406ec13c8fSNan Zhou     {
3416ec13c8fSNan Zhou         if (fs::is_symlink(f))
3426ec13c8fSNan Zhou         {
3436ec13c8fSNan Zhou             continue;
3446ec13c8fSNan Zhou         }
3456ec13c8fSNan Zhou         fs::rename(/*from=*/f, /*to=*/certInstallPath / f.filename());
3466ec13c8fSNan Zhou     }
3476ec13c8fSNan Zhou     // Update file locations and create symbol links
3486ec13c8fSNan Zhou     for (const auto& cert : installedCerts)
3496ec13c8fSNan Zhou     {
3506ec13c8fSNan Zhou         cert->setCertInstallPath(certInstallPath);
3516ec13c8fSNan Zhou         cert->setCertFilePath(certInstallPath /
3526ec13c8fSNan Zhou                               fs::path(cert->getCertFilePath()).filename());
3536ec13c8fSNan Zhou         cert->storageUpdate();
3546ec13c8fSNan Zhou     }
3556ec13c8fSNan Zhou     // Remove the temporary folder
3566ec13c8fSNan Zhou     fs::remove_all(tempPath);
3576ec13c8fSNan Zhou 
3586ec13c8fSNan Zhou     std::vector<sdbusplus::message::object_path> objects;
3596ec13c8fSNan Zhou     for (const auto& certificate : installedCerts)
3606ec13c8fSNan Zhou     {
3616ec13c8fSNan Zhou         objects.emplace_back(certificate->getObjectPath());
3626ec13c8fSNan Zhou     }
3636ec13c8fSNan Zhou 
364*f2646271SRavi Teja     lg2::info("Finishes authority list install; reload units starts");
3656ec13c8fSNan Zhou     reloadOrReset(unitToRestart);
3666ec13c8fSNan Zhou     return objects;
3676ec13c8fSNan Zhou }
3686ec13c8fSNan Zhou 
3696ec13c8fSNan Zhou std::vector<sdbusplus::message::object_path>
3706ec13c8fSNan Zhou     Manager::replaceAll(std::string filePath)
3716ec13c8fSNan Zhou {
3726ec13c8fSNan Zhou     installedCerts.clear();
3736ec13c8fSNan Zhou     certIdCounter = 1;
3746ec13c8fSNan Zhou     storageUpdate();
3756ec13c8fSNan Zhou     return installAll(std::move(filePath));
3766ec13c8fSNan Zhou }
3776ec13c8fSNan Zhou 
378a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
379ae70b3daSDeepak Kodihalli {
3806ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
3816ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
3826ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
3836ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
3846ceec40bSMarri Devender Rao     // deletion of certificates
385db029c95SKowalski, Kamil     installedCerts.clear();
3866ec13c8fSNan Zhou     // If the authorities list exists, delete it as well
387e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
3886ec13c8fSNan Zhou     {
389223e4604SPatrick Williams         if (fs::path authoritiesList = fs::path(certInstallPath) /
390223e4604SPatrick Williams                                        defaultAuthoritiesListFileName;
3916ec13c8fSNan Zhou             fs::exists(authoritiesList))
3926ec13c8fSNan Zhou         {
3936ec13c8fSNan Zhou             fs::remove(authoritiesList);
3946ec13c8fSNan Zhou         }
3956ec13c8fSNan Zhou     }
3966ec13c8fSNan Zhou     certIdCounter = 1;
3972f3563ccSZbigniew Lukwinski     storageUpdate();
3982f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
399ae70b3daSDeepak Kodihalli }
400f4682712SMarri Devender Rao 
4012f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
402a3bb38fbSZbigniew Kurzynski {
403223e4604SPatrick Williams     const std::vector<std::unique_ptr<Certificate>>::iterator& certIt =
404a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
405223e4604SPatrick Williams                      [certificate](const std::unique_ptr<Certificate>& cert) {
4062f3563ccSZbigniew Lukwinski         return (cert.get() == certificate);
407a3bb38fbSZbigniew Kurzynski         });
408a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
409a3bb38fbSZbigniew Kurzynski     {
410a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
4112f3563ccSZbigniew Lukwinski         storageUpdate();
4122f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
413a3bb38fbSZbigniew Kurzynski     }
414a3bb38fbSZbigniew Kurzynski     else
415a3bb38fbSZbigniew Kurzynski     {
416*f2646271SRavi Teja         lg2::error("Certificate does not exist, ID:{ID}", "ID",
417*f2646271SRavi Teja                    certificate->getCertId());
4182f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
4192f3563ccSZbigniew Lukwinski     }
4202f3563ccSZbigniew Lukwinski }
4212f3563ccSZbigniew Lukwinski 
4222f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
4232f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
4242f3563ccSZbigniew Lukwinski {
4252f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
4262f3563ccSZbigniew Lukwinski     {
427698a5743SWilly Tu         certificate->install(filePath, false);
4282f3563ccSZbigniew Lukwinski         storageUpdate();
4292f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
4302f3563ccSZbigniew Lukwinski     }
4312f3563ccSZbigniew Lukwinski     else
4322f3563ccSZbigniew Lukwinski     {
433cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
434a3bb38fbSZbigniew Kurzynski     }
435a3bb38fbSZbigniew Kurzynski }
436a3bb38fbSZbigniew Kurzynski 
437f4682712SMarri Devender Rao std::string Manager::generateCSR(
438f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
439f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
440f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
441f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
442f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
443f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
444f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
445f4682712SMarri Devender Rao {
446f4682712SMarri Devender Rao     // We support only one CSR.
447f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
448f4682712SMarri Devender Rao     auto pid = fork();
449f4682712SMarri Devender Rao     if (pid == -1)
450f4682712SMarri Devender Rao     {
451*f2646271SRavi Teja         lg2::error("Error occurred during forking process");
452f4682712SMarri Devender Rao         report<InternalFailure>();
453f4682712SMarri Devender Rao     }
454f4682712SMarri Devender Rao     else if (pid == 0)
455f4682712SMarri Devender Rao     {
456f4682712SMarri Devender Rao         try
457f4682712SMarri Devender Rao         {
458f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
459f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
460f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
461f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
462f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
463f4682712SMarri Devender Rao                               unstructuredName);
464f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
465f4682712SMarri Devender Rao         }
466f4682712SMarri Devender Rao         catch (const InternalFailure& e)
467f4682712SMarri Devender Rao         {
468f4682712SMarri Devender Rao             // commit the error reported in child process and exit
469f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
470f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
471f4682712SMarri Devender Rao             commit<InternalFailure>();
472f4682712SMarri Devender Rao         }
473d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
474d2393f23SRamesh Iyyar         {
475d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
476d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
477d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
478d2393f23SRamesh Iyyar             commit<InvalidArgument>();
479d2393f23SRamesh Iyyar         }
480f4682712SMarri Devender Rao     }
481f4682712SMarri Devender Rao     else
482f4682712SMarri Devender Rao     {
483f4682712SMarri Devender Rao         using namespace sdeventplus::source;
484223e4604SPatrick Williams         Child::Callback callback =
485223e4604SPatrick Williams             [this](Child& eventSource, const siginfo_t* si) {
486f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
487f4682712SMarri Devender Rao             if (si->si_status != 0)
488f4682712SMarri Devender Rao             {
489e3d47cd4SNan Zhou                 this->createCSRObject(Status::failure);
490f4682712SMarri Devender Rao             }
491f4682712SMarri Devender Rao             else
492f4682712SMarri Devender Rao             {
493e3d47cd4SNan Zhou                 this->createCSRObject(Status::success);
494f4682712SMarri Devender Rao             }
495f4682712SMarri Devender Rao         };
496f4682712SMarri Devender Rao         try
497f4682712SMarri Devender Rao         {
498f4682712SMarri Devender Rao             sigset_t ss;
499f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
500f4682712SMarri Devender Rao             {
501*f2646271SRavi Teja                 lg2::error("Unable to initialize signal set");
502f4682712SMarri Devender Rao                 elog<InternalFailure>();
503f4682712SMarri Devender Rao             }
504f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
505f4682712SMarri Devender Rao             {
506*f2646271SRavi Teja                 lg2::error("Unable to add signal to signal set");
507f4682712SMarri Devender Rao                 elog<InternalFailure>();
508f4682712SMarri Devender Rao             }
509f4682712SMarri Devender Rao 
510f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
511cfb5802aSNan Zhou             if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
512f4682712SMarri Devender Rao             {
513*f2646271SRavi Teja                 lg2::error("Unable to block signal");
514f4682712SMarri Devender Rao                 elog<InternalFailure>();
515f4682712SMarri Devender Rao             }
516f4682712SMarri Devender Rao             if (childPtr)
517f4682712SMarri Devender Rao             {
518f4682712SMarri Devender Rao                 childPtr.reset();
519f4682712SMarri Devender Rao             }
520f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
521f4682712SMarri Devender Rao                                                std::move(callback));
522f4682712SMarri Devender Rao         }
523f4682712SMarri Devender Rao         catch (const InternalFailure& e)
524f4682712SMarri Devender Rao         {
525f4682712SMarri Devender Rao             commit<InternalFailure>();
526f4682712SMarri Devender Rao         }
527f4682712SMarri Devender Rao     }
528f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
529f4682712SMarri Devender Rao     return csrObjectPath;
530f4682712SMarri Devender Rao }
531f4682712SMarri Devender Rao 
532db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
533ffad1ef1SMarri Devender Rao {
534db029c95SKowalski, Kamil     return installedCerts;
535ffad1ef1SMarri Devender Rao }
536ffad1ef1SMarri Devender Rao 
537f4682712SMarri Devender Rao void Manager::generateCSRHelper(
538f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
539f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
540f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
541f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
542f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
543f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
544f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
545f4682712SMarri Devender Rao {
546f4682712SMarri Devender Rao     int ret = 0;
547f4682712SMarri Devender Rao 
548f4682712SMarri Devender Rao     // set version of x509 req
549f4682712SMarri Devender Rao     int nVersion = 1;
550f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
551cf06ccdcSNan Zhou     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
552f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
553f4682712SMarri Devender Rao     if (ret == 0)
554f4682712SMarri Devender Rao     {
555*f2646271SRavi Teja         lg2::error("Error occurred during X509_REQ_set_version call");
556f4682712SMarri Devender Rao         elog<InternalFailure>();
557f4682712SMarri Devender Rao     }
558f4682712SMarri Devender Rao 
559f4682712SMarri Devender Rao     // set subject of x509 req
560f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
561f4682712SMarri Devender Rao 
562f4682712SMarri Devender Rao     if (!alternativeNames.empty())
563f4682712SMarri Devender Rao     {
564f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
565f4682712SMarri Devender Rao         {
566f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
567f4682712SMarri Devender Rao         }
568f4682712SMarri Devender Rao     }
569f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
570f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
571f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
572f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
573f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
574f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
575f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
576f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
577f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
578f4682712SMarri Devender Rao     if (!keyUsage.empty())
579f4682712SMarri Devender Rao     {
580f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
581f4682712SMarri Devender Rao         {
5827641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
5837641105dSMarri Devender Rao             {
5847641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
5857641105dSMarri Devender Rao             }
5867641105dSMarri Devender Rao             else
5877641105dSMarri Devender Rao             {
588f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
589f4682712SMarri Devender Rao             }
590f4682712SMarri Devender Rao         }
5917641105dSMarri Devender Rao     }
592f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
593dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
594f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
595f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
596f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
597f4682712SMarri Devender Rao 
598cf06ccdcSNan Zhou     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
5998a09b52aSRamesh Iyyar 
600*f2646271SRavi Teja     lg2::info("Given Key pair algorithm, KEYPAIRALGORITHM:{KEYPAIRALGORITHM}",
601*f2646271SRavi Teja               "KEYPAIRALGORITHM", keyPairAlgorithm);
6028a09b52aSRamesh Iyyar 
6038a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
6048a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
605c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
6068a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
607c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
6088a09b52aSRamesh Iyyar     else
6098a09b52aSRamesh Iyyar     {
610*f2646271SRavi Teja         lg2::error("Given Key pair algorithm is not supported. Supporting "
6118a09b52aSRamesh Iyyar                    "RSA and EC only");
6128a09b52aSRamesh Iyyar         elog<InvalidArgument>(
6138a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
6148a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
6158a09b52aSRamesh Iyyar     }
6168a09b52aSRamesh Iyyar 
6178a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
6188a09b52aSRamesh Iyyar     if (ret == 0)
6198a09b52aSRamesh Iyyar     {
620*f2646271SRavi Teja         lg2::error("Error occurred while setting Public key");
6218a09b52aSRamesh Iyyar         elog<InternalFailure>();
6228a09b52aSRamesh Iyyar     }
6238a09b52aSRamesh Iyyar 
6248a09b52aSRamesh Iyyar     // Write private key to file
625718eef37SNan Zhou     writePrivateKey(pKey, defaultPrivateKeyFileName);
626f4682712SMarri Devender Rao 
627f4682712SMarri Devender Rao     // set sign key of x509 req
628f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
6298a09b52aSRamesh Iyyar     if (ret == 0)
630f4682712SMarri Devender Rao     {
631*f2646271SRavi Teja         lg2::error("Error occurred while signing key of x509");
632f4682712SMarri Devender Rao         elog<InternalFailure>();
633f4682712SMarri Devender Rao     }
6348a09b52aSRamesh Iyyar 
635*f2646271SRavi Teja     lg2::info("Writing CSR to file");
636718eef37SNan Zhou     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
637c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
638f4682712SMarri Devender Rao }
639f4682712SMarri Devender Rao 
6407641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
6417641105dSMarri Devender Rao {
6427641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
6437641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
6447641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
645223e4604SPatrick Williams     auto it = std::find_if(usageList.begin(), usageList.end(),
646223e4604SPatrick Williams                            [&usage](const char* s) {
647223e4604SPatrick Williams         return (strcmp(s, usage.c_str()) == 0);
648223e4604SPatrick Williams     });
6497641105dSMarri Devender Rao     return it != usageList.end();
6507641105dSMarri Devender Rao }
651cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
652f4682712SMarri Devender Rao {
6538a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
654f4682712SMarri Devender Rao     // set keybit length to default value if not set
6558a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
656f4682712SMarri Devender Rao     {
657*f2646271SRavi Teja         lg2::info("KeyBitLength is not given.Hence, using default KeyBitLength:"
658*f2646271SRavi Teja                   "{DEFAULTKEYBITLENGTH}",
659*f2646271SRavi Teja                   "DEFAULTKEYBITLENGTH", defaultKeyBitLength);
660cf06ccdcSNan Zhou         keyBitLen = defaultKeyBitLength;
661f4682712SMarri Devender Rao     }
66226fb83efSPatrick Williams 
66326fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
66426fb83efSPatrick Williams 
66526fb83efSPatrick Williams     // generate rsa key
666cf06ccdcSNan Zhou     BignumPtr bne(BN_new(), ::BN_free);
66726fb83efSPatrick Williams     auto ret = BN_set_word(bne.get(), RSA_F4);
66826fb83efSPatrick Williams     if (ret == 0)
66926fb83efSPatrick Williams     {
670*f2646271SRavi Teja         lg2::error("Error occurred during BN_set_word call");
67126fb83efSPatrick Williams         elog<InternalFailure>();
67226fb83efSPatrick Williams     }
673762da74eSNan Zhou     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
674762da74eSNan Zhou     RSAPtr rsa(RSA_new(), ::RSA_free);
675762da74eSNan Zhou     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
676f4682712SMarri Devender Rao     if (ret != 1)
677f4682712SMarri Devender Rao     {
678*f2646271SRavi Teja         lg2::error(
679*f2646271SRavi Teja             "Error occurred during RSA_generate_key_ex call: {KEYBITLENGTH}",
680*f2646271SRavi Teja             "KEYBITLENGTH", keyBitLen);
681f4682712SMarri Devender Rao         elog<InternalFailure>();
682f4682712SMarri Devender Rao     }
683f4682712SMarri Devender Rao 
684f4682712SMarri Devender Rao     // set public key of x509 req
685cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
686762da74eSNan Zhou     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
687f4682712SMarri Devender Rao     if (ret == 0)
688f4682712SMarri Devender Rao     {
689*f2646271SRavi Teja         lg2::error("Error occurred during assign rsa key into EVP");
690f4682712SMarri Devender Rao         elog<InternalFailure>();
691f4682712SMarri Devender Rao     }
692762da74eSNan Zhou     // Now |rsa| is managed by |pKey|
693762da74eSNan Zhou     rsa.release();
6948a09b52aSRamesh Iyyar     return pKey;
69526fb83efSPatrick Williams 
69626fb83efSPatrick Williams #else
69726fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
69826fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
69926fb83efSPatrick Williams     if (!ctx)
70026fb83efSPatrick Williams     {
701*f2646271SRavi Teja         lg2::error("Error occurred creating EVP_PKEY_CTX from algorithm");
70226fb83efSPatrick Williams         elog<InternalFailure>();
70326fb83efSPatrick Williams     }
70426fb83efSPatrick Williams 
70526fb83efSPatrick Williams     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
70626fb83efSPatrick Williams         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
70726fb83efSPatrick Williams 
70826fb83efSPatrick Williams     {
709*f2646271SRavi Teja         lg2::error("Error occurred initializing keygen context");
71026fb83efSPatrick Williams         elog<InternalFailure>();
71126fb83efSPatrick Williams     }
71226fb83efSPatrick Williams 
71326fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
71426fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
71526fb83efSPatrick Williams     {
716*f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
71726fb83efSPatrick Williams         elog<InternalFailure>();
71826fb83efSPatrick Williams     }
71926fb83efSPatrick Williams 
72026fb83efSPatrick Williams     return {pKey, &::EVP_PKEY_free};
72126fb83efSPatrick Williams #endif
7228a09b52aSRamesh Iyyar }
7238a09b52aSRamesh Iyyar 
724cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
7258a09b52aSRamesh Iyyar {
7268a09b52aSRamesh Iyyar     std::string curId(curveId);
7278a09b52aSRamesh Iyyar 
7288a09b52aSRamesh Iyyar     if (curId.empty())
7298a09b52aSRamesh Iyyar     {
730*f2646271SRavi Teja         lg2::info("KeyCurveId is not given. Hence using default curve id,"
731*f2646271SRavi Teja                   "DEFAULTKEYCURVEID:{DEFAULTKEYCURVEID}",
732*f2646271SRavi Teja                   "DEFAULTKEYCURVEID", defaultKeyCurveID);
733cf06ccdcSNan Zhou         curId = defaultKeyCurveID;
7348a09b52aSRamesh Iyyar     }
7358a09b52aSRamesh Iyyar 
7368a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
7378a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
7388a09b52aSRamesh Iyyar     {
739*f2646271SRavi Teja         lg2::error(
740*f2646271SRavi Teja             "Error occurred during convert the curve id string format into NID,"
741*f2646271SRavi Teja             "KEYCURVEID:{KEYCURVEID}",
742*f2646271SRavi Teja             "KEYCURVEID", curId);
7438a09b52aSRamesh Iyyar         elog<InternalFailure>();
7448a09b52aSRamesh Iyyar     }
7458a09b52aSRamesh Iyyar 
74626fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
74726fb83efSPatrick Williams 
7488a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
7498a09b52aSRamesh Iyyar 
750cfb5802aSNan Zhou     if (ecKey == nullptr)
7518a09b52aSRamesh Iyyar     {
752*f2646271SRavi Teja         lg2::error(
753*f2646271SRavi Teja             "Error occurred during create the EC_Key object from NID, ECGROUP:{ECGROUP}",
754*f2646271SRavi Teja             "ECGROUP", ecGrp);
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);
768*f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
7698a09b52aSRamesh Iyyar         elog<InternalFailure>();
7708a09b52aSRamesh Iyyar     }
7718a09b52aSRamesh Iyyar 
772cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
7738a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
7748a09b52aSRamesh Iyyar     if (ret == 0)
7758a09b52aSRamesh Iyyar     {
7768a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
777*f2646271SRavi Teja         lg2::error("Error occurred during assign EC Key into EVP");
7788a09b52aSRamesh Iyyar         elog<InternalFailure>();
7798a09b52aSRamesh Iyyar     }
7808a09b52aSRamesh Iyyar 
7818a09b52aSRamesh Iyyar     return pKey;
78226fb83efSPatrick Williams 
78326fb83efSPatrick Williams #else
784e3d47cd4SNan Zhou     auto holderOfKey = [](EVP_PKEY* key) {
78526fb83efSPatrick Williams         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
78626fb83efSPatrick Williams             key, &::EVP_PKEY_free};
78726fb83efSPatrick Williams     };
78826fb83efSPatrick Williams 
78926fb83efSPatrick Williams     // Create context to set up curve parameters.
79026fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
79126fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
79226fb83efSPatrick Williams     if (!ctx)
79326fb83efSPatrick Williams     {
794*f2646271SRavi Teja         lg2::error("Error occurred creating EVP_PKEY_CTX for params");
79526fb83efSPatrick Williams         elog<InternalFailure>();
79626fb83efSPatrick Williams     }
79726fb83efSPatrick Williams 
79826fb83efSPatrick Williams     // Set up curve parameters.
79926fb83efSPatrick Williams     EVP_PKEY* params = nullptr;
80026fb83efSPatrick Williams 
80126fb83efSPatrick Williams     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
80226fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
80326fb83efSPatrick Williams          0) ||
80426fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
80526fb83efSPatrick Williams         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
80626fb83efSPatrick Williams     {
807*f2646271SRavi Teja         lg2::error("Error occurred setting curve parameters");
80826fb83efSPatrick Williams         elog<InternalFailure>();
80926fb83efSPatrick Williams     }
81026fb83efSPatrick Williams 
81126fb83efSPatrick Williams     // Move parameters to RAII holder.
812e3d47cd4SNan Zhou     auto pparms = holderOfKey(params);
81326fb83efSPatrick Williams 
81426fb83efSPatrick Williams     // Create new context for key.
81526fb83efSPatrick Williams     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
81626fb83efSPatrick Williams 
81726fb83efSPatrick Williams     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
81826fb83efSPatrick Williams     {
819*f2646271SRavi Teja         lg2::error("Error occurred initializing keygen context");
82026fb83efSPatrick Williams         elog<InternalFailure>();
82126fb83efSPatrick Williams     }
82226fb83efSPatrick Williams 
82326fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
82426fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
82526fb83efSPatrick Williams     {
826*f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
82726fb83efSPatrick Williams         elog<InternalFailure>();
82826fb83efSPatrick Williams     }
82926fb83efSPatrick Williams 
830e3d47cd4SNan Zhou     return holderOfKey(pKey);
83126fb83efSPatrick Williams #endif
8328a09b52aSRamesh Iyyar }
8338a09b52aSRamesh Iyyar 
834cf06ccdcSNan Zhou void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
835c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
8368a09b52aSRamesh Iyyar {
837*f2646271SRavi Teja     lg2::info("Writing private key to file");
838f4682712SMarri Devender Rao     // write private key to file
839c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
840f4682712SMarri Devender Rao 
841f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
842cfb5802aSNan Zhou     if (fp == nullptr)
843f4682712SMarri Devender Rao     {
844*f2646271SRavi Teja         lg2::error("Error occurred creating private key file");
845f4682712SMarri Devender Rao         elog<InternalFailure>();
846f4682712SMarri Devender Rao     }
847223e4604SPatrick Williams     int ret = PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0,
848223e4604SPatrick Williams                                    nullptr);
849f4682712SMarri Devender Rao     std::fclose(fp);
850f4682712SMarri Devender Rao     if (ret == 0)
851f4682712SMarri Devender Rao     {
852*f2646271SRavi Teja         lg2::error("Error occurred while writing private key to file");
853f4682712SMarri Devender Rao         elog<InternalFailure>();
854f4682712SMarri Devender Rao     }
855f4682712SMarri Devender Rao }
856f4682712SMarri Devender Rao 
857f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
858f4682712SMarri Devender Rao                        const std::string& bytes)
859f4682712SMarri Devender Rao {
860f4682712SMarri Devender Rao     if (bytes.empty())
861f4682712SMarri Devender Rao     {
862f4682712SMarri Devender Rao         return;
863f4682712SMarri Devender Rao     }
864f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
865f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
866f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
867f4682712SMarri Devender Rao     if (ret != 1)
868f4682712SMarri Devender Rao     {
869*f2646271SRavi Teja         lg2::error("Unable to set entry, FIELD:{FIELD}, VALUE:{VALUE}", "FIELD",
870*f2646271SRavi Teja                    field, "VALUE", bytes);
871f4682712SMarri Devender Rao         elog<InternalFailure>();
872f4682712SMarri Devender Rao     }
873f4682712SMarri Devender Rao }
874f4682712SMarri Devender Rao 
875f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
876f4682712SMarri Devender Rao {
877f4682712SMarri Devender Rao     if (csrPtr)
878f4682712SMarri Devender Rao     {
879f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
880f4682712SMarri Devender Rao     }
881f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
882f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
883f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
884f4682712SMarri Devender Rao }
885f4682712SMarri Devender Rao 
886cf06ccdcSNan Zhou void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
887f4682712SMarri Devender Rao {
888f4682712SMarri Devender Rao     if (fs::exists(filePath))
889f4682712SMarri Devender Rao     {
890*f2646271SRavi Teja         lg2::info("Removing the existing file, FILENAME:{FILENAME}", "FILENAME",
891*f2646271SRavi Teja                   filePath);
892f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
893f4682712SMarri Devender Rao         {
894*f2646271SRavi Teja             lg2::error("Unable to remove the file, FILENAME:{FILENAME}",
895*f2646271SRavi Teja                        "FILENAME", filePath);
896f4682712SMarri Devender Rao             elog<InternalFailure>();
897f4682712SMarri Devender Rao         }
898f4682712SMarri Devender Rao     }
899f4682712SMarri Devender Rao 
900cfb5802aSNan Zhou     FILE* fp = nullptr;
901f4682712SMarri Devender Rao 
902cfb5802aSNan Zhou     if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
903f4682712SMarri Devender Rao     {
904*f2646271SRavi Teja         lg2::error(
905*f2646271SRavi Teja             "Error opening the file to write the CSR, FILENAME:{FILENAME}",
906*f2646271SRavi Teja             "FILENAME", filePath);
907f4682712SMarri Devender Rao         elog<InternalFailure>();
908f4682712SMarri Devender Rao     }
909f4682712SMarri Devender Rao 
910f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
911f4682712SMarri Devender Rao     if (!rc)
912f4682712SMarri Devender Rao     {
913*f2646271SRavi Teja         lg2::error("PEM write routine failed, FILENAME:{FILENAME}", "FILENAME",
914*f2646271SRavi Teja                    filePath);
915f4682712SMarri Devender Rao         std::fclose(fp);
916f4682712SMarri Devender Rao         elog<InternalFailure>();
917f4682712SMarri Devender Rao     }
918f4682712SMarri Devender Rao     std::fclose(fp);
919f4682712SMarri Devender Rao }
920f4682712SMarri Devender Rao 
921db029c95SKowalski, Kamil void Manager::createCertificates()
922db029c95SKowalski, Kamil {
923db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
924db029c95SKowalski, Kamil 
925e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
926db029c95SKowalski, Kamil     {
927fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
928db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
929db029c95SKowalski, Kamil         {
930*f2646271SRavi Teja             lg2::error("Certificate installation path exists and it is "
931db029c95SKowalski, Kamil                        "not a directory");
932db029c95SKowalski, Kamil             elog<InternalFailure>();
9336ec13c8fSNan Zhou         }
9346ec13c8fSNan Zhou 
9356ec13c8fSNan Zhou         // If the authorities list exists, recover from it and return
936223e4604SPatrick Williams         if (fs::path authoritiesListFilePath = fs::path(certInstallPath) /
937223e4604SPatrick Williams                                                defaultAuthoritiesListFileName;
9386ec13c8fSNan Zhou             fs::exists(authoritiesListFilePath))
9396ec13c8fSNan Zhou         {
9406ec13c8fSNan Zhou             // remove all other files and directories
9416ec13c8fSNan Zhou             for (auto& path : fs::directory_iterator(certInstallPath))
9426ec13c8fSNan Zhou             {
9436ec13c8fSNan Zhou                 if (path.path() != authoritiesListFilePath)
9446ec13c8fSNan Zhou                 {
9456ec13c8fSNan Zhou                     fs::remove_all(path);
9466ec13c8fSNan Zhou                 }
9476ec13c8fSNan Zhou             }
9486ec13c8fSNan Zhou             installAll(authoritiesListFilePath);
949db029c95SKowalski, Kamil             return;
950db029c95SKowalski, Kamil         }
951db029c95SKowalski, Kamil 
952db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
953ffad1ef1SMarri Devender Rao         {
954ffad1ef1SMarri Devender Rao             try
955ffad1ef1SMarri Devender Rao             {
9562f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
9572f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
9582f3563ccSZbigniew Lukwinski                 // would add value.
9592f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
9602f3563ccSZbigniew Lukwinski                 {
961db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
962db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
963cf06ccdcSNan Zhou                         certType, certInstallPath, path.path(),
964698a5743SWilly Tu                         certWatchPtr.get(), *this, /*restore=*/true));
9652f3563ccSZbigniew Lukwinski                 }
966ffad1ef1SMarri Devender Rao             }
967ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
968ffad1ef1SMarri Devender Rao             {
969ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
970ffad1ef1SMarri Devender Rao             }
971ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
972ffad1ef1SMarri Devender Rao             {
973cf06ccdcSNan Zhou                 report<InvalidCertificate>(InvalidCertificateReason(
974cf06ccdcSNan Zhou                     "Existing certificate file is corrupted"));
975ffad1ef1SMarri Devender Rao             }
976ffad1ef1SMarri Devender Rao         }
977db029c95SKowalski, Kamil     }
978db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
979db029c95SKowalski, Kamil     {
980db029c95SKowalski, Kamil         try
981db029c95SKowalski, Kamil         {
982db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
9832f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
984698a5743SWilly Tu                 certInstallPath, certWatchPtr.get(), *this, /*restore=*/false));
985db029c95SKowalski, Kamil         }
986db029c95SKowalski, Kamil         catch (const InternalFailure& e)
987db029c95SKowalski, Kamil         {
988db029c95SKowalski, Kamil             report<InternalFailure>();
989db029c95SKowalski, Kamil         }
990db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
991db029c95SKowalski, Kamil         {
992cf06ccdcSNan Zhou             report<InvalidCertificate>(InvalidCertificateReason(
993cf06ccdcSNan Zhou                 "Existing certificate file is corrupted"));
994db029c95SKowalski, Kamil         }
995db029c95SKowalski, Kamil     }
996db029c95SKowalski, Kamil }
997c6e58c7eSRamesh Iyyar 
998c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
999c6e58c7eSRamesh Iyyar {
1000223e4604SPatrick Williams     fs::path rsaPrivateKeyFileName = certParentInstallPath /
1001223e4604SPatrick Williams                                      defaultRSAPrivateKeyFileName;
1002c6e58c7eSRamesh Iyyar 
1003c6e58c7eSRamesh Iyyar     try
1004c6e58c7eSRamesh Iyyar     {
1005c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
1006c6e58c7eSRamesh Iyyar         {
1007cf06ccdcSNan Zhou             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
1008718eef37SNan Zhou                             defaultRSAPrivateKeyFileName);
1009c6e58c7eSRamesh Iyyar         }
1010c6e58c7eSRamesh Iyyar     }
1011c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
1012c6e58c7eSRamesh Iyyar     {
1013c6e58c7eSRamesh Iyyar         report<InternalFailure>();
1014c6e58c7eSRamesh Iyyar     }
1015c6e58c7eSRamesh Iyyar }
1016c6e58c7eSRamesh Iyyar 
1017cf06ccdcSNan Zhou EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
1018c6e58c7eSRamesh Iyyar {
1019cf06ccdcSNan Zhou     if (keyBitLength != supportedKeyBitLength)
1020c6e58c7eSRamesh Iyyar     {
1021*f2646271SRavi Teja         lg2::error(
1022*f2646271SRavi Teja             "Given Key bit length is not supported, GIVENKEYBITLENGTH:"
1023*f2646271SRavi Teja             "{GIVENKEYBITLENGTH}, SUPPORTEDKEYBITLENGTH:{SUPPORTEDKEYBITLENGTH}",
1024*f2646271SRavi Teja             "GIVENKEYBITLENGTH", keyBitLength, "SUPPORTEDKEYBITLENGTH",
1025*f2646271SRavi Teja             supportedKeyBitLength);
1026c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
1027c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1028c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1029c6e58c7eSRamesh Iyyar     }
1030223e4604SPatrick Williams     fs::path rsaPrivateKeyFileName = certParentInstallPath /
1031223e4604SPatrick Williams                                      defaultRSAPrivateKeyFileName;
1032c6e58c7eSRamesh Iyyar 
1033c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1034c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
1035c6e58c7eSRamesh Iyyar     {
1036*f2646271SRavi Teja         lg2::error(
1037*f2646271SRavi Teja             "Unable to open RSA private key file to read, RSAKEYFILE:{RSAKEYFILE},"
1038*f2646271SRavi Teja             "ERRORREASON:{ERRORREASON}",
1039*f2646271SRavi Teja             "RSAKEYFILE", rsaPrivateKeyFileName, "ERRORREASON",
1040*f2646271SRavi Teja             strerror(errno));
1041c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1042c6e58c7eSRamesh Iyyar     }
1043c6e58c7eSRamesh Iyyar 
1044cf06ccdcSNan Zhou     EVPPkeyPtr privateKey(
1045c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1046c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
1047c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
1048c6e58c7eSRamesh Iyyar 
1049c6e58c7eSRamesh Iyyar     if (!privateKey)
1050c6e58c7eSRamesh Iyyar     {
1051*f2646271SRavi Teja         lg2::error("Error occurred during PEM_read_PrivateKey call");
1052c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1053c6e58c7eSRamesh Iyyar     }
1054c6e58c7eSRamesh Iyyar     return privateKey;
1055c6e58c7eSRamesh Iyyar }
10562f3563ccSZbigniew Lukwinski 
10572f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
10582f3563ccSZbigniew Lukwinski {
1059e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
10602f3563ccSZbigniew Lukwinski     {
10612f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
10622f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
10632f3563ccSZbigniew Lukwinski         {
10642f3563ccSZbigniew Lukwinski             try
10652f3563ccSZbigniew Lukwinski             {
10662f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
10672f3563ccSZbigniew Lukwinski                 {
10682f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
10692f3563ccSZbigniew Lukwinski                 }
10702f3563ccSZbigniew Lukwinski             }
10712f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
10722f3563ccSZbigniew Lukwinski             {
1073*f2646271SRavi Teja                 lg2::error(
1074*f2646271SRavi Teja                     "Failed to remove symlink for certificate, ERR:{ERR} SYMLINK:{SYMLINK}",
1075*f2646271SRavi Teja                     "ERR", e, "SYMLINK", certPath.path().string());
10762f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
10772f3563ccSZbigniew Lukwinski             }
10782f3563ccSZbigniew Lukwinski         }
10792f3563ccSZbigniew Lukwinski     }
10802f3563ccSZbigniew Lukwinski 
10812f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
10822f3563ccSZbigniew Lukwinski     {
10832f3563ccSZbigniew Lukwinski         cert->storageUpdate();
10842f3563ccSZbigniew Lukwinski     }
10852f3563ccSZbigniew Lukwinski }
10862f3563ccSZbigniew Lukwinski 
1087cf06ccdcSNan Zhou void Manager::reloadOrReset(const std::string& unit)
10882f3563ccSZbigniew Lukwinski {
10892f3563ccSZbigniew Lukwinski     if (!unit.empty())
10902f3563ccSZbigniew Lukwinski     {
10912f3563ccSZbigniew Lukwinski         try
10922f3563ccSZbigniew Lukwinski         {
1093cf06ccdcSNan Zhou             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1094cf06ccdcSNan Zhou             constexpr auto defaultSystemdObjectPath =
1095cf06ccdcSNan Zhou                 "/org/freedesktop/systemd1";
1096cf06ccdcSNan Zhou             constexpr auto defaultSystemdInterface =
10972f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
1098cf06ccdcSNan Zhou             auto method = bus.new_method_call(
1099cf06ccdcSNan Zhou                 defaultSystemdService, defaultSystemdObjectPath,
1100cf06ccdcSNan Zhou                 defaultSystemdInterface, "ReloadOrRestartUnit");
11012f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
11022f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
11032f3563ccSZbigniew Lukwinski         }
1104b3dbfb37SPatrick Williams         catch (const sdbusplus::exception_t& e)
11052f3563ccSZbigniew Lukwinski         {
1106*f2646271SRavi Teja             lg2::error(
1107*f2646271SRavi Teja                 "Failed to reload or restart service, ERR:{ERR}, UNIT:{UNIT}",
1108*f2646271SRavi Teja                 "ERR", e, "UNIT", unit);
11092f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
11102f3563ccSZbigniew Lukwinski         }
11112f3563ccSZbigniew Lukwinski     }
11122f3563ccSZbigniew Lukwinski }
11132f3563ccSZbigniew Lukwinski 
11142f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
11152f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
11162f3563ccSZbigniew Lukwinski {
11172f3563ccSZbigniew Lukwinski     if (std::any_of(
11182f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
1119223e4604SPatrick Williams             [&filePath, certToDrop](const std::unique_ptr<Certificate>& cert) {
11202f3563ccSZbigniew Lukwinski         return cert.get() != certToDrop && cert->isSame(filePath);
11212f3563ccSZbigniew Lukwinski             }))
11222f3563ccSZbigniew Lukwinski     {
11232f3563ccSZbigniew Lukwinski         return false;
11242f3563ccSZbigniew Lukwinski     }
11252f3563ccSZbigniew Lukwinski     else
11262f3563ccSZbigniew Lukwinski     {
11272f3563ccSZbigniew Lukwinski         return true;
11282f3563ccSZbigniew Lukwinski     }
11292f3563ccSZbigniew Lukwinski }
11302f3563ccSZbigniew Lukwinski 
1131e1289adfSNan Zhou } // namespace phosphor::certs
1132