1*014be0bfSNan Zhou #include "config.h"
2*014be0bfSNan Zhou 
3cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
4cfbc8dc8SJayanth Othayoth 
5*014be0bfSNan Zhou #include <openssl/asn1.h>
6*014be0bfSNan Zhou #include <openssl/bn.h>
7*014be0bfSNan Zhou #include <openssl/ec.h>
826fb83efSPatrick Williams #include <openssl/evp.h>
9*014be0bfSNan Zhou #include <openssl/obj_mac.h>
10*014be0bfSNan Zhou #include <openssl/objects.h>
11*014be0bfSNan Zhou #include <openssl/opensslv.h>
12f4682712SMarri Devender Rao #include <openssl/pem.h>
13*014be0bfSNan Zhou #include <openssl/rsa.h>
14f4682712SMarri Devender Rao #include <unistd.h>
15f4682712SMarri Devender Rao 
16a3bb38fbSZbigniew Kurzynski #include <algorithm>
17*014be0bfSNan Zhou #include <array>
18*014be0bfSNan Zhou #include <cerrno>
19*014be0bfSNan Zhou #include <chrono>
20*014be0bfSNan Zhou #include <csignal>
21*014be0bfSNan Zhou #include <cstdio>
22*014be0bfSNan Zhou #include <cstdlib>
23*014be0bfSNan Zhou #include <cstring>
24*014be0bfSNan Zhou #include <exception>
256ceec40bSMarri Devender Rao #include <phosphor-logging/elog-errors.hpp>
26*014be0bfSNan Zhou #include <phosphor-logging/elog.hpp>
27*014be0bfSNan Zhou #include <phosphor-logging/log.hpp>
28*014be0bfSNan Zhou #include <sdbusplus/bus.hpp>
29*014be0bfSNan Zhou #include <sdbusplus/exception.hpp>
30*014be0bfSNan Zhou #include <sdbusplus/message.hpp>
31*014be0bfSNan Zhou #include <sdeventplus/source/base.hpp>
32*014be0bfSNan Zhou #include <sdeventplus/source/child.hpp>
33*014be0bfSNan Zhou #include <utility>
3413bf74e4SMarri Devender Rao #include <xyz/openbmc_project/Certs/error.hpp>
35cfbc8dc8SJayanth Othayoth #include <xyz/openbmc_project/Common/error.hpp>
362f3563ccSZbigniew Lukwinski 
37e1289adfSNan Zhou namespace phosphor::certs
38cfbc8dc8SJayanth Othayoth {
39cf06ccdcSNan Zhou namespace
40cf06ccdcSNan Zhou {
41cf06ccdcSNan Zhou namespace fs = std::filesystem;
42cf06ccdcSNan Zhou using ::phosphor::logging::commit;
43cf06ccdcSNan Zhou using ::phosphor::logging::elog;
44cf06ccdcSNan Zhou using ::phosphor::logging::entry;
45cf06ccdcSNan Zhou using ::phosphor::logging::level;
46cf06ccdcSNan Zhou using ::phosphor::logging::log;
47cf06ccdcSNan Zhou using ::phosphor::logging::report;
48cfbc8dc8SJayanth Othayoth 
49cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
50cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
51cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
52cf06ccdcSNan Zhou using NotAllowedReason =
53cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
54cf06ccdcSNan Zhou using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
55cf06ccdcSNan Zhou     Certs::InvalidCertificate::REASON;
56cf06ccdcSNan Zhou using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
57cf06ccdcSNan Zhou using Argument =
58cf06ccdcSNan Zhou     ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
59c6e58c7eSRamesh Iyyar 
60cf06ccdcSNan Zhou // RAII support for openSSL functions.
61cf06ccdcSNan Zhou using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
62cf06ccdcSNan Zhou using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
63cf06ccdcSNan Zhou using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
64cf06ccdcSNan Zhou 
65cf06ccdcSNan Zhou constexpr int supportedKeyBitLength = 2048;
66cf06ccdcSNan Zhou constexpr int defaultKeyBitLength = 2048;
67cf06ccdcSNan Zhou // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
68cf06ccdcSNan Zhou constexpr auto defaultKeyCurveID = "secp224r1";
69cf06ccdcSNan Zhou } // namespace
70f4682712SMarri Devender Rao 
71f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
72cf06ccdcSNan Zhou                  const char* path, CertificateType type,
73cf06ccdcSNan Zhou                  const std::string& unit, const std::string& installPath) :
74cf06ccdcSNan Zhou     internal::ManagerInterface(bus, path),
75f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
76c6e58c7eSRamesh Iyyar     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
77c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
78cfbc8dc8SJayanth Othayoth {
79db5c6fc8SMarri Devender Rao     try
80db5c6fc8SMarri Devender Rao     {
81fe590c4eSZbigniew Lukwinski         // Create certificate directory if not existing.
82bf3cf751SNan Zhou         // Set correct certificate directory permissions.
83fe590c4eSZbigniew Lukwinski         fs::path certDirectory;
84b57d75e2SMarri Devender Rao         try
85b57d75e2SMarri Devender Rao         {
86cf06ccdcSNan Zhou             if (certType == CertificateType::Authority)
87b57d75e2SMarri Devender Rao             {
88fe590c4eSZbigniew Lukwinski                 certDirectory = certInstallPath;
89b57d75e2SMarri Devender Rao             }
90fe590c4eSZbigniew Lukwinski             else
91fe590c4eSZbigniew Lukwinski             {
92fe590c4eSZbigniew Lukwinski                 certDirectory = certParentInstallPath;
93fe590c4eSZbigniew Lukwinski             }
94fe590c4eSZbigniew Lukwinski 
95fe590c4eSZbigniew Lukwinski             if (!fs::exists(certDirectory))
96fe590c4eSZbigniew Lukwinski             {
97fe590c4eSZbigniew Lukwinski                 fs::create_directories(certDirectory);
98fe590c4eSZbigniew Lukwinski             }
99fe590c4eSZbigniew Lukwinski 
100667286e4SMarri Devender Rao             auto permission = fs::perms::owner_read | fs::perms::owner_write |
101667286e4SMarri Devender Rao                               fs::perms::owner_exec;
102db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
103db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
1042f3563ccSZbigniew Lukwinski             storageUpdate();
105b57d75e2SMarri Devender Rao         }
10671957992SPatrick Williams         catch (const fs::filesystem_error& e)
107b57d75e2SMarri Devender Rao         {
108db5c6fc8SMarri Devender Rao             log<level::ERR>(
109db5c6fc8SMarri Devender Rao                 "Failed to create directory", entry("ERR=%s", e.what()),
110b57d75e2SMarri Devender Rao                 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
111b57d75e2SMarri Devender Rao             report<InternalFailure>();
112b57d75e2SMarri Devender Rao         }
113b57d75e2SMarri Devender Rao 
114c6e58c7eSRamesh Iyyar         // Generating RSA private key file if certificate type is server/client
115cf06ccdcSNan Zhou         if (certType != CertificateType::Authority)
116c6e58c7eSRamesh Iyyar         {
117c6e58c7eSRamesh Iyyar             createRSAPrivateKeyFile();
118c6e58c7eSRamesh Iyyar         }
119c6e58c7eSRamesh Iyyar 
120ffad1ef1SMarri Devender Rao         // restore any existing certificates
121db029c95SKowalski, Kamil         createCertificates();
122ffad1ef1SMarri Devender Rao 
123ffad1ef1SMarri Devender Rao         // watch is not required for authority certificates
124cf06ccdcSNan Zhou         if (certType != CertificateType::Authority)
125ffad1ef1SMarri Devender Rao         {
126ffad1ef1SMarri Devender Rao             // watch for certificate file create/replace
127ffad1ef1SMarri Devender Rao             certWatchPtr = std::make_unique<
128ffad1ef1SMarri Devender Rao                 Watch>(event, certInstallPath, [this]() {
129bf7c588cSMarri Devender Rao                 try
130bf7c588cSMarri Devender Rao                 {
131ffad1ef1SMarri Devender Rao                     // if certificate file existing update it
132db029c95SKowalski, Kamil                     if (!installedCerts.empty())
133ffad1ef1SMarri Devender Rao                     {
134db5c6fc8SMarri Devender Rao                         log<level::INFO>("Inotify callback to update "
135db5c6fc8SMarri Devender Rao                                          "certificate properties");
136db029c95SKowalski, Kamil                         installedCerts[0]->populateProperties();
137ffad1ef1SMarri Devender Rao                     }
138ffad1ef1SMarri Devender Rao                     else
139ffad1ef1SMarri Devender Rao                     {
140ffad1ef1SMarri Devender Rao                         log<level::INFO>(
141ffad1ef1SMarri Devender Rao                             "Inotify callback to create certificate object");
142db029c95SKowalski, Kamil                         createCertificates();
143ffad1ef1SMarri Devender Rao                     }
144bf7c588cSMarri Devender Rao                 }
145bf7c588cSMarri Devender Rao                 catch (const InternalFailure& e)
146bf7c588cSMarri Devender Rao                 {
147ffad1ef1SMarri Devender Rao                     commit<InternalFailure>();
148bf7c588cSMarri Devender Rao                 }
149bf7c588cSMarri Devender Rao                 catch (const InvalidCertificate& e)
150bf7c588cSMarri Devender Rao                 {
151ffad1ef1SMarri Devender Rao                     commit<InvalidCertificate>();
152bf7c588cSMarri Devender Rao                 }
153ffad1ef1SMarri Devender Rao             });
154bf7c588cSMarri Devender Rao         }
155db029c95SKowalski, Kamil         else
156db029c95SKowalski, Kamil         {
157db5c6fc8SMarri Devender Rao             try
158db5c6fc8SMarri Devender Rao             {
159db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
160db5c6fc8SMarri Devender Rao                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
161db029c95SKowalski, Kamil                 {
162db029c95SKowalski, Kamil                     log<level::NOTICE>(
163db029c95SKowalski, Kamil                         "Legacy certificate detected, will be installed from: ",
164db5c6fc8SMarri Devender Rao                         entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
165db5c6fc8SMarri Devender Rao                     install(singleCertPath);
166db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
167db029c95SKowalski, Kamil                     {
168db029c95SKowalski, Kamil                         log<level::ERR>(
169db029c95SKowalski, Kamil                             "Unable to remove old certificate from: ",
170db5c6fc8SMarri Devender Rao                             entry("SINGLE_CERTPATH=%s",
171db5c6fc8SMarri Devender Rao                                   singleCertPath.c_str()));
172db029c95SKowalski, Kamil                         elog<InternalFailure>();
173db029c95SKowalski, Kamil                     }
174db029c95SKowalski, Kamil                 }
175db029c95SKowalski, Kamil             }
176db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
177db5c6fc8SMarri Devender Rao             {
178db5c6fc8SMarri Devender Rao                 log<level::ERR>("Error in restoring legacy certificate",
179db5c6fc8SMarri Devender Rao                                 entry("ERROR_STR=%s", ex.what()));
180db5c6fc8SMarri Devender Rao             }
181db5c6fc8SMarri Devender Rao         }
182db5c6fc8SMarri Devender Rao     }
18371957992SPatrick Williams     catch (const std::exception& ex)
184db5c6fc8SMarri Devender Rao     {
185db5c6fc8SMarri Devender Rao         log<level::ERR>("Error in certificate manager constructor",
186db5c6fc8SMarri Devender Rao                         entry("ERROR_STR=%s", ex.what()));
187db5c6fc8SMarri Devender Rao     }
188dd74bd20SJayanth Othayoth }
189589159f2SJayanth Othayoth 
19006a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath)
191cfbc8dc8SJayanth Othayoth {
192cf06ccdcSNan Zhou     if (certType != CertificateType::Authority && !installedCerts.empty())
1931396511dSMarri Devender Rao     {
194cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
1951396511dSMarri Devender Rao     }
196cf06ccdcSNan Zhou     else if (certType == CertificateType::Authority &&
197718eef37SNan Zhou              installedCerts.size() >= maxNumAuthorityCertificates)
1983b07b77aSZbigniew Lukwinski     {
199cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
2003b07b77aSZbigniew Lukwinski     }
201ffad1ef1SMarri Devender Rao 
2022f3563ccSZbigniew Lukwinski     std::string certObjectPath;
2032f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath))
2042f3563ccSZbigniew Lukwinski     {
2052f3563ccSZbigniew Lukwinski         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
206db029c95SKowalski, Kamil         installedCerts.emplace_back(std::make_unique<Certificate>(
2072f3563ccSZbigniew Lukwinski             bus, certObjectPath, certType, certInstallPath, filePath,
208cf06ccdcSNan Zhou             certWatchPtr.get(), *this));
2092f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
2102f3563ccSZbigniew Lukwinski         certIdCounter++;
2112f3563ccSZbigniew Lukwinski     }
2122f3563ccSZbigniew Lukwinski     else
2132f3563ccSZbigniew Lukwinski     {
214cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
2152f3563ccSZbigniew Lukwinski     }
2162f3563ccSZbigniew Lukwinski 
21706a69d7bSZbigniew Kurzynski     return certObjectPath;
218589159f2SJayanth Othayoth }
219ae70b3daSDeepak Kodihalli 
220a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
221ae70b3daSDeepak Kodihalli {
2226ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
2236ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
2246ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
2256ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
2266ceec40bSMarri Devender Rao     // deletion of certificates
227db029c95SKowalski, Kamil     installedCerts.clear();
2282f3563ccSZbigniew Lukwinski     storageUpdate();
2292f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
230ae70b3daSDeepak Kodihalli }
231f4682712SMarri Devender Rao 
2322f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
233a3bb38fbSZbigniew Kurzynski {
234a3bb38fbSZbigniew Kurzynski     std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
235a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
2362f3563ccSZbigniew Lukwinski                      [certificate](std::unique_ptr<Certificate> const& cert) {
2372f3563ccSZbigniew Lukwinski                          return (cert.get() == certificate);
238a3bb38fbSZbigniew Kurzynski                      });
239a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
240a3bb38fbSZbigniew Kurzynski     {
241a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
2422f3563ccSZbigniew Lukwinski         storageUpdate();
2432f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
244a3bb38fbSZbigniew Kurzynski     }
245a3bb38fbSZbigniew Kurzynski     else
246a3bb38fbSZbigniew Kurzynski     {
247a3bb38fbSZbigniew Kurzynski         log<level::ERR>("Certificate does not exist",
2482f3563ccSZbigniew Lukwinski                         entry("ID=%s", certificate->getCertId().c_str()));
2492f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
2502f3563ccSZbigniew Lukwinski     }
2512f3563ccSZbigniew Lukwinski }
2522f3563ccSZbigniew Lukwinski 
2532f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
2542f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
2552f3563ccSZbigniew Lukwinski {
2562f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
2572f3563ccSZbigniew Lukwinski     {
2582f3563ccSZbigniew Lukwinski         certificate->install(filePath);
2592f3563ccSZbigniew Lukwinski         storageUpdate();
2602f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
2612f3563ccSZbigniew Lukwinski     }
2622f3563ccSZbigniew Lukwinski     else
2632f3563ccSZbigniew Lukwinski     {
264cf06ccdcSNan Zhou         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
265a3bb38fbSZbigniew Kurzynski     }
266a3bb38fbSZbigniew Kurzynski }
267a3bb38fbSZbigniew Kurzynski 
268f4682712SMarri Devender Rao std::string Manager::generateCSR(
269f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
270f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
271f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
272f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
273f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
274f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
275f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
276f4682712SMarri Devender Rao {
277f4682712SMarri Devender Rao     // We support only one CSR.
278f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
279f4682712SMarri Devender Rao     auto pid = fork();
280f4682712SMarri Devender Rao     if (pid == -1)
281f4682712SMarri Devender Rao     {
282f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
283f4682712SMarri Devender Rao         report<InternalFailure>();
284f4682712SMarri Devender Rao     }
285f4682712SMarri Devender Rao     else if (pid == 0)
286f4682712SMarri Devender Rao     {
287f4682712SMarri Devender Rao         try
288f4682712SMarri Devender Rao         {
289f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
290f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
291f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
292f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
293f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
294f4682712SMarri Devender Rao                               unstructuredName);
295f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
296f4682712SMarri Devender Rao         }
297f4682712SMarri Devender Rao         catch (const InternalFailure& e)
298f4682712SMarri Devender Rao         {
299f4682712SMarri Devender Rao             // commit the error reported in child process and exit
300f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
301f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
302f4682712SMarri Devender Rao             commit<InternalFailure>();
303f4682712SMarri Devender Rao         }
304d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
305d2393f23SRamesh Iyyar         {
306d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
307d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
308d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
309d2393f23SRamesh Iyyar             commit<InvalidArgument>();
310d2393f23SRamesh Iyyar         }
311f4682712SMarri Devender Rao     }
312f4682712SMarri Devender Rao     else
313f4682712SMarri Devender Rao     {
314f4682712SMarri Devender Rao         using namespace sdeventplus::source;
315f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
316f4682712SMarri Devender Rao                                           const siginfo_t* si) {
317f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
318f4682712SMarri Devender Rao             if (si->si_status != 0)
319f4682712SMarri Devender Rao             {
320f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
321f4682712SMarri Devender Rao             }
322f4682712SMarri Devender Rao             else
323f4682712SMarri Devender Rao             {
324f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
325f4682712SMarri Devender Rao             }
326f4682712SMarri Devender Rao         };
327f4682712SMarri Devender Rao         try
328f4682712SMarri Devender Rao         {
329f4682712SMarri Devender Rao             sigset_t ss;
330f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
331f4682712SMarri Devender Rao             {
332f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
333f4682712SMarri Devender Rao                 elog<InternalFailure>();
334f4682712SMarri Devender Rao             }
335f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
336f4682712SMarri Devender Rao             {
337f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
338f4682712SMarri Devender Rao                 elog<InternalFailure>();
339f4682712SMarri Devender Rao             }
340f4682712SMarri Devender Rao 
341f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
342cfb5802aSNan Zhou             if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
343f4682712SMarri Devender Rao             {
344f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
345f4682712SMarri Devender Rao                 elog<InternalFailure>();
346f4682712SMarri Devender Rao             }
347f4682712SMarri Devender Rao             if (childPtr)
348f4682712SMarri Devender Rao             {
349f4682712SMarri Devender Rao                 childPtr.reset();
350f4682712SMarri Devender Rao             }
351f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
352f4682712SMarri Devender Rao                                                std::move(callback));
353f4682712SMarri Devender Rao         }
354f4682712SMarri Devender Rao         catch (const InternalFailure& e)
355f4682712SMarri Devender Rao         {
356f4682712SMarri Devender Rao             commit<InternalFailure>();
357f4682712SMarri Devender Rao         }
358f4682712SMarri Devender Rao     }
359f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
360f4682712SMarri Devender Rao     return csrObjectPath;
361f4682712SMarri Devender Rao }
362f4682712SMarri Devender Rao 
363db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
364ffad1ef1SMarri Devender Rao {
365db029c95SKowalski, Kamil     return installedCerts;
366ffad1ef1SMarri Devender Rao }
367ffad1ef1SMarri Devender Rao 
368f4682712SMarri Devender Rao void Manager::generateCSRHelper(
369f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
370f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
371f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
372f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
373f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
374f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
375f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
376f4682712SMarri Devender Rao {
377f4682712SMarri Devender Rao     int ret = 0;
378f4682712SMarri Devender Rao 
379f4682712SMarri Devender Rao     // set version of x509 req
380f4682712SMarri Devender Rao     int nVersion = 1;
381f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
382cf06ccdcSNan Zhou     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
383f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
384f4682712SMarri Devender Rao     if (ret == 0)
385f4682712SMarri Devender Rao     {
386bf3cf751SNan Zhou         log<level::ERR>("Error occurred during X509_REQ_set_version call");
387f4682712SMarri Devender Rao         elog<InternalFailure>();
388f4682712SMarri Devender Rao     }
389f4682712SMarri Devender Rao 
390f4682712SMarri Devender Rao     // set subject of x509 req
391f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
392f4682712SMarri Devender Rao 
393f4682712SMarri Devender Rao     if (!alternativeNames.empty())
394f4682712SMarri Devender Rao     {
395f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
396f4682712SMarri Devender Rao         {
397f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
398f4682712SMarri Devender Rao         }
399f4682712SMarri Devender Rao     }
400f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
401f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
402f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
403f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
404f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
405f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
406f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
407f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
408f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
409f4682712SMarri Devender Rao     if (!keyUsage.empty())
410f4682712SMarri Devender Rao     {
411f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
412f4682712SMarri Devender Rao         {
4137641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
4147641105dSMarri Devender Rao             {
4157641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
4167641105dSMarri Devender Rao             }
4177641105dSMarri Devender Rao             else
4187641105dSMarri Devender Rao             {
419f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
420f4682712SMarri Devender Rao             }
421f4682712SMarri Devender Rao         }
4227641105dSMarri Devender Rao     }
423f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
424dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
425f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
426f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
427f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
428f4682712SMarri Devender Rao 
429cf06ccdcSNan Zhou     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
4308a09b52aSRamesh Iyyar 
4318a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
4328a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
4338a09b52aSRamesh Iyyar 
4348a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
4358a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
436c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
4378a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
438c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
4398a09b52aSRamesh Iyyar     else
4408a09b52aSRamesh Iyyar     {
4418a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
4428a09b52aSRamesh Iyyar                         "RSA and EC only");
4438a09b52aSRamesh Iyyar         elog<InvalidArgument>(
4448a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
4458a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
4468a09b52aSRamesh Iyyar     }
4478a09b52aSRamesh Iyyar 
4488a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
4498a09b52aSRamesh Iyyar     if (ret == 0)
4508a09b52aSRamesh Iyyar     {
451bf3cf751SNan Zhou         log<level::ERR>("Error occurred while setting Public key");
4528a09b52aSRamesh Iyyar         elog<InternalFailure>();
4538a09b52aSRamesh Iyyar     }
4548a09b52aSRamesh Iyyar 
4558a09b52aSRamesh Iyyar     // Write private key to file
456718eef37SNan Zhou     writePrivateKey(pKey, defaultPrivateKeyFileName);
457f4682712SMarri Devender Rao 
458f4682712SMarri Devender Rao     // set sign key of x509 req
459f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
4608a09b52aSRamesh Iyyar     if (ret == 0)
461f4682712SMarri Devender Rao     {
462bf3cf751SNan Zhou         log<level::ERR>("Error occurred while signing key of x509");
463f4682712SMarri Devender Rao         elog<InternalFailure>();
464f4682712SMarri Devender Rao     }
4658a09b52aSRamesh Iyyar 
466f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
467718eef37SNan Zhou     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
468c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
469f4682712SMarri Devender Rao }
470f4682712SMarri Devender Rao 
4717641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
4727641105dSMarri Devender Rao {
4737641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
4747641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
4757641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
4767641105dSMarri Devender Rao     auto it = std::find_if(
4777641105dSMarri Devender Rao         usageList.begin(), usageList.end(),
4787641105dSMarri Devender Rao         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
4797641105dSMarri Devender Rao     return it != usageList.end();
4807641105dSMarri Devender Rao }
481cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
482f4682712SMarri Devender Rao {
4838a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
484f4682712SMarri Devender Rao     // set keybit length to default value if not set
4858a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
486f4682712SMarri Devender Rao     {
4878a09b52aSRamesh Iyyar         log<level::INFO>(
4888a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
489cf06ccdcSNan Zhou             entry("DEFAULTKEYBITLENGTH=%d", defaultKeyBitLength));
490cf06ccdcSNan Zhou         keyBitLen = defaultKeyBitLength;
491f4682712SMarri Devender Rao     }
49226fb83efSPatrick Williams 
49326fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
49426fb83efSPatrick Williams 
49526fb83efSPatrick Williams     // generate rsa key
496cf06ccdcSNan Zhou     BignumPtr bne(BN_new(), ::BN_free);
49726fb83efSPatrick Williams     auto ret = BN_set_word(bne.get(), RSA_F4);
49826fb83efSPatrick Williams     if (ret == 0)
49926fb83efSPatrick Williams     {
500bf3cf751SNan Zhou         log<level::ERR>("Error occurred during BN_set_word call");
50126fb83efSPatrick Williams         elog<InternalFailure>();
50226fb83efSPatrick Williams     }
503762da74eSNan Zhou     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
504762da74eSNan Zhou     RSAPtr rsa(RSA_new(), ::RSA_free);
505762da74eSNan Zhou     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
506f4682712SMarri Devender Rao     if (ret != 1)
507f4682712SMarri Devender Rao     {
508bf3cf751SNan Zhou         log<level::ERR>("Error occurred during RSA_generate_key_ex call",
5098a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
510f4682712SMarri Devender Rao         elog<InternalFailure>();
511f4682712SMarri Devender Rao     }
512f4682712SMarri Devender Rao 
513f4682712SMarri Devender Rao     // set public key of x509 req
514cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
515762da74eSNan Zhou     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
516f4682712SMarri Devender Rao     if (ret == 0)
517f4682712SMarri Devender Rao     {
518bf3cf751SNan Zhou         log<level::ERR>("Error occurred during assign rsa key into EVP");
519f4682712SMarri Devender Rao         elog<InternalFailure>();
520f4682712SMarri Devender Rao     }
521762da74eSNan Zhou     // Now |rsa| is managed by |pKey|
522762da74eSNan Zhou     rsa.release();
5238a09b52aSRamesh Iyyar     return pKey;
52426fb83efSPatrick Williams 
52526fb83efSPatrick Williams #else
52626fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
52726fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
52826fb83efSPatrick Williams     if (!ctx)
52926fb83efSPatrick Williams     {
530bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm");
53126fb83efSPatrick Williams         elog<InternalFailure>();
53226fb83efSPatrick Williams     }
53326fb83efSPatrick Williams 
53426fb83efSPatrick Williams     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
53526fb83efSPatrick Williams         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
53626fb83efSPatrick Williams 
53726fb83efSPatrick Williams     {
538bf3cf751SNan Zhou         log<level::ERR>("Error occurred initializing keygen context");
53926fb83efSPatrick Williams         elog<InternalFailure>();
54026fb83efSPatrick Williams     }
54126fb83efSPatrick Williams 
54226fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
54326fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
54426fb83efSPatrick Williams     {
545bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
54626fb83efSPatrick Williams         elog<InternalFailure>();
54726fb83efSPatrick Williams     }
54826fb83efSPatrick Williams 
54926fb83efSPatrick Williams     return {pKey, &::EVP_PKEY_free};
55026fb83efSPatrick Williams #endif
5518a09b52aSRamesh Iyyar }
5528a09b52aSRamesh Iyyar 
553cf06ccdcSNan Zhou EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
5548a09b52aSRamesh Iyyar {
5558a09b52aSRamesh Iyyar     std::string curId(curveId);
5568a09b52aSRamesh Iyyar 
5578a09b52aSRamesh Iyyar     if (curId.empty())
5588a09b52aSRamesh Iyyar     {
5598a09b52aSRamesh Iyyar         log<level::INFO>(
5608a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
561cf06ccdcSNan Zhou             entry("DEFAULTKEYCURVEID=%s", defaultKeyCurveID));
562cf06ccdcSNan Zhou         curId = defaultKeyCurveID;
5638a09b52aSRamesh Iyyar     }
5648a09b52aSRamesh Iyyar 
5658a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
5668a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
5678a09b52aSRamesh Iyyar     {
5688a09b52aSRamesh Iyyar         log<level::ERR>(
569bf3cf751SNan Zhou             "Error occurred during convert the curve id string format into NID",
5708a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
5718a09b52aSRamesh Iyyar         elog<InternalFailure>();
5728a09b52aSRamesh Iyyar     }
5738a09b52aSRamesh Iyyar 
57426fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
57526fb83efSPatrick Williams 
5768a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
5778a09b52aSRamesh Iyyar 
578cfb5802aSNan Zhou     if (ecKey == nullptr)
5798a09b52aSRamesh Iyyar     {
5808a09b52aSRamesh Iyyar         log<level::ERR>(
581bf3cf751SNan Zhou             "Error occurred during create the EC_Key object from NID",
5828a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
5838a09b52aSRamesh Iyyar         elog<InternalFailure>();
5848a09b52aSRamesh Iyyar     }
5858a09b52aSRamesh Iyyar 
5868a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
5878a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
5888a09b52aSRamesh Iyyar     // flag on the key.
5898a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
5908a09b52aSRamesh Iyyar 
5918a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
5928a09b52aSRamesh Iyyar 
5938a09b52aSRamesh Iyyar     if (ret == 0)
5948a09b52aSRamesh Iyyar     {
5958a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
596bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
5978a09b52aSRamesh Iyyar         elog<InternalFailure>();
5988a09b52aSRamesh Iyyar     }
5998a09b52aSRamesh Iyyar 
600cf06ccdcSNan Zhou     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
6018a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
6028a09b52aSRamesh Iyyar     if (ret == 0)
6038a09b52aSRamesh Iyyar     {
6048a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
605bf3cf751SNan Zhou         log<level::ERR>("Error occurred during assign EC Key into EVP");
6068a09b52aSRamesh Iyyar         elog<InternalFailure>();
6078a09b52aSRamesh Iyyar     }
6088a09b52aSRamesh Iyyar 
6098a09b52aSRamesh Iyyar     return pKey;
61026fb83efSPatrick Williams 
61126fb83efSPatrick Williams #else
61226fb83efSPatrick Williams     auto holder_of_key = [](EVP_PKEY* key) {
61326fb83efSPatrick Williams         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
61426fb83efSPatrick Williams             key, &::EVP_PKEY_free};
61526fb83efSPatrick Williams     };
61626fb83efSPatrick Williams 
61726fb83efSPatrick Williams     // Create context to set up curve parameters.
61826fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
61926fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
62026fb83efSPatrick Williams     if (!ctx)
62126fb83efSPatrick Williams     {
622bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params");
62326fb83efSPatrick Williams         elog<InternalFailure>();
62426fb83efSPatrick Williams     }
62526fb83efSPatrick Williams 
62626fb83efSPatrick Williams     // Set up curve parameters.
62726fb83efSPatrick Williams     EVP_PKEY* params = nullptr;
62826fb83efSPatrick Williams 
62926fb83efSPatrick Williams     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
63026fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
63126fb83efSPatrick Williams          0) ||
63226fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
63326fb83efSPatrick Williams         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
63426fb83efSPatrick Williams     {
635bf3cf751SNan Zhou         log<level::ERR>("Error occurred setting curve parameters");
63626fb83efSPatrick Williams         elog<InternalFailure>();
63726fb83efSPatrick Williams     }
63826fb83efSPatrick Williams 
63926fb83efSPatrick Williams     // Move parameters to RAII holder.
64026fb83efSPatrick Williams     auto pparms = holder_of_key(params);
64126fb83efSPatrick Williams 
64226fb83efSPatrick Williams     // Create new context for key.
64326fb83efSPatrick Williams     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
64426fb83efSPatrick Williams 
64526fb83efSPatrick Williams     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
64626fb83efSPatrick Williams     {
647bf3cf751SNan Zhou         log<level::ERR>("Error occurred initializing keygen context");
64826fb83efSPatrick Williams         elog<InternalFailure>();
64926fb83efSPatrick Williams     }
65026fb83efSPatrick Williams 
65126fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
65226fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
65326fb83efSPatrick Williams     {
654bf3cf751SNan Zhou         log<level::ERR>("Error occurred during generate EC key");
65526fb83efSPatrick Williams         elog<InternalFailure>();
65626fb83efSPatrick Williams     }
65726fb83efSPatrick Williams 
65826fb83efSPatrick Williams     return holder_of_key(pKey);
65926fb83efSPatrick Williams #endif
6608a09b52aSRamesh Iyyar }
6618a09b52aSRamesh Iyyar 
662cf06ccdcSNan Zhou void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
663c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
6648a09b52aSRamesh Iyyar {
6658a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
666f4682712SMarri Devender Rao     // write private key to file
667c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
668f4682712SMarri Devender Rao 
669f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
670cfb5802aSNan Zhou     if (fp == nullptr)
671f4682712SMarri Devender Rao     {
672bf3cf751SNan Zhou         log<level::ERR>("Error occurred creating private key file");
673f4682712SMarri Devender Rao         elog<InternalFailure>();
674f4682712SMarri Devender Rao     }
675cfb5802aSNan Zhou     int ret =
676cfb5802aSNan Zhou         PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr);
677f4682712SMarri Devender Rao     std::fclose(fp);
678f4682712SMarri Devender Rao     if (ret == 0)
679f4682712SMarri Devender Rao     {
680bf3cf751SNan Zhou         log<level::ERR>("Error occurred while writing private key to file");
681f4682712SMarri Devender Rao         elog<InternalFailure>();
682f4682712SMarri Devender Rao     }
683f4682712SMarri Devender Rao }
684f4682712SMarri Devender Rao 
685f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
686f4682712SMarri Devender Rao                        const std::string& bytes)
687f4682712SMarri Devender Rao {
688f4682712SMarri Devender Rao     if (bytes.empty())
689f4682712SMarri Devender Rao     {
690f4682712SMarri Devender Rao         return;
691f4682712SMarri Devender Rao     }
692f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
693f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
694f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
695f4682712SMarri Devender Rao     if (ret != 1)
696f4682712SMarri Devender Rao     {
697f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
698f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
699f4682712SMarri Devender Rao         elog<InternalFailure>();
700f4682712SMarri Devender Rao     }
701f4682712SMarri Devender Rao }
702f4682712SMarri Devender Rao 
703f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
704f4682712SMarri Devender Rao {
705f4682712SMarri Devender Rao     if (csrPtr)
706f4682712SMarri Devender Rao     {
707f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
708f4682712SMarri Devender Rao     }
709f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
710f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
711f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
712f4682712SMarri Devender Rao }
713f4682712SMarri Devender Rao 
714cf06ccdcSNan Zhou void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
715f4682712SMarri Devender Rao {
716f4682712SMarri Devender Rao     if (fs::exists(filePath))
717f4682712SMarri Devender Rao     {
718f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
719f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
720f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
721f4682712SMarri Devender Rao         {
722f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
723f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
724f4682712SMarri Devender Rao             elog<InternalFailure>();
725f4682712SMarri Devender Rao         }
726f4682712SMarri Devender Rao     }
727f4682712SMarri Devender Rao 
728cfb5802aSNan Zhou     FILE* fp = nullptr;
729f4682712SMarri Devender Rao 
730cfb5802aSNan Zhou     if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
731f4682712SMarri Devender Rao     {
732f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
733f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
734f4682712SMarri Devender Rao         elog<InternalFailure>();
735f4682712SMarri Devender Rao     }
736f4682712SMarri Devender Rao 
737f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
738f4682712SMarri Devender Rao     if (!rc)
739f4682712SMarri Devender Rao     {
740f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
741f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
742f4682712SMarri Devender Rao         std::fclose(fp);
743f4682712SMarri Devender Rao         elog<InternalFailure>();
744f4682712SMarri Devender Rao     }
745f4682712SMarri Devender Rao     std::fclose(fp);
746f4682712SMarri Devender Rao }
747f4682712SMarri Devender Rao 
748db029c95SKowalski, Kamil void Manager::createCertificates()
749db029c95SKowalski, Kamil {
750db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
751db029c95SKowalski, Kamil 
752cf06ccdcSNan Zhou     if (certType == CertificateType::Authority)
753db029c95SKowalski, Kamil     {
754fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
755db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
756db029c95SKowalski, Kamil         {
757db029c95SKowalski, Kamil             log<level::ERR>("Certificate installation path exists and it is "
758db029c95SKowalski, Kamil                             "not a directory");
759db029c95SKowalski, Kamil             elog<InternalFailure>();
760db029c95SKowalski, Kamil             return;
761db029c95SKowalski, Kamil         }
762db029c95SKowalski, Kamil 
763db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
764ffad1ef1SMarri Devender Rao         {
765ffad1ef1SMarri Devender Rao             try
766ffad1ef1SMarri Devender Rao             {
7672f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
7682f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
7692f3563ccSZbigniew Lukwinski                 // would add value.
7702f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
7712f3563ccSZbigniew Lukwinski                 {
772db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
773db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
774cf06ccdcSNan Zhou                         certType, certInstallPath, path.path(),
775cf06ccdcSNan Zhou                         certWatchPtr.get(), *this));
7762f3563ccSZbigniew Lukwinski                 }
777ffad1ef1SMarri Devender Rao             }
778ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
779ffad1ef1SMarri Devender Rao             {
780ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
781ffad1ef1SMarri Devender Rao             }
782ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
783ffad1ef1SMarri Devender Rao             {
784cf06ccdcSNan Zhou                 report<InvalidCertificate>(InvalidCertificateReason(
785cf06ccdcSNan Zhou                     "Existing certificate file is corrupted"));
786ffad1ef1SMarri Devender Rao             }
787ffad1ef1SMarri Devender Rao         }
788db029c95SKowalski, Kamil     }
789db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
790db029c95SKowalski, Kamil     {
791db029c95SKowalski, Kamil         try
792db029c95SKowalski, Kamil         {
793db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
7942f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
795cf06ccdcSNan Zhou                 certInstallPath, certWatchPtr.get(), *this));
796db029c95SKowalski, Kamil         }
797db029c95SKowalski, Kamil         catch (const InternalFailure& e)
798db029c95SKowalski, Kamil         {
799db029c95SKowalski, Kamil             report<InternalFailure>();
800db029c95SKowalski, Kamil         }
801db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
802db029c95SKowalski, Kamil         {
803cf06ccdcSNan Zhou             report<InvalidCertificate>(InvalidCertificateReason(
804cf06ccdcSNan Zhou                 "Existing certificate file is corrupted"));
805db029c95SKowalski, Kamil         }
806db029c95SKowalski, Kamil     }
807db029c95SKowalski, Kamil }
808c6e58c7eSRamesh Iyyar 
809c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
810c6e58c7eSRamesh Iyyar {
811c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
812718eef37SNan Zhou         certParentInstallPath / defaultRSAPrivateKeyFileName;
813c6e58c7eSRamesh Iyyar 
814c6e58c7eSRamesh Iyyar     try
815c6e58c7eSRamesh Iyyar     {
816c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
817c6e58c7eSRamesh Iyyar         {
818cf06ccdcSNan Zhou             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
819718eef37SNan Zhou                             defaultRSAPrivateKeyFileName);
820c6e58c7eSRamesh Iyyar         }
821c6e58c7eSRamesh Iyyar     }
822c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
823c6e58c7eSRamesh Iyyar     {
824c6e58c7eSRamesh Iyyar         report<InternalFailure>();
825c6e58c7eSRamesh Iyyar     }
826c6e58c7eSRamesh Iyyar }
827c6e58c7eSRamesh Iyyar 
828cf06ccdcSNan Zhou EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
829c6e58c7eSRamesh Iyyar {
830cf06ccdcSNan Zhou     if (keyBitLength != supportedKeyBitLength)
831c6e58c7eSRamesh Iyyar     {
832c6e58c7eSRamesh Iyyar         log<level::ERR>(
833c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
834c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
835cf06ccdcSNan Zhou             entry("SUPPORTEDKEYBITLENGTH=%d", supportedKeyBitLength));
836c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
837c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
838c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
839c6e58c7eSRamesh Iyyar     }
840c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
841718eef37SNan Zhou         certParentInstallPath / defaultRSAPrivateKeyFileName;
842c6e58c7eSRamesh Iyyar 
843c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
844c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
845c6e58c7eSRamesh Iyyar     {
846c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
847c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
848c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
849c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
850c6e58c7eSRamesh Iyyar     }
851c6e58c7eSRamesh Iyyar 
852cf06ccdcSNan Zhou     EVPPkeyPtr privateKey(
853c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
854c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
855c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
856c6e58c7eSRamesh Iyyar 
857c6e58c7eSRamesh Iyyar     if (!privateKey)
858c6e58c7eSRamesh Iyyar     {
859bf3cf751SNan Zhou         log<level::ERR>("Error occurred during PEM_read_PrivateKey call");
860c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
861c6e58c7eSRamesh Iyyar     }
862c6e58c7eSRamesh Iyyar     return privateKey;
863c6e58c7eSRamesh Iyyar }
8642f3563ccSZbigniew Lukwinski 
8652f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
8662f3563ccSZbigniew Lukwinski {
867cf06ccdcSNan Zhou     if (certType == CertificateType::Authority)
8682f3563ccSZbigniew Lukwinski     {
8692f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
8702f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
8712f3563ccSZbigniew Lukwinski         {
8722f3563ccSZbigniew Lukwinski             try
8732f3563ccSZbigniew Lukwinski             {
8742f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
8752f3563ccSZbigniew Lukwinski                 {
8762f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
8772f3563ccSZbigniew Lukwinski                 }
8782f3563ccSZbigniew Lukwinski             }
8792f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
8802f3563ccSZbigniew Lukwinski             {
8812f3563ccSZbigniew Lukwinski                 log<level::ERR>(
8822f3563ccSZbigniew Lukwinski                     "Failed to remove symlink for certificate",
8832f3563ccSZbigniew Lukwinski                     entry("ERR=%s", e.what()),
8842f3563ccSZbigniew Lukwinski                     entry("SYMLINK=%s", certPath.path().string().c_str()));
8852f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
8862f3563ccSZbigniew Lukwinski             }
8872f3563ccSZbigniew Lukwinski         }
8882f3563ccSZbigniew Lukwinski     }
8892f3563ccSZbigniew Lukwinski 
8902f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
8912f3563ccSZbigniew Lukwinski     {
8922f3563ccSZbigniew Lukwinski         cert->storageUpdate();
8932f3563ccSZbigniew Lukwinski     }
8942f3563ccSZbigniew Lukwinski }
8952f3563ccSZbigniew Lukwinski 
896cf06ccdcSNan Zhou void Manager::reloadOrReset(const std::string& unit)
8972f3563ccSZbigniew Lukwinski {
8982f3563ccSZbigniew Lukwinski     if (!unit.empty())
8992f3563ccSZbigniew Lukwinski     {
9002f3563ccSZbigniew Lukwinski         try
9012f3563ccSZbigniew Lukwinski         {
902cf06ccdcSNan Zhou             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
903cf06ccdcSNan Zhou             constexpr auto defaultSystemdObjectPath =
904cf06ccdcSNan Zhou                 "/org/freedesktop/systemd1";
905cf06ccdcSNan Zhou             constexpr auto defaultSystemdInterface =
9062f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
907cf06ccdcSNan Zhou             auto method = bus.new_method_call(
908cf06ccdcSNan Zhou                 defaultSystemdService, defaultSystemdObjectPath,
909cf06ccdcSNan Zhou                 defaultSystemdInterface, "ReloadOrRestartUnit");
9102f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
9112f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
9122f3563ccSZbigniew Lukwinski         }
913ca128117SPatrick Williams         catch (const sdbusplus::exception::exception& e)
9142f3563ccSZbigniew Lukwinski         {
9152f3563ccSZbigniew Lukwinski             log<level::ERR>("Failed to reload or restart service",
9162f3563ccSZbigniew Lukwinski                             entry("ERR=%s", e.what()),
9172f3563ccSZbigniew Lukwinski                             entry("UNIT=%s", unit.c_str()));
9182f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
9192f3563ccSZbigniew Lukwinski         }
9202f3563ccSZbigniew Lukwinski     }
9212f3563ccSZbigniew Lukwinski }
9222f3563ccSZbigniew Lukwinski 
9232f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
9242f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
9252f3563ccSZbigniew Lukwinski {
9262f3563ccSZbigniew Lukwinski     if (std::any_of(
9272f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
9282f3563ccSZbigniew Lukwinski             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
9292f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
9302f3563ccSZbigniew Lukwinski             }))
9312f3563ccSZbigniew Lukwinski     {
9322f3563ccSZbigniew Lukwinski         return false;
9332f3563ccSZbigniew Lukwinski     }
9342f3563ccSZbigniew Lukwinski     else
9352f3563ccSZbigniew Lukwinski     {
9362f3563ccSZbigniew Lukwinski         return true;
9372f3563ccSZbigniew Lukwinski     }
9382f3563ccSZbigniew Lukwinski }
9392f3563ccSZbigniew Lukwinski 
940e1289adfSNan Zhou } // namespace phosphor::certs
941