xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 5b3ee057e56ec3186e6543366aa1be3ae9629263)
1014be0bfSNan Zhou #include "config.h"
2014be0bfSNan Zhou 
3cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
4cfbc8dc8SJayanth Othayoth 
56ec13c8fSNan Zhou #include "x509_utils.hpp"
66ec13c8fSNan Zhou 
7014be0bfSNan Zhou #include <openssl/asn1.h>
8014be0bfSNan Zhou #include <openssl/bn.h>
9014be0bfSNan Zhou #include <openssl/ec.h>
108dbcc72dSAndrew Geissler #include <openssl/err.h>
1126fb83efSPatrick Williams #include <openssl/evp.h>
12014be0bfSNan Zhou #include <openssl/obj_mac.h>
13014be0bfSNan Zhou #include <openssl/objects.h>
14014be0bfSNan Zhou #include <openssl/opensslv.h>
15f4682712SMarri Devender Rao #include <openssl/pem.h>
16014be0bfSNan Zhou #include <openssl/rsa.h>
17f4682712SMarri Devender Rao #include <unistd.h>
18f4682712SMarri Devender Rao 
19223e4604SPatrick Williams #include <phosphor-logging/elog-errors.hpp>
20223e4604SPatrick Williams #include <phosphor-logging/elog.hpp>
21f2646271SRavi Teja #include <phosphor-logging/lg2.hpp>
22223e4604SPatrick Williams #include <sdbusplus/bus.hpp>
23223e4604SPatrick Williams #include <sdbusplus/exception.hpp>
24223e4604SPatrick Williams #include <sdbusplus/message.hpp>
25223e4604SPatrick Williams #include <sdeventplus/source/base.hpp>
26223e4604SPatrick Williams #include <sdeventplus/source/child.hpp>
27223e4604SPatrick Williams #include <xyz/openbmc_project/Certs/error.hpp>
28223e4604SPatrick Williams #include <xyz/openbmc_project/Common/error.hpp>
29223e4604SPatrick Williams 
30a3bb38fbSZbigniew Kurzynski #include <algorithm>
31014be0bfSNan Zhou #include <array>
32014be0bfSNan Zhou #include <cerrno>
33014be0bfSNan Zhou #include <chrono>
34014be0bfSNan Zhou #include <csignal>
35014be0bfSNan Zhou #include <cstdio>
36014be0bfSNan Zhou #include <cstdlib>
37014be0bfSNan Zhou #include <cstring>
38014be0bfSNan Zhou #include <exception>
396ec13c8fSNan Zhou #include <fstream>
40014be0bfSNan Zhou #include <utility>
412f3563ccSZbigniew Lukwinski 
42e1289adfSNan Zhou namespace phosphor::certs
43cfbc8dc8SJayanth Othayoth {
44cf06ccdcSNan Zhou namespace
45cf06ccdcSNan Zhou {
46cf06ccdcSNan Zhou namespace fs = std::filesystem;
47cf06ccdcSNan Zhou using ::phosphor::logging::commit;
48cf06ccdcSNan Zhou using ::phosphor::logging::elog;
49cf06ccdcSNan Zhou using ::phosphor::logging::report;
50cfbc8dc8SJayanth Othayoth 
51cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
52cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
53cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
54cf06ccdcSNan Zhou using NotAllowedReason =
55cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
56cf06ccdcSNan Zhou using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
57cf06ccdcSNan Zhou     Certs::InvalidCertificate::REASON;
58cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
59cf06ccdcSNan Zhou using Argument =
60cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
61c6e58c7eSRamesh Iyyar 
62cf06ccdcSNan Zhou // RAII support for openSSL functions.
63cf06ccdcSNan Zhou using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
64cf06ccdcSNan Zhou using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
65cf06ccdcSNan Zhou using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
666ec13c8fSNan Zhou using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
67cf06ccdcSNan Zhou 
68cf06ccdcSNan Zhou constexpr int supportedKeyBitLength = 2048;
69cf06ccdcSNan Zhou constexpr int defaultKeyBitLength = 2048;
70cf06ccdcSNan Zhou // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
71cf06ccdcSNan Zhou constexpr auto defaultKeyCurveID = "secp224r1";
726ec13c8fSNan Zhou // PEM certificate block markers, defined in go/rfc/7468.
736ec13c8fSNan Zhou constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
746ec13c8fSNan Zhou constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
756ec13c8fSNan Zhou 
766ec13c8fSNan Zhou /**
776ec13c8fSNan Zhou  * @brief Splits the given authorities list file and returns an array of
786ec13c8fSNan Zhou  * individual PEM encoded x509 certificate.
796ec13c8fSNan Zhou  *
806ec13c8fSNan Zhou  * @param[in] sourceFilePath - Path to the authorities list file.
816ec13c8fSNan Zhou  *
826ec13c8fSNan Zhou  * @return An array of individual PEM encoded x509 certificate
836ec13c8fSNan Zhou  */
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) :
134a2f68d8bSPatrick Williams     internal::ManagerInterface(bus, path), bus(bus), event(event),
135a2f68d8bSPatrick Williams     objectPath(path), certType(type), unitToRestart(std::move(unit)),
136a2f68d8bSPatrick Williams     certInstallPath(std::move(installPath)),
137c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
138cfbc8dc8SJayanth Othayoth {
139db5c6fc8SMarri Devender Rao     try
140db5c6fc8SMarri Devender Rao     {
141fe590c4eSZbigniew Lukwinski         // Create certificate directory if not existing.
142bf3cf751SNan Zhou         // Set correct certificate directory permissions.
143fe590c4eSZbigniew Lukwinski         fs::path certDirectory;
144b57d75e2SMarri Devender Rao         try
145b57d75e2SMarri Devender Rao         {
146e3d47cd4SNan Zhou             if (certType == CertificateType::authority)
147b57d75e2SMarri Devender Rao             {
148fe590c4eSZbigniew Lukwinski                 certDirectory = certInstallPath;
149b57d75e2SMarri Devender Rao             }
150fe590c4eSZbigniew Lukwinski             else
151fe590c4eSZbigniew Lukwinski             {
152fe590c4eSZbigniew Lukwinski                 certDirectory = certParentInstallPath;
153fe590c4eSZbigniew Lukwinski             }
154fe590c4eSZbigniew Lukwinski 
155fe590c4eSZbigniew Lukwinski             if (!fs::exists(certDirectory))
156fe590c4eSZbigniew Lukwinski             {
157fe590c4eSZbigniew Lukwinski                 fs::create_directories(certDirectory);
158fe590c4eSZbigniew Lukwinski             }
159fe590c4eSZbigniew Lukwinski 
160667286e4SMarri Devender Rao             auto permission = fs::perms::owner_read | fs::perms::owner_write |
161667286e4SMarri Devender Rao                               fs::perms::owner_exec;
162db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
163db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
1642f3563ccSZbigniew Lukwinski             storageUpdate();
165b57d75e2SMarri Devender Rao         }
16671957992SPatrick Williams         catch (const fs::filesystem_error& e)
167b57d75e2SMarri Devender Rao         {
168f2646271SRavi Teja             lg2::error(
169f2646271SRavi Teja                 "Failed to create directory, ERR:{ERR}, DIRECTORY:{DIRECTORY}",
170f2646271SRavi Teja                 "ERR", e, "DIRECTORY", certParentInstallPath);
171b57d75e2SMarri Devender Rao             report<InternalFailure>();
172b57d75e2SMarri Devender Rao         }
173b57d75e2SMarri Devender Rao 
174c6e58c7eSRamesh Iyyar         // Generating RSA private key file if certificate type is server/client
175e3d47cd4SNan Zhou         if (certType != CertificateType::authority)
176c6e58c7eSRamesh Iyyar         {
177c6e58c7eSRamesh Iyyar             createRSAPrivateKeyFile();
178c6e58c7eSRamesh Iyyar         }
179c6e58c7eSRamesh Iyyar 
180ffad1ef1SMarri Devender Rao         // restore any existing certificates
181db029c95SKowalski, Kamil         createCertificates();
182ffad1ef1SMarri Devender Rao 
183ffad1ef1SMarri Devender Rao         // watch is not required for authority certificates
184e3d47cd4SNan Zhou         if (certType != CertificateType::authority)
185ffad1ef1SMarri Devender Rao         {
186ffad1ef1SMarri Devender Rao             // watch for certificate file create/replace
187a2f68d8bSPatrick Williams             certWatchPtr = std::make_unique<
188a2f68d8bSPatrick Williams                 Watch>(event, certInstallPath, [this]() {
189bf7c588cSMarri Devender Rao                 try
190bf7c588cSMarri Devender Rao                 {
191ffad1ef1SMarri Devender Rao                     // if certificate file existing update it
192db029c95SKowalski, Kamil                     if (!installedCerts.empty())
193ffad1ef1SMarri Devender Rao                     {
194f2646271SRavi Teja                         lg2::info("Inotify callback to update "
195db5c6fc8SMarri Devender Rao                                   "certificate properties");
196db029c95SKowalski, Kamil                         installedCerts[0]->populateProperties();
197ffad1ef1SMarri Devender Rao                     }
198ffad1ef1SMarri Devender Rao                     else
199ffad1ef1SMarri Devender Rao                     {
200f2646271SRavi Teja                         lg2::info(
201ffad1ef1SMarri Devender Rao                             "Inotify callback to create certificate object");
202db029c95SKowalski, Kamil                         createCertificates();
203ffad1ef1SMarri Devender Rao                     }
204bf7c588cSMarri Devender Rao                 }
205bf7c588cSMarri Devender Rao                 catch (const InternalFailure& e)
206bf7c588cSMarri Devender Rao                 {
207ffad1ef1SMarri Devender Rao                     commit<InternalFailure>();
208bf7c588cSMarri Devender Rao                 }
209bf7c588cSMarri Devender Rao                 catch (const InvalidCertificate& e)
210bf7c588cSMarri Devender Rao                 {
211ffad1ef1SMarri Devender Rao                     commit<InvalidCertificate>();
212bf7c588cSMarri Devender Rao                 }
213ffad1ef1SMarri Devender Rao             });
214bf7c588cSMarri Devender Rao         }
215db029c95SKowalski, Kamil         else
216db029c95SKowalski, Kamil         {
217db5c6fc8SMarri Devender Rao             try
218db5c6fc8SMarri Devender Rao             {
219db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
220db5c6fc8SMarri Devender Rao                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
221db029c95SKowalski, Kamil                 {
222f2646271SRavi Teja                     lg2::notice(
223f2646271SRavi Teja                         "Legacy certificate detected, will be installed from,"
224f2646271SRavi Teja                         "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
225f2646271SRavi Teja                         "SINGLE_CERTPATH", singleCertPath);
226db5c6fc8SMarri Devender Rao                     install(singleCertPath);
227db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
228db029c95SKowalski, Kamil                     {
229f2646271SRavi Teja                         lg2::error("Unable to remove old certificate from,"
230f2646271SRavi Teja                                    "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
231f2646271SRavi Teja                                    "SINGLE_CERTPATH", singleCertPath);
232db029c95SKowalski, Kamil                         elog<InternalFailure>();
233db029c95SKowalski, Kamil                     }
234db029c95SKowalski, Kamil                 }
235db029c95SKowalski, Kamil             }
236db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
237db5c6fc8SMarri Devender Rao             {
238f2646271SRavi Teja                 lg2::error(
239f2646271SRavi Teja                     "Error in restoring legacy certificate, ERROR_STR:{ERROR_STR}",
240f2646271SRavi Teja                     "ERROR_STR", ex);
241db5c6fc8SMarri Devender Rao             }
242db5c6fc8SMarri Devender Rao         }
243db5c6fc8SMarri Devender Rao     }
24471957992SPatrick Williams     catch (const std::exception& ex)
245db5c6fc8SMarri Devender Rao     {
246f2646271SRavi Teja         lg2::error(
247f2646271SRavi Teja             "Error in certificate manager constructor, ERROR_STR:{ERROR_STR}",
248f2646271SRavi Teja             "ERROR_STR", ex);
249db5c6fc8SMarri Devender Rao     }
250dd74bd20SJayanth Othayoth }
251589159f2SJayanth Othayoth 
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     {
287a2f68d8bSPatrick Williams         elog<NotAllowed>(NotAllowedReason(
288a2f68d8bSPatrick Williams             "The InstallAll interface is only allowed for "
2896ec13c8fSNan Zhou             "Authority certificates"));
2906ec13c8fSNan Zhou     }
2916ec13c8fSNan Zhou 
2926ec13c8fSNan Zhou     if (!installedCerts.empty())
2936ec13c8fSNan Zhou     {
2946ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason(
2956ec13c8fSNan Zhou             "There are already root certificates; Call DeleteAll then "
2966ec13c8fSNan Zhou             "InstallAll, or use ReplaceAll"));
2976ec13c8fSNan Zhou     }
2986ec13c8fSNan Zhou 
2996ec13c8fSNan Zhou     fs::path sourceFile(filePath);
3006ec13c8fSNan Zhou     if (!fs::exists(sourceFile))
3016ec13c8fSNan Zhou     {
302f2646271SRavi Teja         lg2::error("File is Missing, FILE:{FILE}", "FILE", filePath);
3036ec13c8fSNan Zhou         elog<InternalFailure>();
3046ec13c8fSNan Zhou     }
3056ec13c8fSNan Zhou     std::vector<std::string> authorities = splitCertificates(sourceFile);
3066ec13c8fSNan Zhou     if (authorities.size() > maxNumAuthorityCertificates)
3076ec13c8fSNan Zhou     {
3086ec13c8fSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
3096ec13c8fSNan Zhou     }
3106ec13c8fSNan Zhou 
311f2646271SRavi Teja     lg2::info("Starts authority list install");
31278357b0aSNan Zhou 
3136ec13c8fSNan Zhou     fs::path authorityStore(certInstallPath);
3146ec13c8fSNan Zhou 
3156ec13c8fSNan Zhou     // Atomically install all the certificates
3166ec13c8fSNan Zhou     fs::path tempPath = Certificate::generateUniqueFilePath(authorityStore);
3176ec13c8fSNan Zhou     fs::create_directory(tempPath);
3186ec13c8fSNan Zhou     // Copies the authorities list
3196ec13c8fSNan Zhou     Certificate::copyCertificate(sourceFile,
3206ec13c8fSNan Zhou                                  tempPath / defaultAuthoritiesListFileName);
3216ec13c8fSNan Zhou     std::vector<std::unique_ptr<Certificate>> tempCertificates;
3226ec13c8fSNan Zhou     uint64_t tempCertIdCounter = certIdCounter;
3236ec13c8fSNan Zhou     X509StorePtr x509Store = getX509Store(sourceFile);
3246ec13c8fSNan Zhou     for (const auto& authority : authorities)
3256ec13c8fSNan Zhou     {
326a2f68d8bSPatrick Williams         std::string certObjectPath =
327a2f68d8bSPatrick Williams             objectPath + '/' + std::to_string(tempCertIdCounter);
3286ec13c8fSNan Zhou         tempCertificates.emplace_back(std::make_unique<Certificate>(
3296ec13c8fSNan Zhou             bus, certObjectPath, certType, tempPath, *x509Store, authority,
330698a5743SWilly Tu             certWatchPtr.get(), *this, /*restore=*/false));
3316ec13c8fSNan Zhou         tempCertIdCounter++;
3326ec13c8fSNan Zhou     }
3336ec13c8fSNan Zhou 
3346ec13c8fSNan Zhou     // We are good now, issue swap
3356ec13c8fSNan Zhou     installedCerts = std::move(tempCertificates);
3366ec13c8fSNan Zhou     certIdCounter = tempCertIdCounter;
3376ec13c8fSNan Zhou     // Rename all the certificates including the authorities list
3386ec13c8fSNan Zhou     for (const fs::path& f : fs::directory_iterator(tempPath))
3396ec13c8fSNan Zhou     {
3406ec13c8fSNan Zhou         if (fs::is_symlink(f))
3416ec13c8fSNan Zhou         {
3426ec13c8fSNan Zhou             continue;
3436ec13c8fSNan Zhou         }
3446ec13c8fSNan Zhou         fs::rename(/*from=*/f, /*to=*/certInstallPath / f.filename());
3456ec13c8fSNan Zhou     }
3466ec13c8fSNan Zhou     // Update file locations and create symbol links
3476ec13c8fSNan Zhou     for (const auto& cert : installedCerts)
3486ec13c8fSNan Zhou     {
3496ec13c8fSNan Zhou         cert->setCertInstallPath(certInstallPath);
350a2f68d8bSPatrick Williams         cert->setCertFilePath(
351a2f68d8bSPatrick Williams             certInstallPath / fs::path(cert->getCertFilePath()).filename());
3526ec13c8fSNan Zhou         cert->storageUpdate();
3536ec13c8fSNan Zhou     }
3546ec13c8fSNan Zhou     // Remove the temporary folder
3556ec13c8fSNan Zhou     fs::remove_all(tempPath);
3566ec13c8fSNan Zhou 
3576ec13c8fSNan Zhou     std::vector<sdbusplus::message::object_path> objects;
3586ec13c8fSNan Zhou     for (const auto& certificate : installedCerts)
3596ec13c8fSNan Zhou     {
3606ec13c8fSNan Zhou         objects.emplace_back(certificate->getObjectPath());
3616ec13c8fSNan Zhou     }
3626ec13c8fSNan Zhou 
363f2646271SRavi Teja     lg2::info("Finishes authority list install; reload units starts");
3646ec13c8fSNan Zhou     reloadOrReset(unitToRestart);
3656ec13c8fSNan Zhou     return objects;
3666ec13c8fSNan Zhou }
3676ec13c8fSNan Zhou 
3686ec13c8fSNan Zhou std::vector<sdbusplus::message::object_path>
replaceAll(std::string filePath)3696ec13c8fSNan Zhou     Manager::replaceAll(std::string filePath)
3706ec13c8fSNan Zhou {
3716ec13c8fSNan Zhou     installedCerts.clear();
3726ec13c8fSNan Zhou     certIdCounter = 1;
3736ec13c8fSNan Zhou     storageUpdate();
3746ec13c8fSNan Zhou     return installAll(std::move(filePath));
3756ec13c8fSNan Zhou }
3766ec13c8fSNan Zhou 
deleteAll()377a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
378ae70b3daSDeepak Kodihalli {
3796ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
3806ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
3816ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
3826ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
3836ceec40bSMarri Devender Rao     // deletion of certificates
384db029c95SKowalski, Kamil     installedCerts.clear();
3856ec13c8fSNan Zhou     // If the authorities list exists, delete it as well
386e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
3876ec13c8fSNan Zhou     {
388a2f68d8bSPatrick Williams         if (fs::path authoritiesList =
389a2f68d8bSPatrick Williams                 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
3906ec13c8fSNan Zhou             fs::exists(authoritiesList))
3916ec13c8fSNan Zhou         {
3926ec13c8fSNan Zhou             fs::remove(authoritiesList);
3936ec13c8fSNan Zhou         }
3946ec13c8fSNan Zhou     }
3956ec13c8fSNan Zhou     certIdCounter = 1;
3962f3563ccSZbigniew Lukwinski     storageUpdate();
3972f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
398ae70b3daSDeepak Kodihalli }
399f4682712SMarri Devender Rao 
deleteCertificate(const Certificate * const certificate)4002f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
401a3bb38fbSZbigniew Kurzynski {
402223e4604SPatrick Williams     const std::vector<std::unique_ptr<Certificate>>::iterator& certIt =
403a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
404223e4604SPatrick Williams                      [certificate](const std::unique_ptr<Certificate>& cert) {
4052f3563ccSZbigniew Lukwinski                          return (cert.get() == certificate);
406a3bb38fbSZbigniew Kurzynski                      });
407a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
408a3bb38fbSZbigniew Kurzynski     {
409a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
4102f3563ccSZbigniew Lukwinski         storageUpdate();
4112f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
412a3bb38fbSZbigniew Kurzynski     }
413a3bb38fbSZbigniew Kurzynski     else
414a3bb38fbSZbigniew Kurzynski     {
415f2646271SRavi Teja         lg2::error("Certificate does not exist, ID:{ID}", "ID",
416f2646271SRavi Teja                    certificate->getCertId());
4172f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
4182f3563ccSZbigniew Lukwinski     }
4192f3563ccSZbigniew Lukwinski }
4202f3563ccSZbigniew Lukwinski 
replaceCertificate(Certificate * const certificate,const std::string & filePath)4212f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
4222f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
4232f3563ccSZbigniew Lukwinski {
4242f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
4252f3563ccSZbigniew Lukwinski     {
426698a5743SWilly Tu         certificate->install(filePath, false);
4272f3563ccSZbigniew Lukwinski         storageUpdate();
4282f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
4292f3563ccSZbigniew Lukwinski     }
4302f3563ccSZbigniew Lukwinski     else
4312f3563ccSZbigniew Lukwinski     {
432cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
433a3bb38fbSZbigniew Kurzynski     }
434a3bb38fbSZbigniew Kurzynski }
435a3bb38fbSZbigniew 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)436f4682712SMarri Devender Rao std::string Manager::generateCSR(
437f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
438f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
439f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
440f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
441f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
442f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
443f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
444f4682712SMarri Devender Rao {
445f4682712SMarri Devender Rao     // We support only one CSR.
446f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
447f4682712SMarri Devender Rao     auto pid = fork();
448f4682712SMarri Devender Rao     if (pid == -1)
449f4682712SMarri Devender Rao     {
450f2646271SRavi Teja         lg2::error("Error occurred during forking process");
451f4682712SMarri Devender Rao         report<InternalFailure>();
452f4682712SMarri Devender Rao     }
453f4682712SMarri Devender Rao     else if (pid == 0)
454f4682712SMarri Devender Rao     {
455f4682712SMarri Devender Rao         try
456f4682712SMarri Devender Rao         {
457a2f68d8bSPatrick Williams             generateCSRHelper(
458a2f68d8bSPatrick Williams                 alternativeNames, challengePassword, city, commonName,
459a2f68d8bSPatrick Williams                 contactPerson, country, email, givenName, initials,
460a2f68d8bSPatrick Williams                 keyBitLength, keyCurveId, keyPairAlgorithm, keyUsage,
461a2f68d8bSPatrick Williams                 organization, organizationalUnit, state, surname,
462f4682712SMarri Devender Rao                 unstructuredName);
463f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
464f4682712SMarri Devender Rao         }
465f4682712SMarri Devender Rao         catch (const InternalFailure& e)
466f4682712SMarri Devender Rao         {
467f4682712SMarri Devender Rao             // commit the error reported in child process and exit
468f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
469f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
470f4682712SMarri Devender Rao             commit<InternalFailure>();
471f4682712SMarri Devender Rao         }
472d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
473d2393f23SRamesh Iyyar         {
474d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
475d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
476d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
477d2393f23SRamesh Iyyar             commit<InvalidArgument>();
478d2393f23SRamesh Iyyar         }
479f4682712SMarri Devender Rao     }
480f4682712SMarri Devender Rao     else
481f4682712SMarri Devender Rao     {
482f4682712SMarri Devender Rao         using namespace sdeventplus::source;
483a2f68d8bSPatrick Williams         Child::Callback callback =
484a2f68d8bSPatrick Williams             [this](Child& eventSource, const siginfo_t* si) {
485f4682712SMarri Devender Rao                 eventSource.set_enabled(Enabled::On);
486f4682712SMarri Devender Rao                 if (si->si_status != 0)
487f4682712SMarri Devender Rao                 {
488e3d47cd4SNan Zhou                     this->createCSRObject(Status::failure);
489f4682712SMarri Devender Rao                 }
490f4682712SMarri Devender Rao                 else
491f4682712SMarri Devender Rao                 {
492e3d47cd4SNan Zhou                     this->createCSRObject(Status::success);
493f4682712SMarri Devender Rao                 }
494f4682712SMarri Devender Rao             };
495f4682712SMarri Devender Rao         try
496f4682712SMarri Devender Rao         {
497f4682712SMarri Devender Rao             sigset_t ss;
498f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
499f4682712SMarri Devender Rao             {
500f2646271SRavi Teja                 lg2::error("Unable to initialize signal set");
501f4682712SMarri Devender Rao                 elog<InternalFailure>();
502f4682712SMarri Devender Rao             }
503f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
504f4682712SMarri Devender Rao             {
505f2646271SRavi Teja                 lg2::error("Unable to add signal to signal set");
506f4682712SMarri Devender Rao                 elog<InternalFailure>();
507f4682712SMarri Devender Rao             }
508f4682712SMarri Devender Rao 
509f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
510cfb5802aSNan Zhou             if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
511f4682712SMarri Devender Rao             {
512f2646271SRavi Teja                 lg2::error("Unable to block signal");
513f4682712SMarri Devender Rao                 elog<InternalFailure>();
514f4682712SMarri Devender Rao             }
515f4682712SMarri Devender Rao             if (childPtr)
516f4682712SMarri Devender Rao             {
517f4682712SMarri Devender Rao                 childPtr.reset();
518f4682712SMarri Devender Rao             }
519f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
520f4682712SMarri Devender Rao                                                std::move(callback));
521f4682712SMarri Devender Rao         }
522f4682712SMarri Devender Rao         catch (const InternalFailure& e)
523f4682712SMarri Devender Rao         {
524f4682712SMarri Devender Rao             commit<InternalFailure>();
525f4682712SMarri Devender Rao         }
526f4682712SMarri Devender Rao     }
527f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
528f4682712SMarri Devender Rao     return csrObjectPath;
529f4682712SMarri Devender Rao }
530f4682712SMarri Devender Rao 
getCertificates()531db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
532ffad1ef1SMarri Devender Rao {
533db029c95SKowalski, Kamil     return installedCerts;
534ffad1ef1SMarri Devender Rao }
535ffad1ef1SMarri 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)536f4682712SMarri Devender Rao void Manager::generateCSRHelper(
537f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
538f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
539f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
540f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
541f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
542f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
543f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
544f4682712SMarri Devender Rao {
545f4682712SMarri Devender Rao     int ret = 0;
546f4682712SMarri Devender Rao 
547cf06ccdcSNan Zhou     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
548f4682712SMarri Devender Rao 
549f4682712SMarri Devender Rao     // set subject of x509 req
550f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
551f4682712SMarri Devender Rao 
552f4682712SMarri Devender Rao     if (!alternativeNames.empty())
553f4682712SMarri Devender Rao     {
554f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
555f4682712SMarri Devender Rao         {
556f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
557f4682712SMarri Devender Rao         }
558f4682712SMarri Devender Rao     }
559f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
560f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
561f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
562f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
563f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
564f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
565f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
566f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
567f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
568f4682712SMarri Devender Rao     if (!keyUsage.empty())
569f4682712SMarri Devender Rao     {
570f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
571f4682712SMarri Devender Rao         {
5727641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
5737641105dSMarri Devender Rao             {
5747641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
5757641105dSMarri Devender Rao             }
5767641105dSMarri Devender Rao             else
5777641105dSMarri Devender Rao             {
578f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
579f4682712SMarri Devender Rao             }
580f4682712SMarri Devender Rao         }
5817641105dSMarri Devender Rao     }
582f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
583dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
584f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
585f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
586f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
587f4682712SMarri Devender Rao 
588cf06ccdcSNan Zhou     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
5898a09b52aSRamesh Iyyar 
590f2646271SRavi Teja     lg2::info("Given Key pair algorithm, KEYPAIRALGORITHM:{KEYPAIRALGORITHM}",
591f2646271SRavi Teja               "KEYPAIRALGORITHM", keyPairAlgorithm);
5928a09b52aSRamesh Iyyar 
5938a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
5948a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
595c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
5968a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
597c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
5988a09b52aSRamesh Iyyar     else
5998a09b52aSRamesh Iyyar     {
600f2646271SRavi Teja         lg2::error("Given Key pair algorithm is not supported. Supporting "
6018a09b52aSRamesh Iyyar                    "RSA and EC only");
6028a09b52aSRamesh Iyyar         elog<InvalidArgument>(
6038a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
6048a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
6058a09b52aSRamesh Iyyar     }
6068a09b52aSRamesh Iyyar 
6078a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
6088a09b52aSRamesh Iyyar     if (ret == 0)
6098a09b52aSRamesh Iyyar     {
610f2646271SRavi Teja         lg2::error("Error occurred while setting Public key");
6118dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
6128a09b52aSRamesh Iyyar         elog<InternalFailure>();
6138a09b52aSRamesh Iyyar     }
6148a09b52aSRamesh Iyyar 
6158a09b52aSRamesh Iyyar     // Write private key to file
616718eef37SNan Zhou     writePrivateKey(pKey, defaultPrivateKeyFileName);
617f4682712SMarri Devender Rao 
618f4682712SMarri Devender Rao     // set sign key of x509 req
619f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
6208a09b52aSRamesh Iyyar     if (ret == 0)
621f4682712SMarri Devender Rao     {
622f2646271SRavi Teja         lg2::error("Error occurred while signing key of x509");
6238dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
624f4682712SMarri Devender Rao         elog<InternalFailure>();
625f4682712SMarri Devender Rao     }
6268a09b52aSRamesh Iyyar 
627f2646271SRavi Teja     lg2::info("Writing CSR to file");
628718eef37SNan Zhou     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
629c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
630f4682712SMarri Devender Rao }
631f4682712SMarri Devender Rao 
isExtendedKeyUsage(const std::string & usage)6327641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
6337641105dSMarri Devender Rao {
6347641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
6357641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
6367641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
637d96b81caSPatrick Williams     auto it = std::find_if(
638d96b81caSPatrick Williams         usageList.begin(), usageList.end(),
639d96b81caSPatrick Williams         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
6407641105dSMarri Devender Rao     return it != usageList.end();
6417641105dSMarri Devender Rao }
generateRSAKeyPair(const int64_t keyBitLength)642cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
643f4682712SMarri Devender Rao {
6448a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
645f4682712SMarri Devender Rao     // set keybit length to default value if not set
6468a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
647f4682712SMarri Devender Rao     {
648f2646271SRavi Teja         lg2::info("KeyBitLength is not given.Hence, using default KeyBitLength:"
649f2646271SRavi Teja                   "{DEFAULTKEYBITLENGTH}",
650f2646271SRavi Teja                   "DEFAULTKEYBITLENGTH", defaultKeyBitLength);
651cf06ccdcSNan Zhou         keyBitLen = defaultKeyBitLength;
652f4682712SMarri Devender Rao     }
65326fb83efSPatrick Williams 
65426fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
65526fb83efSPatrick Williams 
65626fb83efSPatrick Williams     // generate rsa key
657cf06ccdcSNan Zhou     BignumPtr bne(BN_new(), ::BN_free);
65826fb83efSPatrick Williams     auto ret = BN_set_word(bne.get(), RSA_F4);
65926fb83efSPatrick Williams     if (ret == 0)
66026fb83efSPatrick Williams     {
661f2646271SRavi Teja         lg2::error("Error occurred during BN_set_word call");
6628dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
66326fb83efSPatrick Williams         elog<InternalFailure>();
66426fb83efSPatrick Williams     }
665762da74eSNan Zhou     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
666762da74eSNan Zhou     RSAPtr rsa(RSA_new(), ::RSA_free);
667762da74eSNan Zhou     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
668f4682712SMarri Devender Rao     if (ret != 1)
669f4682712SMarri Devender Rao     {
670f2646271SRavi Teja         lg2::error(
671f2646271SRavi Teja             "Error occurred during RSA_generate_key_ex call: {KEYBITLENGTH}",
672f2646271SRavi Teja             "KEYBITLENGTH", keyBitLen);
6738dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
674f4682712SMarri Devender Rao         elog<InternalFailure>();
675f4682712SMarri Devender Rao     }
676f4682712SMarri Devender Rao 
677f4682712SMarri Devender Rao     // set public key of x509 req
678cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
679762da74eSNan Zhou     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
680f4682712SMarri Devender Rao     if (ret == 0)
681f4682712SMarri Devender Rao     {
682f2646271SRavi Teja         lg2::error("Error occurred during assign rsa key into EVP");
6838dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
684f4682712SMarri Devender Rao         elog<InternalFailure>();
685f4682712SMarri Devender Rao     }
686762da74eSNan Zhou     // Now |rsa| is managed by |pKey|
687762da74eSNan Zhou     rsa.release();
6888a09b52aSRamesh Iyyar     return pKey;
68926fb83efSPatrick Williams 
69026fb83efSPatrick Williams #else
69126fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
69226fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
69326fb83efSPatrick Williams     if (!ctx)
69426fb83efSPatrick Williams     {
695f2646271SRavi Teja         lg2::error("Error occurred creating EVP_PKEY_CTX from algorithm");
6968dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
69726fb83efSPatrick Williams         elog<InternalFailure>();
69826fb83efSPatrick Williams     }
69926fb83efSPatrick Williams 
70026fb83efSPatrick Williams     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
7011c1497a5SJayanth Othayoth         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(),
7021c1497a5SJayanth Othayoth                                           static_cast<int>(keyBitLen)) <= 0))
70326fb83efSPatrick Williams 
70426fb83efSPatrick Williams     {
705f2646271SRavi Teja         lg2::error("Error occurred initializing keygen context");
7068dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
70726fb83efSPatrick Williams         elog<InternalFailure>();
70826fb83efSPatrick Williams     }
70926fb83efSPatrick Williams 
71026fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
71126fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
71226fb83efSPatrick Williams     {
713f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
7148dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
71526fb83efSPatrick Williams         elog<InternalFailure>();
71626fb83efSPatrick Williams     }
71726fb83efSPatrick Williams 
71826fb83efSPatrick Williams     return {pKey, &::EVP_PKEY_free};
71926fb83efSPatrick Williams #endif
7208a09b52aSRamesh Iyyar }
7218a09b52aSRamesh Iyyar 
generateECKeyPair(const std::string & curveId)722cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
7238a09b52aSRamesh Iyyar {
7248a09b52aSRamesh Iyyar     std::string curId(curveId);
7258a09b52aSRamesh Iyyar 
7268a09b52aSRamesh Iyyar     if (curId.empty())
7278a09b52aSRamesh Iyyar     {
728f2646271SRavi Teja         lg2::info("KeyCurveId is not given. Hence using default curve id,"
729f2646271SRavi Teja                   "DEFAULTKEYCURVEID:{DEFAULTKEYCURVEID}",
730f2646271SRavi Teja                   "DEFAULTKEYCURVEID", defaultKeyCurveID);
731cf06ccdcSNan Zhou         curId = defaultKeyCurveID;
7328a09b52aSRamesh Iyyar     }
7338a09b52aSRamesh Iyyar 
7348a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
7358a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
7368a09b52aSRamesh Iyyar     {
737f2646271SRavi Teja         lg2::error(
738f2646271SRavi Teja             "Error occurred during convert the curve id string format into NID,"
739f2646271SRavi Teja             "KEYCURVEID:{KEYCURVEID}",
740f2646271SRavi Teja             "KEYCURVEID", curId);
7418a09b52aSRamesh Iyyar         elog<InternalFailure>();
7428a09b52aSRamesh Iyyar     }
7438a09b52aSRamesh Iyyar 
74426fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
74526fb83efSPatrick Williams 
7468a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
7478a09b52aSRamesh Iyyar 
748cfb5802aSNan Zhou     if (ecKey == nullptr)
7498a09b52aSRamesh Iyyar     {
750f2646271SRavi Teja         lg2::error(
751f2646271SRavi Teja             "Error occurred during create the EC_Key object from NID, ECGROUP:{ECGROUP}",
752f2646271SRavi Teja             "ECGROUP", ecGrp);
7538dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
7548a09b52aSRamesh Iyyar         elog<InternalFailure>();
7558a09b52aSRamesh Iyyar     }
7568a09b52aSRamesh Iyyar 
7578a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
7588a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
7598a09b52aSRamesh Iyyar     // flag on the key.
7608a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
7618a09b52aSRamesh Iyyar 
7628a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
7638a09b52aSRamesh Iyyar 
7648a09b52aSRamesh Iyyar     if (ret == 0)
7658a09b52aSRamesh Iyyar     {
7668a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
767f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
7688dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
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);
777f2646271SRavi Teja         lg2::error("Error occurred during assign EC Key into EVP");
7788dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
7798a09b52aSRamesh Iyyar         elog<InternalFailure>();
7808a09b52aSRamesh Iyyar     }
7818a09b52aSRamesh Iyyar 
7828a09b52aSRamesh Iyyar     return pKey;
78326fb83efSPatrick Williams 
78426fb83efSPatrick Williams #else
785e3d47cd4SNan Zhou     auto holderOfKey = [](EVP_PKEY* key) {
78626fb83efSPatrick Williams         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
78726fb83efSPatrick Williams             key, &::EVP_PKEY_free};
78826fb83efSPatrick Williams     };
78926fb83efSPatrick Williams 
79026fb83efSPatrick Williams     // Create context to set up curve parameters.
79126fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
79226fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
79326fb83efSPatrick Williams     if (!ctx)
79426fb83efSPatrick Williams     {
795f2646271SRavi Teja         lg2::error("Error occurred creating EVP_PKEY_CTX for params");
7968dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
79726fb83efSPatrick Williams         elog<InternalFailure>();
79826fb83efSPatrick Williams     }
79926fb83efSPatrick Williams 
80026fb83efSPatrick Williams     // Set up curve parameters.
80126fb83efSPatrick Williams     EVP_PKEY* params = nullptr;
80226fb83efSPatrick Williams 
80326fb83efSPatrick Williams     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
80426fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
80526fb83efSPatrick Williams          0) ||
80626fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
80726fb83efSPatrick Williams         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
80826fb83efSPatrick Williams     {
809f2646271SRavi Teja         lg2::error("Error occurred setting curve parameters");
8108dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
81126fb83efSPatrick Williams         elog<InternalFailure>();
81226fb83efSPatrick Williams     }
81326fb83efSPatrick Williams 
81426fb83efSPatrick Williams     // Move parameters to RAII holder.
815e3d47cd4SNan Zhou     auto pparms = holderOfKey(params);
81626fb83efSPatrick Williams 
81726fb83efSPatrick Williams     // Create new context for key.
81826fb83efSPatrick Williams     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
81926fb83efSPatrick Williams 
82026fb83efSPatrick Williams     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
82126fb83efSPatrick Williams     {
822f2646271SRavi Teja         lg2::error("Error occurred initializing keygen context");
8238dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
82426fb83efSPatrick Williams         elog<InternalFailure>();
82526fb83efSPatrick Williams     }
82626fb83efSPatrick Williams 
82726fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
82826fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
82926fb83efSPatrick Williams     {
830f2646271SRavi Teja         lg2::error("Error occurred during generate EC key");
8318dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
83226fb83efSPatrick Williams         elog<InternalFailure>();
83326fb83efSPatrick Williams     }
83426fb83efSPatrick Williams 
835e3d47cd4SNan Zhou     return holderOfKey(pKey);
83626fb83efSPatrick Williams #endif
8378a09b52aSRamesh Iyyar }
8388a09b52aSRamesh Iyyar 
writePrivateKey(const EVPPkeyPtr & pKey,const std::string & privKeyFileName)839cf06ccdcSNan Zhou void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
840c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
8418a09b52aSRamesh Iyyar {
842f2646271SRavi Teja     lg2::info("Writing private key to file");
843f4682712SMarri Devender Rao     // write private key to file
844c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
845f4682712SMarri Devender Rao 
846f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
847cfb5802aSNan Zhou     if (fp == nullptr)
848f4682712SMarri Devender Rao     {
849f2646271SRavi Teja         lg2::error("Error occurred creating private key file");
850f4682712SMarri Devender Rao         elog<InternalFailure>();
851f4682712SMarri Devender Rao     }
852*5b3ee057SJayanth Othayoth     int ret = PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, nullptr,
853*5b3ee057SJayanth Othayoth                                    nullptr);
854f4682712SMarri Devender Rao     std::fclose(fp);
855f4682712SMarri Devender Rao     if (ret == 0)
856f4682712SMarri Devender Rao     {
857f2646271SRavi Teja         lg2::error("Error occurred while writing private key to file");
858f4682712SMarri Devender Rao         elog<InternalFailure>();
859f4682712SMarri Devender Rao     }
860f4682712SMarri Devender Rao }
861f4682712SMarri Devender Rao 
addEntry(X509_NAME * x509Name,const char * field,const std::string & bytes)862f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
863f4682712SMarri Devender Rao                        const std::string& bytes)
864f4682712SMarri Devender Rao {
865f4682712SMarri Devender Rao     if (bytes.empty())
866f4682712SMarri Devender Rao     {
867f4682712SMarri Devender Rao         return;
868f4682712SMarri Devender Rao     }
869f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
870f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
871f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
872f4682712SMarri Devender Rao     if (ret != 1)
873f4682712SMarri Devender Rao     {
874f2646271SRavi Teja         lg2::error("Unable to set entry, FIELD:{FIELD}, VALUE:{VALUE}", "FIELD",
875f2646271SRavi Teja                    field, "VALUE", bytes);
8768dbcc72dSAndrew Geissler         ERR_print_errors_fp(stderr);
877f4682712SMarri Devender Rao         elog<InternalFailure>();
878f4682712SMarri Devender Rao     }
879f4682712SMarri Devender Rao }
880f4682712SMarri Devender Rao 
createCSRObject(const Status & status)881f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
882f4682712SMarri Devender Rao {
883f4682712SMarri Devender Rao     if (csrPtr)
884f4682712SMarri Devender Rao     {
885f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
886f4682712SMarri Devender Rao     }
887f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
888f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
889f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
890f4682712SMarri Devender Rao }
891f4682712SMarri Devender Rao 
writeCSR(const std::string & filePath,const X509ReqPtr & x509Req)892cf06ccdcSNan Zhou void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
893f4682712SMarri Devender Rao {
894f4682712SMarri Devender Rao     if (fs::exists(filePath))
895f4682712SMarri Devender Rao     {
896f2646271SRavi Teja         lg2::info("Removing the existing file, FILENAME:{FILENAME}", "FILENAME",
897f2646271SRavi Teja                   filePath);
898f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
899f4682712SMarri Devender Rao         {
900f2646271SRavi Teja             lg2::error("Unable to remove the file, FILENAME:{FILENAME}",
901f2646271SRavi Teja                        "FILENAME", filePath);
902f4682712SMarri Devender Rao             elog<InternalFailure>();
903f4682712SMarri Devender Rao         }
904f4682712SMarri Devender Rao     }
905f4682712SMarri Devender Rao 
906cb1ee9dcSJayanth Othayoth     FILE* fp = std::fopen(filePath.c_str(), "w");
907f4682712SMarri Devender Rao 
908cb1ee9dcSJayanth Othayoth     if (fp == nullptr)
909f4682712SMarri Devender Rao     {
910f2646271SRavi Teja         lg2::error(
911f2646271SRavi Teja             "Error opening the file to write the CSR, FILENAME:{FILENAME}",
912f2646271SRavi Teja             "FILENAME", filePath);
913f4682712SMarri Devender Rao         elog<InternalFailure>();
914f4682712SMarri Devender Rao     }
915f4682712SMarri Devender Rao 
916f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
917f4682712SMarri Devender Rao     if (!rc)
918f4682712SMarri Devender Rao     {
919f2646271SRavi Teja         lg2::error("PEM write routine failed, FILENAME:{FILENAME}", "FILENAME",
920f2646271SRavi Teja                    filePath);
921f4682712SMarri Devender Rao         std::fclose(fp);
922f4682712SMarri Devender Rao         elog<InternalFailure>();
923f4682712SMarri Devender Rao     }
924f4682712SMarri Devender Rao     std::fclose(fp);
925f4682712SMarri Devender Rao }
926f4682712SMarri Devender Rao 
createCertificates()927db029c95SKowalski, Kamil void Manager::createCertificates()
928db029c95SKowalski, Kamil {
929db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
930db029c95SKowalski, Kamil 
931e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
932db029c95SKowalski, Kamil     {
933fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
934db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
935db029c95SKowalski, Kamil         {
936f2646271SRavi Teja             lg2::error("Certificate installation path exists and it is "
937db029c95SKowalski, Kamil                        "not a directory");
938db029c95SKowalski, Kamil             elog<InternalFailure>();
9396ec13c8fSNan Zhou         }
9406ec13c8fSNan Zhou 
9416ec13c8fSNan Zhou         // If the authorities list exists, recover from it and return
942a2f68d8bSPatrick Williams         if (fs::path authoritiesListFilePath =
943a2f68d8bSPatrick Williams                 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
9446ec13c8fSNan Zhou             fs::exists(authoritiesListFilePath))
9456ec13c8fSNan Zhou         {
9466ec13c8fSNan Zhou             // remove all other files and directories
9476ec13c8fSNan Zhou             for (auto& path : fs::directory_iterator(certInstallPath))
9486ec13c8fSNan Zhou             {
9496ec13c8fSNan Zhou                 if (path.path() != authoritiesListFilePath)
9506ec13c8fSNan Zhou                 {
9516ec13c8fSNan Zhou                     fs::remove_all(path);
9526ec13c8fSNan Zhou                 }
9536ec13c8fSNan Zhou             }
9546ec13c8fSNan Zhou             installAll(authoritiesListFilePath);
955db029c95SKowalski, Kamil             return;
956db029c95SKowalski, Kamil         }
957db029c95SKowalski, Kamil 
958db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
959ffad1ef1SMarri Devender Rao         {
960ffad1ef1SMarri Devender Rao             try
961ffad1ef1SMarri Devender Rao             {
9622f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
9632f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
9642f3563ccSZbigniew Lukwinski                 // would add value.
9652f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
9662f3563ccSZbigniew Lukwinski                 {
967db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
968db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
969cf06ccdcSNan Zhou                         certType, certInstallPath, path.path(),
970698a5743SWilly Tu                         certWatchPtr.get(), *this, /*restore=*/true));
9712f3563ccSZbigniew Lukwinski                 }
972ffad1ef1SMarri Devender Rao             }
973ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
974ffad1ef1SMarri Devender Rao             {
975ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
976ffad1ef1SMarri Devender Rao             }
977ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
978ffad1ef1SMarri Devender Rao             {
979cf06ccdcSNan Zhou                 report<InvalidCertificate>(InvalidCertificateReason(
980cf06ccdcSNan Zhou                     "Existing certificate file is corrupted"));
981ffad1ef1SMarri Devender Rao             }
982ffad1ef1SMarri Devender Rao         }
983db029c95SKowalski, Kamil     }
984db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
985db029c95SKowalski, Kamil     {
986db029c95SKowalski, Kamil         try
987db029c95SKowalski, Kamil         {
988db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
9892f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
990698a5743SWilly Tu                 certInstallPath, certWatchPtr.get(), *this, /*restore=*/false));
991db029c95SKowalski, Kamil         }
992db029c95SKowalski, Kamil         catch (const InternalFailure& e)
993db029c95SKowalski, Kamil         {
994db029c95SKowalski, Kamil             report<InternalFailure>();
995db029c95SKowalski, Kamil         }
996db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
997db029c95SKowalski, Kamil         {
998cf06ccdcSNan Zhou             report<InvalidCertificate>(InvalidCertificateReason(
999cf06ccdcSNan Zhou                 "Existing certificate file is corrupted"));
1000db029c95SKowalski, Kamil         }
1001db029c95SKowalski, Kamil     }
1002db029c95SKowalski, Kamil }
1003c6e58c7eSRamesh Iyyar 
createRSAPrivateKeyFile()1004c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
1005c6e58c7eSRamesh Iyyar {
1006a2f68d8bSPatrick Williams     fs::path rsaPrivateKeyFileName =
1007a2f68d8bSPatrick Williams         certParentInstallPath / defaultRSAPrivateKeyFileName;
1008c6e58c7eSRamesh Iyyar 
1009c6e58c7eSRamesh Iyyar     try
1010c6e58c7eSRamesh Iyyar     {
1011c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
1012c6e58c7eSRamesh Iyyar         {
1013cf06ccdcSNan Zhou             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
1014718eef37SNan Zhou                             defaultRSAPrivateKeyFileName);
1015c6e58c7eSRamesh Iyyar         }
1016c6e58c7eSRamesh Iyyar     }
1017c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
1018c6e58c7eSRamesh Iyyar     {
1019c6e58c7eSRamesh Iyyar         report<InternalFailure>();
1020c6e58c7eSRamesh Iyyar     }
1021c6e58c7eSRamesh Iyyar }
1022c6e58c7eSRamesh Iyyar 
getRSAKeyPair(const int64_t keyBitLength)1023cf06ccdcSNan Zhou EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
1024c6e58c7eSRamesh Iyyar {
1025cf06ccdcSNan Zhou     if (keyBitLength != supportedKeyBitLength)
1026c6e58c7eSRamesh Iyyar     {
1027f2646271SRavi Teja         lg2::error(
1028f2646271SRavi Teja             "Given Key bit length is not supported, GIVENKEYBITLENGTH:"
1029f2646271SRavi Teja             "{GIVENKEYBITLENGTH}, SUPPORTEDKEYBITLENGTH:{SUPPORTEDKEYBITLENGTH}",
1030f2646271SRavi Teja             "GIVENKEYBITLENGTH", keyBitLength, "SUPPORTEDKEYBITLENGTH",
1031f2646271SRavi Teja             supportedKeyBitLength);
1032c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
1033c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1034c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1035c6e58c7eSRamesh Iyyar     }
1036a2f68d8bSPatrick Williams     fs::path rsaPrivateKeyFileName =
1037a2f68d8bSPatrick Williams         certParentInstallPath / defaultRSAPrivateKeyFileName;
1038c6e58c7eSRamesh Iyyar 
1039c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1040c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
1041c6e58c7eSRamesh Iyyar     {
1042f2646271SRavi Teja         lg2::error(
1043f2646271SRavi Teja             "Unable to open RSA private key file to read, RSAKEYFILE:{RSAKEYFILE},"
1044f2646271SRavi Teja             "ERRORREASON:{ERRORREASON}",
1045f2646271SRavi Teja             "RSAKEYFILE", rsaPrivateKeyFileName, "ERRORREASON",
1046f2646271SRavi Teja             strerror(errno));
1047c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1048c6e58c7eSRamesh Iyyar     }
1049c6e58c7eSRamesh Iyyar 
1050cf06ccdcSNan Zhou     EVPPkeyPtr privateKey(
1051c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1052c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
1053c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
1054c6e58c7eSRamesh Iyyar 
1055c6e58c7eSRamesh Iyyar     if (!privateKey)
1056c6e58c7eSRamesh Iyyar     {
1057f2646271SRavi Teja         lg2::error("Error occurred during PEM_read_PrivateKey call");
1058c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
1059c6e58c7eSRamesh Iyyar     }
1060c6e58c7eSRamesh Iyyar     return privateKey;
1061c6e58c7eSRamesh Iyyar }
10622f3563ccSZbigniew Lukwinski 
storageUpdate()10632f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
10642f3563ccSZbigniew Lukwinski {
1065e3d47cd4SNan Zhou     if (certType == CertificateType::authority)
10662f3563ccSZbigniew Lukwinski     {
10672f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
10682f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
10692f3563ccSZbigniew Lukwinski         {
10702f3563ccSZbigniew Lukwinski             try
10712f3563ccSZbigniew Lukwinski             {
10722f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
10732f3563ccSZbigniew Lukwinski                 {
10742f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
10752f3563ccSZbigniew Lukwinski                 }
10762f3563ccSZbigniew Lukwinski             }
10772f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
10782f3563ccSZbigniew Lukwinski             {
1079f2646271SRavi Teja                 lg2::error(
1080f2646271SRavi Teja                     "Failed to remove symlink for certificate, ERR:{ERR} SYMLINK:{SYMLINK}",
1081f2646271SRavi Teja                     "ERR", e, "SYMLINK", certPath.path().string());
10822f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
10832f3563ccSZbigniew Lukwinski             }
10842f3563ccSZbigniew Lukwinski         }
10852f3563ccSZbigniew Lukwinski     }
10862f3563ccSZbigniew Lukwinski 
10872f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
10882f3563ccSZbigniew Lukwinski     {
10892f3563ccSZbigniew Lukwinski         cert->storageUpdate();
10902f3563ccSZbigniew Lukwinski     }
10912f3563ccSZbigniew Lukwinski }
10922f3563ccSZbigniew Lukwinski 
reloadOrReset(const std::string & unit)1093cf06ccdcSNan Zhou void Manager::reloadOrReset(const std::string& unit)
10942f3563ccSZbigniew Lukwinski {
10952f3563ccSZbigniew Lukwinski     if (!unit.empty())
10962f3563ccSZbigniew Lukwinski     {
10972f3563ccSZbigniew Lukwinski         try
10982f3563ccSZbigniew Lukwinski         {
1099cf06ccdcSNan Zhou             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1100cf06ccdcSNan Zhou             constexpr auto defaultSystemdObjectPath =
1101cf06ccdcSNan Zhou                 "/org/freedesktop/systemd1";
1102cf06ccdcSNan Zhou             constexpr auto defaultSystemdInterface =
11032f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
1104cf06ccdcSNan Zhou             auto method = bus.new_method_call(
1105cf06ccdcSNan Zhou                 defaultSystemdService, defaultSystemdObjectPath,
1106cf06ccdcSNan Zhou                 defaultSystemdInterface, "ReloadOrRestartUnit");
11072f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
11082f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
11092f3563ccSZbigniew Lukwinski         }
1110b3dbfb37SPatrick Williams         catch (const sdbusplus::exception_t& e)
11112f3563ccSZbigniew Lukwinski         {
1112f2646271SRavi Teja             lg2::error(
1113f2646271SRavi Teja                 "Failed to reload or restart service, ERR:{ERR}, UNIT:{UNIT}",
1114f2646271SRavi Teja                 "ERR", e, "UNIT", unit);
11152f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
11162f3563ccSZbigniew Lukwinski         }
11172f3563ccSZbigniew Lukwinski     }
11182f3563ccSZbigniew Lukwinski }
11192f3563ccSZbigniew Lukwinski 
isCertificateUnique(const std::string & filePath,const Certificate * const certToDrop)11202f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
11212f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
11222f3563ccSZbigniew Lukwinski {
11232f3563ccSZbigniew Lukwinski     if (std::any_of(
11242f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
1125223e4604SPatrick Williams             [&filePath, certToDrop](const std::unique_ptr<Certificate>& cert) {
11262f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
11272f3563ccSZbigniew Lukwinski             }))
11282f3563ccSZbigniew Lukwinski     {
11292f3563ccSZbigniew Lukwinski         return false;
11302f3563ccSZbigniew Lukwinski     }
11312f3563ccSZbigniew Lukwinski     else
11322f3563ccSZbigniew Lukwinski     {
11332f3563ccSZbigniew Lukwinski         return true;
11342f3563ccSZbigniew Lukwinski     }
11352f3563ccSZbigniew Lukwinski }
11362f3563ccSZbigniew Lukwinski 
1137e1289adfSNan Zhou } // namespace phosphor::certs
1138