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>
10*8dbcc72dSAndrew 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  */
splitCertificates(const std::string & sourceFilePath)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 
Manager(sdbusplus::bus_t & bus,sdeventplus::Event & event,const char * path,CertificateType type,const std::string & unit,const std::string & installPath)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) :
134cf06ccdcSNan Zhou     internal::ManagerInterface(bus, path),
135f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
136c6e58c7eSRamesh Iyyar     unitToRestart(std::move(unit)), 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
187223e4604SPatrick Williams             certWatchPtr = std::make_unique<Watch>(event, certInstallPath,
188223e4604SPatrick Williams                                                    [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 
install(const std::string filePath)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>
installAll(const std::string filePath)2836ec13c8fSNan Zhou     Manager::installAll(const std::string filePath)
2846ec13c8fSNan Zhou {
285e3d47cd4SNan Zhou     if (certType != CertificateType::authority)
2866ec13c8fSNan Zhou     {
2876ec13c8fSNan Zhou         elog<NotAllowed>(
2886ec13c8fSNan Zhou             NotAllowedReason("The InstallAll interface is only allowed for "
2896ec13c8fSNan Zhou                              "Authority certificates"));
2906ec13c8fSNan Zhou     }
2916ec13c8fSNan Zhou 
2926ec13c8fSNan Zhou     if (!installedCerts.empty())
2936ec13c8fSNan Zhou     {
2946ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason(
2956ec13c8fSNan Zhou             "There are already root certificates; Call DeleteAll then "
2966ec13c8fSNan Zhou             "InstallAll, or use ReplaceAll"));
2976ec13c8fSNan Zhou     }
2986ec13c8fSNan Zhou 
2996ec13c8fSNan Zhou     fs::path sourceFile(filePath);
3006ec13c8fSNan Zhou     if (!fs::exists(sourceFile))
3016ec13c8fSNan Zhou     {
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);
314223e4604SPatrick Williams     fs::path authoritiesListFile = authorityStore /
315223e4604SPatrick Williams                                    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     {
328223e4604SPatrick Williams         std::string certObjectPath = objectPath + '/' +
329223e4604SPatrick Williams                                      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);
3526ec13c8fSNan Zhou         cert->setCertFilePath(certInstallPath /
3536ec13c8fSNan Zhou                               fs::path(cert->getCertFilePath()).filename());
3546ec13c8fSNan Zhou         cert->storageUpdate();
3556ec13c8fSNan Zhou     }
3566ec13c8fSNan Zhou     // Remove the temporary folder
3576ec13c8fSNan Zhou     fs::remove_all(tempPath);
3586ec13c8fSNan Zhou 
3596ec13c8fSNan Zhou     std::vector<sdbusplus::message::object_path> objects;
3606ec13c8fSNan Zhou     for (const auto& certificate : installedCerts)
3616ec13c8fSNan Zhou     {
3626ec13c8fSNan Zhou         objects.emplace_back(certificate->getObjectPath());
3636ec13c8fSNan Zhou     }
3646ec13c8fSNan Zhou 
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>
replaceAll(std::string filePath)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 
deleteAll()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     {
390223e4604SPatrick Williams         if (fs::path authoritiesList = fs::path(certInstallPath) /
391223e4604SPatrick Williams                                        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 
deleteCertificate(const Certificate * const certificate)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 
replaceCertificate(Certificate * const certificate,const std::string & filePath)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 
generateCSR(std::vector<std::string> alternativeNames,std::string challengePassword,std::string city,std::string commonName,std::string contactPerson,std::string country,std::string email,std::string givenName,std::string initials,int64_t keyBitLength,std::string keyCurveId,std::string keyPairAlgorithm,std::vector<std::string> keyUsage,std::string organization,std::string organizationalUnit,std::string state,std::string surname,std::string unstructuredName)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         {
459f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
460f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
461f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
462f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
463f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
464f4682712SMarri Devender Rao                               unstructuredName);
465f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
466f4682712SMarri Devender Rao         }
467f4682712SMarri Devender Rao         catch (const InternalFailure& e)
468f4682712SMarri Devender Rao         {
469f4682712SMarri Devender Rao             // commit the error reported in child process and exit
470f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
471f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
472f4682712SMarri Devender Rao             commit<InternalFailure>();
473f4682712SMarri Devender Rao         }
474d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
475d2393f23SRamesh Iyyar         {
476d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
477d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
478d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
479d2393f23SRamesh Iyyar             commit<InvalidArgument>();
480d2393f23SRamesh Iyyar         }
481f4682712SMarri Devender Rao     }
482f4682712SMarri Devender Rao     else
483f4682712SMarri Devender Rao     {
484f4682712SMarri Devender Rao         using namespace sdeventplus::source;
485d96b81caSPatrick Williams         Child::Callback callback = [this](Child& eventSource,
486d96b81caSPatrick Williams                                           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 
getCertificates()533db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
534ffad1ef1SMarri Devender Rao {
535db029c95SKowalski, Kamil     return installedCerts;
536ffad1ef1SMarri Devender Rao }
537ffad1ef1SMarri Devender Rao 
generateCSRHelper(std::vector<std::string> alternativeNames,std::string challengePassword,std::string city,std::string commonName,std::string contactPerson,std::string country,std::string email,std::string givenName,std::string initials,int64_t keyBitLength,std::string keyCurveId,std::string keyPairAlgorithm,std::vector<std::string> keyUsage,std::string organization,std::string organizationalUnit,std::string state,std::string surname,std::string unstructuredName)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");
613*8dbcc72dSAndrew 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");
625*8dbcc72dSAndrew 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 
isExtendedKeyUsage(const std::string & usage)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 }
generateRSAKeyPair(const int64_t keyBitLength)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");
664*8dbcc72dSAndrew 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);
675*8dbcc72dSAndrew 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");
685*8dbcc72dSAndrew 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");
698*8dbcc72dSAndrew 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");
707*8dbcc72dSAndrew 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");
715*8dbcc72dSAndrew 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 
generateECKeyPair(const std::string & curveId)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);
754*8dbcc72dSAndrew 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");
769*8dbcc72dSAndrew 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");
779*8dbcc72dSAndrew 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");
797*8dbcc72dSAndrew 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");
811*8dbcc72dSAndrew 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");
824*8dbcc72dSAndrew 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");
832*8dbcc72dSAndrew 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 
writePrivateKey(const EVPPkeyPtr & pKey,const std::string & privKeyFileName)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     }
853223e4604SPatrick Williams     int ret = PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0,
854223e4604SPatrick Williams                                    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 
addEntry(X509_NAME * x509Name,const char * field,const std::string & bytes)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);
877*8dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
878f4682712SMarri Devender Rao         elog<InternalFailure>();
879f4682712SMarri Devender Rao     }
880f4682712SMarri Devender Rao }
881f4682712SMarri Devender Rao 
createCSRObject(const Status & status)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 
writeCSR(const std::string & filePath,const X509ReqPtr & x509Req)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 
createCertificates()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
943223e4604SPatrick Williams         if (fs::path authoritiesListFilePath = fs::path(certInstallPath) /
944223e4604SPatrick Williams                                                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 
createRSAPrivateKeyFile()1005c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
1006c6e58c7eSRamesh Iyyar {
1007223e4604SPatrick Williams     fs::path rsaPrivateKeyFileName = certParentInstallPath /
1008223e4604SPatrick Williams                                      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 
getRSAKeyPair(const int64_t keyBitLength)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     }
1037223e4604SPatrick Williams     fs::path rsaPrivateKeyFileName = certParentInstallPath /
1038223e4604SPatrick Williams                                      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 
storageUpdate()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 
reloadOrReset(const std::string & unit)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 
isCertificateUnique(const std::string & filePath,const Certificate * const certToDrop)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