xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 26fb83eff52ccab4f26b64a99324b5b3daf4f1c1)
1cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
2cfbc8dc8SJayanth Othayoth 
3*26fb83efSPatrick Williams #include <openssl/evp.h>
4f4682712SMarri Devender Rao #include <openssl/pem.h>
5f4682712SMarri Devender Rao #include <unistd.h>
6f4682712SMarri Devender Rao 
7a3bb38fbSZbigniew Kurzynski #include <algorithm>
86ceec40bSMarri Devender Rao #include <phosphor-logging/elog-errors.hpp>
913bf74e4SMarri Devender Rao #include <xyz/openbmc_project/Certs/error.hpp>
10cfbc8dc8SJayanth Othayoth #include <xyz/openbmc_project/Common/error.hpp>
112f3563ccSZbigniew Lukwinski 
12cfbc8dc8SJayanth Othayoth namespace phosphor
13cfbc8dc8SJayanth Othayoth {
14cfbc8dc8SJayanth Othayoth namespace certs
15cfbc8dc8SJayanth Othayoth {
161396511dSMarri Devender Rao using InternalFailure =
171396511dSMarri Devender Rao     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
18ffad1ef1SMarri Devender Rao using InvalidCertificate =
19ffad1ef1SMarri Devender Rao     sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
20ffad1ef1SMarri Devender Rao using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
21cfbc8dc8SJayanth Othayoth 
22f4682712SMarri Devender Rao using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
23f4682712SMarri Devender Rao using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
24c6e58c7eSRamesh Iyyar using InvalidArgument =
25c6e58c7eSRamesh Iyyar     sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
26c6e58c7eSRamesh Iyyar using Argument = xyz::openbmc_project::Common::InvalidArgument;
27c6e58c7eSRamesh Iyyar 
28c6e58c7eSRamesh Iyyar constexpr auto SUPPORTED_KEYBITLENGTH = 2048;
29f4682712SMarri Devender Rao 
30f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
31f4682712SMarri Devender Rao                  const char* path, const CertificateType& type,
32f4682712SMarri Devender Rao                  UnitsToRestart&& unit, CertInstallPath&& installPath) :
336ceec40bSMarri Devender Rao     Ifaces(bus, path),
34f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
35c6e58c7eSRamesh Iyyar     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
36c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
37cfbc8dc8SJayanth Othayoth {
38db5c6fc8SMarri Devender Rao     try
39db5c6fc8SMarri Devender Rao     {
40fe590c4eSZbigniew Lukwinski         // Create certificate directory if not existing.
41fe590c4eSZbigniew Lukwinski         // Set correct certificate directory permitions.
42fe590c4eSZbigniew Lukwinski         fs::path certDirectory;
43b57d75e2SMarri Devender Rao         try
44b57d75e2SMarri Devender Rao         {
45fe590c4eSZbigniew Lukwinski             if (certType == AUTHORITY)
46b57d75e2SMarri Devender Rao             {
47fe590c4eSZbigniew Lukwinski                 certDirectory = certInstallPath;
48b57d75e2SMarri Devender Rao             }
49fe590c4eSZbigniew Lukwinski             else
50fe590c4eSZbigniew Lukwinski             {
51fe590c4eSZbigniew Lukwinski                 certDirectory = certParentInstallPath;
52fe590c4eSZbigniew Lukwinski             }
53fe590c4eSZbigniew Lukwinski 
54fe590c4eSZbigniew Lukwinski             if (!fs::exists(certDirectory))
55fe590c4eSZbigniew Lukwinski             {
56fe590c4eSZbigniew Lukwinski                 fs::create_directories(certDirectory);
57fe590c4eSZbigniew Lukwinski             }
58fe590c4eSZbigniew Lukwinski 
59667286e4SMarri Devender Rao             auto permission = fs::perms::owner_read | fs::perms::owner_write |
60667286e4SMarri Devender Rao                               fs::perms::owner_exec;
61db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
62db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
632f3563ccSZbigniew Lukwinski             storageUpdate();
64b57d75e2SMarri Devender Rao         }
6571957992SPatrick Williams         catch (const fs::filesystem_error& e)
66b57d75e2SMarri Devender Rao         {
67db5c6fc8SMarri Devender Rao             log<level::ERR>(
68db5c6fc8SMarri Devender Rao                 "Failed to create directory", entry("ERR=%s", e.what()),
69b57d75e2SMarri Devender Rao                 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
70b57d75e2SMarri Devender Rao             report<InternalFailure>();
71b57d75e2SMarri Devender Rao         }
72b57d75e2SMarri Devender Rao 
73c6e58c7eSRamesh Iyyar         // Generating RSA private key file if certificate type is server/client
74c6e58c7eSRamesh Iyyar         if (certType != AUTHORITY)
75c6e58c7eSRamesh Iyyar         {
76c6e58c7eSRamesh Iyyar             createRSAPrivateKeyFile();
77c6e58c7eSRamesh Iyyar         }
78c6e58c7eSRamesh Iyyar 
79ffad1ef1SMarri Devender Rao         // restore any existing certificates
80db029c95SKowalski, Kamil         createCertificates();
81ffad1ef1SMarri Devender Rao 
82ffad1ef1SMarri Devender Rao         // watch is not required for authority certificates
83ffad1ef1SMarri Devender Rao         if (certType != AUTHORITY)
84ffad1ef1SMarri Devender Rao         {
85ffad1ef1SMarri Devender Rao             // watch for certificate file create/replace
86ffad1ef1SMarri Devender Rao             certWatchPtr = std::make_unique<
87ffad1ef1SMarri Devender Rao                 Watch>(event, certInstallPath, [this]() {
88bf7c588cSMarri Devender Rao                 try
89bf7c588cSMarri Devender Rao                 {
90ffad1ef1SMarri Devender Rao                     // if certificate file existing update it
91db029c95SKowalski, Kamil                     if (!installedCerts.empty())
92ffad1ef1SMarri Devender Rao                     {
93db5c6fc8SMarri Devender Rao                         log<level::INFO>("Inotify callback to update "
94db5c6fc8SMarri Devender Rao                                          "certificate properties");
95db029c95SKowalski, Kamil                         installedCerts[0]->populateProperties();
96ffad1ef1SMarri Devender Rao                     }
97ffad1ef1SMarri Devender Rao                     else
98ffad1ef1SMarri Devender Rao                     {
99ffad1ef1SMarri Devender Rao                         log<level::INFO>(
100ffad1ef1SMarri Devender Rao                             "Inotify callback to create certificate object");
101db029c95SKowalski, Kamil                         createCertificates();
102ffad1ef1SMarri Devender Rao                     }
103bf7c588cSMarri Devender Rao                 }
104bf7c588cSMarri Devender Rao                 catch (const InternalFailure& e)
105bf7c588cSMarri Devender Rao                 {
106ffad1ef1SMarri Devender Rao                     commit<InternalFailure>();
107bf7c588cSMarri Devender Rao                 }
108bf7c588cSMarri Devender Rao                 catch (const InvalidCertificate& e)
109bf7c588cSMarri Devender Rao                 {
110ffad1ef1SMarri Devender Rao                     commit<InvalidCertificate>();
111bf7c588cSMarri Devender Rao                 }
112ffad1ef1SMarri Devender Rao             });
113bf7c588cSMarri Devender Rao         }
114db029c95SKowalski, Kamil         else
115db029c95SKowalski, Kamil         {
116db5c6fc8SMarri Devender Rao             try
117db5c6fc8SMarri Devender Rao             {
118db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
119db5c6fc8SMarri Devender Rao                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
120db029c95SKowalski, Kamil                 {
121db029c95SKowalski, Kamil                     log<level::NOTICE>(
122db029c95SKowalski, Kamil                         "Legacy certificate detected, will be installed from: ",
123db5c6fc8SMarri Devender Rao                         entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
124db5c6fc8SMarri Devender Rao                     install(singleCertPath);
125db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
126db029c95SKowalski, Kamil                     {
127db029c95SKowalski, Kamil                         log<level::ERR>(
128db029c95SKowalski, Kamil                             "Unable to remove old certificate from: ",
129db5c6fc8SMarri Devender Rao                             entry("SINGLE_CERTPATH=%s",
130db5c6fc8SMarri Devender Rao                                   singleCertPath.c_str()));
131db029c95SKowalski, Kamil                         elog<InternalFailure>();
132db029c95SKowalski, Kamil                     }
133db029c95SKowalski, Kamil                 }
134db029c95SKowalski, Kamil             }
135db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
136db5c6fc8SMarri Devender Rao             {
137db5c6fc8SMarri Devender Rao                 log<level::ERR>("Error in restoring legacy certificate",
138db5c6fc8SMarri Devender Rao                                 entry("ERROR_STR=%s", ex.what()));
139db5c6fc8SMarri Devender Rao             }
140db5c6fc8SMarri Devender Rao         }
141db5c6fc8SMarri Devender Rao     }
14271957992SPatrick Williams     catch (const std::exception& ex)
143db5c6fc8SMarri Devender Rao     {
144db5c6fc8SMarri Devender Rao         log<level::ERR>("Error in certificate manager constructor",
145db5c6fc8SMarri Devender Rao                         entry("ERROR_STR=%s", ex.what()));
146db5c6fc8SMarri Devender Rao     }
147dd74bd20SJayanth Othayoth }
148589159f2SJayanth Othayoth 
14906a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath)
150cfbc8dc8SJayanth Othayoth {
1511396511dSMarri Devender Rao     using NotAllowed =
1521396511dSMarri Devender Rao         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
1531396511dSMarri Devender Rao     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
154db029c95SKowalski, Kamil 
155db029c95SKowalski, Kamil     if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty())
1561396511dSMarri Devender Rao     {
1571396511dSMarri Devender Rao         elog<NotAllowed>(Reason("Certificate already exist"));
1581396511dSMarri Devender Rao     }
1593b07b77aSZbigniew Lukwinski     else if (certType == phosphor::certs::AUTHORITY &&
1603b07b77aSZbigniew Lukwinski              installedCerts.size() >= AUTHORITY_CERTIFICATES_LIMIT)
1613b07b77aSZbigniew Lukwinski     {
1623b07b77aSZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificates limit reached"));
1633b07b77aSZbigniew Lukwinski     }
164ffad1ef1SMarri Devender Rao 
1652f3563ccSZbigniew Lukwinski     std::string certObjectPath;
1662f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath))
1672f3563ccSZbigniew Lukwinski     {
1682f3563ccSZbigniew Lukwinski         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
169db029c95SKowalski, Kamil         installedCerts.emplace_back(std::make_unique<Certificate>(
1702f3563ccSZbigniew Lukwinski             bus, certObjectPath, certType, certInstallPath, filePath,
1712f3563ccSZbigniew Lukwinski             certWatchPtr, *this));
1722f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
1732f3563ccSZbigniew Lukwinski         certIdCounter++;
1742f3563ccSZbigniew Lukwinski     }
1752f3563ccSZbigniew Lukwinski     else
1762f3563ccSZbigniew Lukwinski     {
1772f3563ccSZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificate already exist"));
1782f3563ccSZbigniew Lukwinski     }
1792f3563ccSZbigniew Lukwinski 
18006a69d7bSZbigniew Kurzynski     return certObjectPath;
181589159f2SJayanth Othayoth }
182ae70b3daSDeepak Kodihalli 
183a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
184ae70b3daSDeepak Kodihalli {
1856ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
1866ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
1876ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
1886ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
1896ceec40bSMarri Devender Rao     // deletion of certificates
190db029c95SKowalski, Kamil     installedCerts.clear();
1912f3563ccSZbigniew Lukwinski     storageUpdate();
1922f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
193ae70b3daSDeepak Kodihalli }
194f4682712SMarri Devender Rao 
1952f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
196a3bb38fbSZbigniew Kurzynski {
197a3bb38fbSZbigniew Kurzynski     std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
198a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
1992f3563ccSZbigniew Lukwinski                      [certificate](std::unique_ptr<Certificate> const& cert) {
2002f3563ccSZbigniew Lukwinski                          return (cert.get() == certificate);
201a3bb38fbSZbigniew Kurzynski                      });
202a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
203a3bb38fbSZbigniew Kurzynski     {
204a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
2052f3563ccSZbigniew Lukwinski         storageUpdate();
2062f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
207a3bb38fbSZbigniew Kurzynski     }
208a3bb38fbSZbigniew Kurzynski     else
209a3bb38fbSZbigniew Kurzynski     {
210a3bb38fbSZbigniew Kurzynski         log<level::ERR>("Certificate does not exist",
2112f3563ccSZbigniew Lukwinski                         entry("ID=%s", certificate->getCertId().c_str()));
2122f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
2132f3563ccSZbigniew Lukwinski     }
2142f3563ccSZbigniew Lukwinski }
2152f3563ccSZbigniew Lukwinski 
2162f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
2172f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
2182f3563ccSZbigniew Lukwinski {
2192f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
2202f3563ccSZbigniew Lukwinski     {
2212f3563ccSZbigniew Lukwinski         certificate->install(filePath);
2222f3563ccSZbigniew Lukwinski         storageUpdate();
2232f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
2242f3563ccSZbigniew Lukwinski     }
2252f3563ccSZbigniew Lukwinski     else
2262f3563ccSZbigniew Lukwinski     {
22715cbbec2SZbigniew Lukwinski         using NotAllowed =
22815cbbec2SZbigniew Lukwinski             sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
22915cbbec2SZbigniew Lukwinski         using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
23015cbbec2SZbigniew Lukwinski 
23115cbbec2SZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificate already exist"));
232a3bb38fbSZbigniew Kurzynski     }
233a3bb38fbSZbigniew Kurzynski }
234a3bb38fbSZbigniew Kurzynski 
235f4682712SMarri Devender Rao std::string Manager::generateCSR(
236f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
237f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
238f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
239f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
240f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
241f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
242f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
243f4682712SMarri Devender Rao {
244f4682712SMarri Devender Rao     // We support only one CSR.
245f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
246f4682712SMarri Devender Rao     auto pid = fork();
247f4682712SMarri Devender Rao     if (pid == -1)
248f4682712SMarri Devender Rao     {
249f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
250f4682712SMarri Devender Rao         report<InternalFailure>();
251f4682712SMarri Devender Rao     }
252f4682712SMarri Devender Rao     else if (pid == 0)
253f4682712SMarri Devender Rao     {
254f4682712SMarri Devender Rao         try
255f4682712SMarri Devender Rao         {
256f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
257f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
258f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
259f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
260f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
261f4682712SMarri Devender Rao                               unstructuredName);
262f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
263f4682712SMarri Devender Rao         }
264f4682712SMarri Devender Rao         catch (const InternalFailure& e)
265f4682712SMarri Devender Rao         {
266f4682712SMarri Devender Rao             // commit the error reported in child process and exit
267f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
268f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
269f4682712SMarri Devender Rao             commit<InternalFailure>();
270f4682712SMarri Devender Rao         }
271d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
272d2393f23SRamesh Iyyar         {
273d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
274d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
275d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
276d2393f23SRamesh Iyyar             commit<InvalidArgument>();
277d2393f23SRamesh Iyyar         }
278f4682712SMarri Devender Rao     }
279f4682712SMarri Devender Rao     else
280f4682712SMarri Devender Rao     {
281f4682712SMarri Devender Rao         using namespace sdeventplus::source;
282f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
283f4682712SMarri Devender Rao                                           const siginfo_t* si) {
284f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
285f4682712SMarri Devender Rao             if (si->si_status != 0)
286f4682712SMarri Devender Rao             {
287f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
288f4682712SMarri Devender Rao             }
289f4682712SMarri Devender Rao             else
290f4682712SMarri Devender Rao             {
291f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
292f4682712SMarri Devender Rao             }
293f4682712SMarri Devender Rao         };
294f4682712SMarri Devender Rao         try
295f4682712SMarri Devender Rao         {
296f4682712SMarri Devender Rao             sigset_t ss;
297f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
298f4682712SMarri Devender Rao             {
299f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
300f4682712SMarri Devender Rao                 elog<InternalFailure>();
301f4682712SMarri Devender Rao             }
302f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
303f4682712SMarri Devender Rao             {
304f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
305f4682712SMarri Devender Rao                 elog<InternalFailure>();
306f4682712SMarri Devender Rao             }
307f4682712SMarri Devender Rao 
308f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
309f4682712SMarri Devender Rao             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
310f4682712SMarri Devender Rao             {
311f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
312f4682712SMarri Devender Rao                 elog<InternalFailure>();
313f4682712SMarri Devender Rao             }
314f4682712SMarri Devender Rao             if (childPtr)
315f4682712SMarri Devender Rao             {
316f4682712SMarri Devender Rao                 childPtr.reset();
317f4682712SMarri Devender Rao             }
318f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
319f4682712SMarri Devender Rao                                                std::move(callback));
320f4682712SMarri Devender Rao         }
321f4682712SMarri Devender Rao         catch (const InternalFailure& e)
322f4682712SMarri Devender Rao         {
323f4682712SMarri Devender Rao             commit<InternalFailure>();
324f4682712SMarri Devender Rao         }
325f4682712SMarri Devender Rao     }
326f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
327f4682712SMarri Devender Rao     return csrObjectPath;
328f4682712SMarri Devender Rao }
329f4682712SMarri Devender Rao 
330db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
331ffad1ef1SMarri Devender Rao {
332db029c95SKowalski, Kamil     return installedCerts;
333ffad1ef1SMarri Devender Rao }
334ffad1ef1SMarri Devender Rao 
335f4682712SMarri Devender Rao void Manager::generateCSRHelper(
336f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
337f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
338f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
339f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
340f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
341f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
342f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
343f4682712SMarri Devender Rao {
344f4682712SMarri Devender Rao     int ret = 0;
345f4682712SMarri Devender Rao 
346f4682712SMarri Devender Rao     // set version of x509 req
347f4682712SMarri Devender Rao     int nVersion = 1;
348f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
349f4682712SMarri Devender Rao     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
350f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
351f4682712SMarri Devender Rao     if (ret == 0)
352f4682712SMarri Devender Rao     {
353f4682712SMarri Devender Rao         log<level::ERR>("Error occured during X509_REQ_set_version call");
354f4682712SMarri Devender Rao         elog<InternalFailure>();
355f4682712SMarri Devender Rao     }
356f4682712SMarri Devender Rao 
357f4682712SMarri Devender Rao     // set subject of x509 req
358f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
359f4682712SMarri Devender Rao 
360f4682712SMarri Devender Rao     if (!alternativeNames.empty())
361f4682712SMarri Devender Rao     {
362f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
363f4682712SMarri Devender Rao         {
364f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
365f4682712SMarri Devender Rao         }
366f4682712SMarri Devender Rao     }
367f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
368f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
369f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
370f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
371f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
372f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
373f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
374f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
375f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
376f4682712SMarri Devender Rao     if (!keyUsage.empty())
377f4682712SMarri Devender Rao     {
378f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
379f4682712SMarri Devender Rao         {
3807641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
3817641105dSMarri Devender Rao             {
3827641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
3837641105dSMarri Devender Rao             }
3847641105dSMarri Devender Rao             else
3857641105dSMarri Devender Rao             {
386f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
387f4682712SMarri Devender Rao             }
388f4682712SMarri Devender Rao         }
3897641105dSMarri Devender Rao     }
390f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
391dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
392f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
393f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
394f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
395f4682712SMarri Devender Rao 
3968a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
3978a09b52aSRamesh Iyyar 
3988a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
3998a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
4008a09b52aSRamesh Iyyar 
4018a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
4028a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
403c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
4048a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
405c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
4068a09b52aSRamesh Iyyar     else
4078a09b52aSRamesh Iyyar     {
4088a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
4098a09b52aSRamesh Iyyar                         "RSA and EC only");
4108a09b52aSRamesh Iyyar         elog<InvalidArgument>(
4118a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
4128a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
4138a09b52aSRamesh Iyyar     }
4148a09b52aSRamesh Iyyar 
4158a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
4168a09b52aSRamesh Iyyar     if (ret == 0)
4178a09b52aSRamesh Iyyar     {
4188a09b52aSRamesh Iyyar         log<level::ERR>("Error occured while setting Public key");
4198a09b52aSRamesh Iyyar         elog<InternalFailure>();
4208a09b52aSRamesh Iyyar     }
4218a09b52aSRamesh Iyyar 
4228a09b52aSRamesh Iyyar     // Write private key to file
423c6e58c7eSRamesh Iyyar     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
424f4682712SMarri Devender Rao 
425f4682712SMarri Devender Rao     // set sign key of x509 req
426f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
4278a09b52aSRamesh Iyyar     if (ret == 0)
428f4682712SMarri Devender Rao     {
429f4682712SMarri Devender Rao         log<level::ERR>("Error occured while signing key of x509");
430f4682712SMarri Devender Rao         elog<InternalFailure>();
431f4682712SMarri Devender Rao     }
4328a09b52aSRamesh Iyyar 
433f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
434c6e58c7eSRamesh Iyyar     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
435c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
436f4682712SMarri Devender Rao }
437f4682712SMarri Devender Rao 
4387641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
4397641105dSMarri Devender Rao {
4407641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
4417641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
4427641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
4437641105dSMarri Devender Rao     auto it = std::find_if(
4447641105dSMarri Devender Rao         usageList.begin(), usageList.end(),
4457641105dSMarri Devender Rao         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
4467641105dSMarri Devender Rao     return it != usageList.end();
4477641105dSMarri Devender Rao }
4488a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
449f4682712SMarri Devender Rao {
4508a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
451f4682712SMarri Devender Rao     // set keybit length to default value if not set
4528a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
453f4682712SMarri Devender Rao     {
4548a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
4558a09b52aSRamesh Iyyar         log<level::INFO>(
4568a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
4578a09b52aSRamesh Iyyar             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
4588a09b52aSRamesh Iyyar         keyBitLen = DEFAULT_KEYBITLENGTH;
459f4682712SMarri Devender Rao     }
460*26fb83efSPatrick Williams 
461*26fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
462*26fb83efSPatrick Williams 
463*26fb83efSPatrick Williams     // generate rsa key
464*26fb83efSPatrick Williams     BIGNUM_Ptr bne(BN_new(), ::BN_free);
465*26fb83efSPatrick Williams     auto ret = BN_set_word(bne.get(), RSA_F4);
466*26fb83efSPatrick Williams     if (ret == 0)
467*26fb83efSPatrick Williams     {
468*26fb83efSPatrick Williams         log<level::ERR>("Error occured during BN_set_word call");
469*26fb83efSPatrick Williams         elog<InternalFailure>();
470*26fb83efSPatrick Williams     }
471*26fb83efSPatrick Williams 
472f4682712SMarri Devender Rao     RSA* rsa = RSA_new();
4738a09b52aSRamesh Iyyar     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
474f4682712SMarri Devender Rao     if (ret != 1)
475f4682712SMarri Devender Rao     {
476f4682712SMarri Devender Rao         free(rsa);
477f4682712SMarri Devender Rao         log<level::ERR>("Error occured during RSA_generate_key_ex call",
4788a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
479f4682712SMarri Devender Rao         elog<InternalFailure>();
480f4682712SMarri Devender Rao     }
481f4682712SMarri Devender Rao 
482f4682712SMarri Devender Rao     // set public key of x509 req
483f4682712SMarri Devender Rao     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
4848a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
485f4682712SMarri Devender Rao     if (ret == 0)
486f4682712SMarri Devender Rao     {
4878a09b52aSRamesh Iyyar         free(rsa);
4888a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign rsa key into EVP");
489f4682712SMarri Devender Rao         elog<InternalFailure>();
490f4682712SMarri Devender Rao     }
491f4682712SMarri Devender Rao 
4928a09b52aSRamesh Iyyar     return pKey;
493*26fb83efSPatrick Williams 
494*26fb83efSPatrick Williams #else
495*26fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
496*26fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
497*26fb83efSPatrick Williams     if (!ctx)
498*26fb83efSPatrick Williams     {
499*26fb83efSPatrick Williams         log<level::ERR>("Error occured creating EVP_PKEY_CTX from algorithm");
500*26fb83efSPatrick Williams         elog<InternalFailure>();
501*26fb83efSPatrick Williams     }
502*26fb83efSPatrick Williams 
503*26fb83efSPatrick Williams     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
504*26fb83efSPatrick Williams         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
505*26fb83efSPatrick Williams 
506*26fb83efSPatrick Williams     {
507*26fb83efSPatrick Williams         log<level::ERR>("Error occured initializing keygen context");
508*26fb83efSPatrick Williams         elog<InternalFailure>();
509*26fb83efSPatrick Williams     }
510*26fb83efSPatrick Williams 
511*26fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
512*26fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
513*26fb83efSPatrick Williams     {
514*26fb83efSPatrick Williams         log<level::ERR>("Error occured during generate EC key");
515*26fb83efSPatrick Williams         elog<InternalFailure>();
516*26fb83efSPatrick Williams     }
517*26fb83efSPatrick Williams 
518*26fb83efSPatrick Williams     return {pKey, &::EVP_PKEY_free};
519*26fb83efSPatrick Williams #endif
5208a09b52aSRamesh Iyyar }
5218a09b52aSRamesh Iyyar 
5228a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
5238a09b52aSRamesh Iyyar {
5248a09b52aSRamesh Iyyar     std::string curId(curveId);
5258a09b52aSRamesh Iyyar 
5268a09b52aSRamesh Iyyar     if (curId.empty())
5278a09b52aSRamesh Iyyar     {
5288a09b52aSRamesh Iyyar         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
5298a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
5308a09b52aSRamesh Iyyar         log<level::INFO>(
5318a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
5328a09b52aSRamesh Iyyar             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
5338a09b52aSRamesh Iyyar         curId = DEFAULT_KEYCURVEID;
5348a09b52aSRamesh Iyyar     }
5358a09b52aSRamesh Iyyar 
5368a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
5378a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
5388a09b52aSRamesh Iyyar     {
5398a09b52aSRamesh Iyyar         log<level::ERR>(
5408a09b52aSRamesh Iyyar             "Error occured during convert the curve id string format into NID",
5418a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
5428a09b52aSRamesh Iyyar         elog<InternalFailure>();
5438a09b52aSRamesh Iyyar     }
5448a09b52aSRamesh Iyyar 
545*26fb83efSPatrick Williams #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
546*26fb83efSPatrick Williams 
5478a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
5488a09b52aSRamesh Iyyar 
5498a09b52aSRamesh Iyyar     if (ecKey == NULL)
5508a09b52aSRamesh Iyyar     {
5518a09b52aSRamesh Iyyar         log<level::ERR>(
5528a09b52aSRamesh Iyyar             "Error occured during create the EC_Key object from NID",
5538a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
5548a09b52aSRamesh Iyyar         elog<InternalFailure>();
5558a09b52aSRamesh Iyyar     }
5568a09b52aSRamesh Iyyar 
5578a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
5588a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
5598a09b52aSRamesh Iyyar     // flag on the key.
5608a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
5618a09b52aSRamesh Iyyar 
5628a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
5638a09b52aSRamesh Iyyar 
5648a09b52aSRamesh Iyyar     if (ret == 0)
5658a09b52aSRamesh Iyyar     {
5668a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5678a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during generate EC key");
5688a09b52aSRamesh Iyyar         elog<InternalFailure>();
5698a09b52aSRamesh Iyyar     }
5708a09b52aSRamesh Iyyar 
5718a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
5728a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
5738a09b52aSRamesh Iyyar     if (ret == 0)
5748a09b52aSRamesh Iyyar     {
5758a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5768a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign EC Key into EVP");
5778a09b52aSRamesh Iyyar         elog<InternalFailure>();
5788a09b52aSRamesh Iyyar     }
5798a09b52aSRamesh Iyyar 
5808a09b52aSRamesh Iyyar     return pKey;
581*26fb83efSPatrick Williams 
582*26fb83efSPatrick Williams #else
583*26fb83efSPatrick Williams     auto holder_of_key = [](EVP_PKEY* key) {
584*26fb83efSPatrick Williams         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
585*26fb83efSPatrick Williams             key, &::EVP_PKEY_free};
586*26fb83efSPatrick Williams     };
587*26fb83efSPatrick Williams 
588*26fb83efSPatrick Williams     // Create context to set up curve parameters.
589*26fb83efSPatrick Williams     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
590*26fb83efSPatrick Williams         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
591*26fb83efSPatrick Williams     if (!ctx)
592*26fb83efSPatrick Williams     {
593*26fb83efSPatrick Williams         log<level::ERR>("Error occured creating EVP_PKEY_CTX for params");
594*26fb83efSPatrick Williams         elog<InternalFailure>();
595*26fb83efSPatrick Williams     }
596*26fb83efSPatrick Williams 
597*26fb83efSPatrick Williams     // Set up curve parameters.
598*26fb83efSPatrick Williams     EVP_PKEY* params = nullptr;
599*26fb83efSPatrick Williams 
600*26fb83efSPatrick Williams     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
601*26fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
602*26fb83efSPatrick Williams          0) ||
603*26fb83efSPatrick Williams         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
604*26fb83efSPatrick Williams         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
605*26fb83efSPatrick Williams     {
606*26fb83efSPatrick Williams         log<level::ERR>("Error occured setting curve parameters");
607*26fb83efSPatrick Williams         elog<InternalFailure>();
608*26fb83efSPatrick Williams     }
609*26fb83efSPatrick Williams 
610*26fb83efSPatrick Williams     // Move parameters to RAII holder.
611*26fb83efSPatrick Williams     auto pparms = holder_of_key(params);
612*26fb83efSPatrick Williams 
613*26fb83efSPatrick Williams     // Create new context for key.
614*26fb83efSPatrick Williams     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
615*26fb83efSPatrick Williams 
616*26fb83efSPatrick Williams     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
617*26fb83efSPatrick Williams     {
618*26fb83efSPatrick Williams         log<level::ERR>("Error occured initializing keygen context");
619*26fb83efSPatrick Williams         elog<InternalFailure>();
620*26fb83efSPatrick Williams     }
621*26fb83efSPatrick Williams 
622*26fb83efSPatrick Williams     EVP_PKEY* pKey = nullptr;
623*26fb83efSPatrick Williams     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
624*26fb83efSPatrick Williams     {
625*26fb83efSPatrick Williams         log<level::ERR>("Error occured during generate EC key");
626*26fb83efSPatrick Williams         elog<InternalFailure>();
627*26fb83efSPatrick Williams     }
628*26fb83efSPatrick Williams 
629*26fb83efSPatrick Williams     return holder_of_key(pKey);
630*26fb83efSPatrick Williams #endif
6318a09b52aSRamesh Iyyar }
6328a09b52aSRamesh Iyyar 
633c6e58c7eSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
634c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
6358a09b52aSRamesh Iyyar {
6368a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
637f4682712SMarri Devender Rao     // write private key to file
638c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
639f4682712SMarri Devender Rao 
640f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
641f4682712SMarri Devender Rao     if (fp == NULL)
642f4682712SMarri Devender Rao     {
643f4682712SMarri Devender Rao         log<level::ERR>("Error occured creating private key file");
644f4682712SMarri Devender Rao         elog<InternalFailure>();
645f4682712SMarri Devender Rao     }
6468a09b52aSRamesh Iyyar     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
647f4682712SMarri Devender Rao     std::fclose(fp);
648f4682712SMarri Devender Rao     if (ret == 0)
649f4682712SMarri Devender Rao     {
650f4682712SMarri Devender Rao         log<level::ERR>("Error occured while writing private key to file");
651f4682712SMarri Devender Rao         elog<InternalFailure>();
652f4682712SMarri Devender Rao     }
653f4682712SMarri Devender Rao }
654f4682712SMarri Devender Rao 
655f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
656f4682712SMarri Devender Rao                        const std::string& bytes)
657f4682712SMarri Devender Rao {
658f4682712SMarri Devender Rao     if (bytes.empty())
659f4682712SMarri Devender Rao     {
660f4682712SMarri Devender Rao         return;
661f4682712SMarri Devender Rao     }
662f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
663f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
664f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
665f4682712SMarri Devender Rao     if (ret != 1)
666f4682712SMarri Devender Rao     {
667f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
668f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
669f4682712SMarri Devender Rao         elog<InternalFailure>();
670f4682712SMarri Devender Rao     }
671f4682712SMarri Devender Rao }
672f4682712SMarri Devender Rao 
673f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
674f4682712SMarri Devender Rao {
675f4682712SMarri Devender Rao     if (csrPtr)
676f4682712SMarri Devender Rao     {
677f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
678f4682712SMarri Devender Rao     }
679f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
680f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
681f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
682f4682712SMarri Devender Rao }
683f4682712SMarri Devender Rao 
684f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
685f4682712SMarri Devender Rao {
686f4682712SMarri Devender Rao     if (fs::exists(filePath))
687f4682712SMarri Devender Rao     {
688f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
689f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
690f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
691f4682712SMarri Devender Rao         {
692f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
693f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
694f4682712SMarri Devender Rao             elog<InternalFailure>();
695f4682712SMarri Devender Rao         }
696f4682712SMarri Devender Rao     }
697f4682712SMarri Devender Rao 
698f4682712SMarri Devender Rao     FILE* fp = NULL;
699f4682712SMarri Devender Rao 
700f4682712SMarri Devender Rao     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
701f4682712SMarri Devender Rao     {
702f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
703f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
704f4682712SMarri Devender Rao         elog<InternalFailure>();
705f4682712SMarri Devender Rao     }
706f4682712SMarri Devender Rao 
707f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
708f4682712SMarri Devender Rao     if (!rc)
709f4682712SMarri Devender Rao     {
710f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
711f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
712f4682712SMarri Devender Rao         std::fclose(fp);
713f4682712SMarri Devender Rao         elog<InternalFailure>();
714f4682712SMarri Devender Rao     }
715f4682712SMarri Devender Rao     std::fclose(fp);
716f4682712SMarri Devender Rao }
717f4682712SMarri Devender Rao 
718db029c95SKowalski, Kamil void Manager::createCertificates()
719db029c95SKowalski, Kamil {
720db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
721db029c95SKowalski, Kamil 
722db029c95SKowalski, Kamil     if (certType == phosphor::certs::AUTHORITY)
723db029c95SKowalski, Kamil     {
724fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
725db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
726db029c95SKowalski, Kamil         {
727db029c95SKowalski, Kamil             log<level::ERR>("Certificate installation path exists and it is "
728db029c95SKowalski, Kamil                             "not a directory");
729db029c95SKowalski, Kamil             elog<InternalFailure>();
730db029c95SKowalski, Kamil             return;
731db029c95SKowalski, Kamil         }
732db029c95SKowalski, Kamil 
733db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
734ffad1ef1SMarri Devender Rao         {
735ffad1ef1SMarri Devender Rao             try
736ffad1ef1SMarri Devender Rao             {
7372f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
7382f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
7392f3563ccSZbigniew Lukwinski                 // would add value.
7402f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
7412f3563ccSZbigniew Lukwinski                 {
742db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
743db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
7442f3563ccSZbigniew Lukwinski                         certType, certInstallPath, path.path(), certWatchPtr,
7452f3563ccSZbigniew Lukwinski                         *this));
7462f3563ccSZbigniew Lukwinski                 }
747ffad1ef1SMarri Devender Rao             }
748ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
749ffad1ef1SMarri Devender Rao             {
750ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
751ffad1ef1SMarri Devender Rao             }
752ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
753ffad1ef1SMarri Devender Rao             {
754ffad1ef1SMarri Devender Rao                 report<InvalidCertificate>(
755ffad1ef1SMarri Devender Rao                     Reason("Existing certificate file is corrupted"));
756ffad1ef1SMarri Devender Rao             }
757ffad1ef1SMarri Devender Rao         }
758db029c95SKowalski, Kamil     }
759db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
760db029c95SKowalski, Kamil     {
761db029c95SKowalski, Kamil         try
762db029c95SKowalski, Kamil         {
763db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
7642f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
7652f3563ccSZbigniew Lukwinski                 certInstallPath, certWatchPtr, *this));
766db029c95SKowalski, Kamil         }
767db029c95SKowalski, Kamil         catch (const InternalFailure& e)
768db029c95SKowalski, Kamil         {
769db029c95SKowalski, Kamil             report<InternalFailure>();
770db029c95SKowalski, Kamil         }
771db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
772db029c95SKowalski, Kamil         {
773db029c95SKowalski, Kamil             report<InvalidCertificate>(
774db029c95SKowalski, Kamil                 Reason("Existing certificate file is corrupted"));
775db029c95SKowalski, Kamil         }
776db029c95SKowalski, Kamil     }
777db029c95SKowalski, Kamil }
778c6e58c7eSRamesh Iyyar 
779c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
780c6e58c7eSRamesh Iyyar {
781c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
782c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
783c6e58c7eSRamesh Iyyar 
784c6e58c7eSRamesh Iyyar     try
785c6e58c7eSRamesh Iyyar     {
786c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
787c6e58c7eSRamesh Iyyar         {
788c6e58c7eSRamesh Iyyar             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
789c6e58c7eSRamesh Iyyar                             RSA_PRIV_KEY_FILE_NAME);
790c6e58c7eSRamesh Iyyar         }
791c6e58c7eSRamesh Iyyar     }
792c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
793c6e58c7eSRamesh Iyyar     {
794c6e58c7eSRamesh Iyyar         report<InternalFailure>();
795c6e58c7eSRamesh Iyyar     }
796c6e58c7eSRamesh Iyyar }
797c6e58c7eSRamesh Iyyar 
798c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
799c6e58c7eSRamesh Iyyar {
800c6e58c7eSRamesh Iyyar     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
801c6e58c7eSRamesh Iyyar     {
802c6e58c7eSRamesh Iyyar         log<level::ERR>(
803c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
804c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
805c6e58c7eSRamesh Iyyar             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
806c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
807c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
808c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
809c6e58c7eSRamesh Iyyar     }
810c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
811c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
812c6e58c7eSRamesh Iyyar 
813c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
814c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
815c6e58c7eSRamesh Iyyar     {
816c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
817c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
818c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
819c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
820c6e58c7eSRamesh Iyyar     }
821c6e58c7eSRamesh Iyyar 
822c6e58c7eSRamesh Iyyar     EVP_PKEY_Ptr privateKey(
823c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
824c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
825c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
826c6e58c7eSRamesh Iyyar 
827c6e58c7eSRamesh Iyyar     if (!privateKey)
828c6e58c7eSRamesh Iyyar     {
829c6e58c7eSRamesh Iyyar         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
830c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
831c6e58c7eSRamesh Iyyar     }
832c6e58c7eSRamesh Iyyar     return privateKey;
833c6e58c7eSRamesh Iyyar }
8342f3563ccSZbigniew Lukwinski 
8352f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
8362f3563ccSZbigniew Lukwinski {
8372f3563ccSZbigniew Lukwinski     if (certType == phosphor::certs::AUTHORITY)
8382f3563ccSZbigniew Lukwinski     {
8392f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
8402f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
8412f3563ccSZbigniew Lukwinski         {
8422f3563ccSZbigniew Lukwinski             try
8432f3563ccSZbigniew Lukwinski             {
8442f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
8452f3563ccSZbigniew Lukwinski                 {
8462f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
8472f3563ccSZbigniew Lukwinski                 }
8482f3563ccSZbigniew Lukwinski             }
8492f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
8502f3563ccSZbigniew Lukwinski             {
8512f3563ccSZbigniew Lukwinski                 log<level::ERR>(
8522f3563ccSZbigniew Lukwinski                     "Failed to remove symlink for certificate",
8532f3563ccSZbigniew Lukwinski                     entry("ERR=%s", e.what()),
8542f3563ccSZbigniew Lukwinski                     entry("SYMLINK=%s", certPath.path().string().c_str()));
8552f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
8562f3563ccSZbigniew Lukwinski             }
8572f3563ccSZbigniew Lukwinski         }
8582f3563ccSZbigniew Lukwinski     }
8592f3563ccSZbigniew Lukwinski 
8602f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
8612f3563ccSZbigniew Lukwinski     {
8622f3563ccSZbigniew Lukwinski         cert->storageUpdate();
8632f3563ccSZbigniew Lukwinski     }
8642f3563ccSZbigniew Lukwinski }
8652f3563ccSZbigniew Lukwinski 
8662f3563ccSZbigniew Lukwinski void Manager::reloadOrReset(const UnitsToRestart& unit)
8672f3563ccSZbigniew Lukwinski {
8682f3563ccSZbigniew Lukwinski     if (!unit.empty())
8692f3563ccSZbigniew Lukwinski     {
8702f3563ccSZbigniew Lukwinski         try
8712f3563ccSZbigniew Lukwinski         {
8722f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
8732f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
8742f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_INTERFACE =
8752f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
8762f3563ccSZbigniew Lukwinski 
8772f3563ccSZbigniew Lukwinski             auto method =
8782f3563ccSZbigniew Lukwinski                 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
8792f3563ccSZbigniew Lukwinski                                     SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
8802f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
8812f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
8822f3563ccSZbigniew Lukwinski         }
883ca128117SPatrick Williams         catch (const sdbusplus::exception::exception& e)
8842f3563ccSZbigniew Lukwinski         {
8852f3563ccSZbigniew Lukwinski             log<level::ERR>("Failed to reload or restart service",
8862f3563ccSZbigniew Lukwinski                             entry("ERR=%s", e.what()),
8872f3563ccSZbigniew Lukwinski                             entry("UNIT=%s", unit.c_str()));
8882f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
8892f3563ccSZbigniew Lukwinski         }
8902f3563ccSZbigniew Lukwinski     }
8912f3563ccSZbigniew Lukwinski }
8922f3563ccSZbigniew Lukwinski 
8932f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
8942f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
8952f3563ccSZbigniew Lukwinski {
8962f3563ccSZbigniew Lukwinski     if (std::any_of(
8972f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
8982f3563ccSZbigniew Lukwinski             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
8992f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
9002f3563ccSZbigniew Lukwinski             }))
9012f3563ccSZbigniew Lukwinski     {
9022f3563ccSZbigniew Lukwinski         return false;
9032f3563ccSZbigniew Lukwinski     }
9042f3563ccSZbigniew Lukwinski     else
9052f3563ccSZbigniew Lukwinski     {
9062f3563ccSZbigniew Lukwinski         return true;
9072f3563ccSZbigniew Lukwinski     }
9082f3563ccSZbigniew Lukwinski }
9092f3563ccSZbigniew Lukwinski 
910cfbc8dc8SJayanth Othayoth } // namespace certs
911cfbc8dc8SJayanth Othayoth } // namespace phosphor
912