xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 71957992588d1b239c33ba25cf713b48b4014521)
1cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
2cfbc8dc8SJayanth Othayoth 
3f4682712SMarri Devender Rao #include <openssl/pem.h>
4f4682712SMarri Devender Rao #include <unistd.h>
5f4682712SMarri Devender Rao 
6a3bb38fbSZbigniew Kurzynski #include <algorithm>
76ceec40bSMarri Devender Rao #include <phosphor-logging/elog-errors.hpp>
813bf74e4SMarri Devender Rao #include <xyz/openbmc_project/Certs/error.hpp>
9cfbc8dc8SJayanth Othayoth #include <xyz/openbmc_project/Common/error.hpp>
102f3563ccSZbigniew Lukwinski 
11cfbc8dc8SJayanth Othayoth namespace phosphor
12cfbc8dc8SJayanth Othayoth {
13cfbc8dc8SJayanth Othayoth namespace certs
14cfbc8dc8SJayanth Othayoth {
151396511dSMarri Devender Rao using InternalFailure =
161396511dSMarri Devender Rao     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
17ffad1ef1SMarri Devender Rao using InvalidCertificate =
18ffad1ef1SMarri Devender Rao     sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
19ffad1ef1SMarri Devender Rao using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
20cfbc8dc8SJayanth Othayoth 
21f4682712SMarri Devender Rao using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
22f4682712SMarri Devender Rao using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
23c6e58c7eSRamesh Iyyar using InvalidArgument =
24c6e58c7eSRamesh Iyyar     sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
25c6e58c7eSRamesh Iyyar using Argument = xyz::openbmc_project::Common::InvalidArgument;
26c6e58c7eSRamesh Iyyar 
27c6e58c7eSRamesh Iyyar constexpr auto SUPPORTED_KEYBITLENGTH = 2048;
28f4682712SMarri Devender Rao 
29f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
30f4682712SMarri Devender Rao                  const char* path, const CertificateType& type,
31f4682712SMarri Devender Rao                  UnitsToRestart&& unit, CertInstallPath&& installPath) :
326ceec40bSMarri Devender Rao     Ifaces(bus, path),
33f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
34c6e58c7eSRamesh Iyyar     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
35c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
36cfbc8dc8SJayanth Othayoth {
37db5c6fc8SMarri Devender Rao     try
38db5c6fc8SMarri Devender Rao     {
39fe590c4eSZbigniew Lukwinski         // Create certificate directory if not existing.
40fe590c4eSZbigniew Lukwinski         // Set correct certificate directory permitions.
41fe590c4eSZbigniew Lukwinski         fs::path certDirectory;
42b57d75e2SMarri Devender Rao         try
43b57d75e2SMarri Devender Rao         {
44fe590c4eSZbigniew Lukwinski             if (certType == AUTHORITY)
45b57d75e2SMarri Devender Rao             {
46fe590c4eSZbigniew Lukwinski                 certDirectory = certInstallPath;
47b57d75e2SMarri Devender Rao             }
48fe590c4eSZbigniew Lukwinski             else
49fe590c4eSZbigniew Lukwinski             {
50fe590c4eSZbigniew Lukwinski                 certDirectory = certParentInstallPath;
51fe590c4eSZbigniew Lukwinski             }
52fe590c4eSZbigniew Lukwinski 
53fe590c4eSZbigniew Lukwinski             if (!fs::exists(certDirectory))
54fe590c4eSZbigniew Lukwinski             {
55fe590c4eSZbigniew Lukwinski                 fs::create_directories(certDirectory);
56fe590c4eSZbigniew Lukwinski             }
57fe590c4eSZbigniew Lukwinski 
58667286e4SMarri Devender Rao             auto permission = fs::perms::owner_read | fs::perms::owner_write |
59667286e4SMarri Devender Rao                               fs::perms::owner_exec;
60db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
61db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
622f3563ccSZbigniew Lukwinski             storageUpdate();
63b57d75e2SMarri Devender Rao         }
64*71957992SPatrick Williams         catch (const fs::filesystem_error& e)
65b57d75e2SMarri Devender Rao         {
66db5c6fc8SMarri Devender Rao             log<level::ERR>(
67db5c6fc8SMarri Devender Rao                 "Failed to create directory", entry("ERR=%s", e.what()),
68b57d75e2SMarri Devender Rao                 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
69b57d75e2SMarri Devender Rao             report<InternalFailure>();
70b57d75e2SMarri Devender Rao         }
71b57d75e2SMarri Devender Rao 
72c6e58c7eSRamesh Iyyar         // Generating RSA private key file if certificate type is server/client
73c6e58c7eSRamesh Iyyar         if (certType != AUTHORITY)
74c6e58c7eSRamesh Iyyar         {
75c6e58c7eSRamesh Iyyar             createRSAPrivateKeyFile();
76c6e58c7eSRamesh Iyyar         }
77c6e58c7eSRamesh Iyyar 
78ffad1ef1SMarri Devender Rao         // restore any existing certificates
79db029c95SKowalski, Kamil         createCertificates();
80ffad1ef1SMarri Devender Rao 
81ffad1ef1SMarri Devender Rao         // watch is not required for authority certificates
82ffad1ef1SMarri Devender Rao         if (certType != AUTHORITY)
83ffad1ef1SMarri Devender Rao         {
84ffad1ef1SMarri Devender Rao             // watch for certificate file create/replace
85ffad1ef1SMarri Devender Rao             certWatchPtr = std::make_unique<
86ffad1ef1SMarri Devender Rao                 Watch>(event, certInstallPath, [this]() {
87bf7c588cSMarri Devender Rao                 try
88bf7c588cSMarri Devender Rao                 {
89ffad1ef1SMarri Devender Rao                     // if certificate file existing update it
90db029c95SKowalski, Kamil                     if (!installedCerts.empty())
91ffad1ef1SMarri Devender Rao                     {
92db5c6fc8SMarri Devender Rao                         log<level::INFO>("Inotify callback to update "
93db5c6fc8SMarri Devender Rao                                          "certificate properties");
94db029c95SKowalski, Kamil                         installedCerts[0]->populateProperties();
95ffad1ef1SMarri Devender Rao                     }
96ffad1ef1SMarri Devender Rao                     else
97ffad1ef1SMarri Devender Rao                     {
98ffad1ef1SMarri Devender Rao                         log<level::INFO>(
99ffad1ef1SMarri Devender Rao                             "Inotify callback to create certificate object");
100db029c95SKowalski, Kamil                         createCertificates();
101ffad1ef1SMarri Devender Rao                     }
102bf7c588cSMarri Devender Rao                 }
103bf7c588cSMarri Devender Rao                 catch (const InternalFailure& e)
104bf7c588cSMarri Devender Rao                 {
105ffad1ef1SMarri Devender Rao                     commit<InternalFailure>();
106bf7c588cSMarri Devender Rao                 }
107bf7c588cSMarri Devender Rao                 catch (const InvalidCertificate& e)
108bf7c588cSMarri Devender Rao                 {
109ffad1ef1SMarri Devender Rao                     commit<InvalidCertificate>();
110bf7c588cSMarri Devender Rao                 }
111ffad1ef1SMarri Devender Rao             });
112bf7c588cSMarri Devender Rao         }
113db029c95SKowalski, Kamil         else
114db029c95SKowalski, Kamil         {
115db5c6fc8SMarri Devender Rao             try
116db5c6fc8SMarri Devender Rao             {
117db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
118db5c6fc8SMarri Devender Rao                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
119db029c95SKowalski, Kamil                 {
120db029c95SKowalski, Kamil                     log<level::NOTICE>(
121db029c95SKowalski, Kamil                         "Legacy certificate detected, will be installed from: ",
122db5c6fc8SMarri Devender Rao                         entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
123db5c6fc8SMarri Devender Rao                     install(singleCertPath);
124db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
125db029c95SKowalski, Kamil                     {
126db029c95SKowalski, Kamil                         log<level::ERR>(
127db029c95SKowalski, Kamil                             "Unable to remove old certificate from: ",
128db5c6fc8SMarri Devender Rao                             entry("SINGLE_CERTPATH=%s",
129db5c6fc8SMarri Devender Rao                                   singleCertPath.c_str()));
130db029c95SKowalski, Kamil                         elog<InternalFailure>();
131db029c95SKowalski, Kamil                     }
132db029c95SKowalski, Kamil                 }
133db029c95SKowalski, Kamil             }
134db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
135db5c6fc8SMarri Devender Rao             {
136db5c6fc8SMarri Devender Rao                 log<level::ERR>("Error in restoring legacy certificate",
137db5c6fc8SMarri Devender Rao                                 entry("ERROR_STR=%s", ex.what()));
138db5c6fc8SMarri Devender Rao             }
139db5c6fc8SMarri Devender Rao         }
140db5c6fc8SMarri Devender Rao     }
141*71957992SPatrick Williams     catch (const std::exception& ex)
142db5c6fc8SMarri Devender Rao     {
143db5c6fc8SMarri Devender Rao         log<level::ERR>("Error in certificate manager constructor",
144db5c6fc8SMarri Devender Rao                         entry("ERROR_STR=%s", ex.what()));
145db5c6fc8SMarri Devender Rao     }
146dd74bd20SJayanth Othayoth }
147589159f2SJayanth Othayoth 
14806a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath)
149cfbc8dc8SJayanth Othayoth {
1501396511dSMarri Devender Rao     using NotAllowed =
1511396511dSMarri Devender Rao         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
1521396511dSMarri Devender Rao     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
153db029c95SKowalski, Kamil 
154db029c95SKowalski, Kamil     if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty())
1551396511dSMarri Devender Rao     {
1561396511dSMarri Devender Rao         elog<NotAllowed>(Reason("Certificate already exist"));
1571396511dSMarri Devender Rao     }
1583b07b77aSZbigniew Lukwinski     else if (certType == phosphor::certs::AUTHORITY &&
1593b07b77aSZbigniew Lukwinski              installedCerts.size() >= AUTHORITY_CERTIFICATES_LIMIT)
1603b07b77aSZbigniew Lukwinski     {
1613b07b77aSZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificates limit reached"));
1623b07b77aSZbigniew Lukwinski     }
163ffad1ef1SMarri Devender Rao 
1642f3563ccSZbigniew Lukwinski     std::string certObjectPath;
1652f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath))
1662f3563ccSZbigniew Lukwinski     {
1672f3563ccSZbigniew Lukwinski         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
168db029c95SKowalski, Kamil         installedCerts.emplace_back(std::make_unique<Certificate>(
1692f3563ccSZbigniew Lukwinski             bus, certObjectPath, certType, certInstallPath, filePath,
1702f3563ccSZbigniew Lukwinski             certWatchPtr, *this));
1712f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
1722f3563ccSZbigniew Lukwinski         certIdCounter++;
1732f3563ccSZbigniew Lukwinski     }
1742f3563ccSZbigniew Lukwinski     else
1752f3563ccSZbigniew Lukwinski     {
1762f3563ccSZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificate already exist"));
1772f3563ccSZbigniew Lukwinski     }
1782f3563ccSZbigniew Lukwinski 
17906a69d7bSZbigniew Kurzynski     return certObjectPath;
180589159f2SJayanth Othayoth }
181ae70b3daSDeepak Kodihalli 
182a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
183ae70b3daSDeepak Kodihalli {
1846ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
1856ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
1866ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
1876ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
1886ceec40bSMarri Devender Rao     // deletion of certificates
189db029c95SKowalski, Kamil     installedCerts.clear();
1902f3563ccSZbigniew Lukwinski     storageUpdate();
1912f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
192ae70b3daSDeepak Kodihalli }
193f4682712SMarri Devender Rao 
1942f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
195a3bb38fbSZbigniew Kurzynski {
196a3bb38fbSZbigniew Kurzynski     std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
197a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
1982f3563ccSZbigniew Lukwinski                      [certificate](std::unique_ptr<Certificate> const& cert) {
1992f3563ccSZbigniew Lukwinski                          return (cert.get() == certificate);
200a3bb38fbSZbigniew Kurzynski                      });
201a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
202a3bb38fbSZbigniew Kurzynski     {
203a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
2042f3563ccSZbigniew Lukwinski         storageUpdate();
2052f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
206a3bb38fbSZbigniew Kurzynski     }
207a3bb38fbSZbigniew Kurzynski     else
208a3bb38fbSZbigniew Kurzynski     {
209a3bb38fbSZbigniew Kurzynski         log<level::ERR>("Certificate does not exist",
2102f3563ccSZbigniew Lukwinski                         entry("ID=%s", certificate->getCertId().c_str()));
2112f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
2122f3563ccSZbigniew Lukwinski     }
2132f3563ccSZbigniew Lukwinski }
2142f3563ccSZbigniew Lukwinski 
2152f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
2162f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
2172f3563ccSZbigniew Lukwinski {
2182f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
2192f3563ccSZbigniew Lukwinski     {
2202f3563ccSZbigniew Lukwinski         certificate->install(filePath);
2212f3563ccSZbigniew Lukwinski         storageUpdate();
2222f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
2232f3563ccSZbigniew Lukwinski     }
2242f3563ccSZbigniew Lukwinski     else
2252f3563ccSZbigniew Lukwinski     {
22615cbbec2SZbigniew Lukwinski         using NotAllowed =
22715cbbec2SZbigniew Lukwinski             sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
22815cbbec2SZbigniew Lukwinski         using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
22915cbbec2SZbigniew Lukwinski 
23015cbbec2SZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificate already exist"));
231a3bb38fbSZbigniew Kurzynski     }
232a3bb38fbSZbigniew Kurzynski }
233a3bb38fbSZbigniew Kurzynski 
234f4682712SMarri Devender Rao std::string Manager::generateCSR(
235f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
236f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
237f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
238f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
239f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
240f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
241f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
242f4682712SMarri Devender Rao {
243f4682712SMarri Devender Rao     // We support only one CSR.
244f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
245f4682712SMarri Devender Rao     auto pid = fork();
246f4682712SMarri Devender Rao     if (pid == -1)
247f4682712SMarri Devender Rao     {
248f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
249f4682712SMarri Devender Rao         report<InternalFailure>();
250f4682712SMarri Devender Rao     }
251f4682712SMarri Devender Rao     else if (pid == 0)
252f4682712SMarri Devender Rao     {
253f4682712SMarri Devender Rao         try
254f4682712SMarri Devender Rao         {
255f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
256f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
257f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
258f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
259f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
260f4682712SMarri Devender Rao                               unstructuredName);
261f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
262f4682712SMarri Devender Rao         }
263f4682712SMarri Devender Rao         catch (const InternalFailure& e)
264f4682712SMarri Devender Rao         {
265f4682712SMarri Devender Rao             // commit the error reported in child process and exit
266f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
267f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
268f4682712SMarri Devender Rao             commit<InternalFailure>();
269f4682712SMarri Devender Rao         }
270d2393f23SRamesh Iyyar         catch (const InvalidArgument& e)
271d2393f23SRamesh Iyyar         {
272d2393f23SRamesh Iyyar             // commit the error reported in child process and exit
273d2393f23SRamesh Iyyar             // Callback method from SDEvent Loop looks for exit status
274d2393f23SRamesh Iyyar             exit(EXIT_FAILURE);
275d2393f23SRamesh Iyyar             commit<InvalidArgument>();
276d2393f23SRamesh Iyyar         }
277f4682712SMarri Devender Rao     }
278f4682712SMarri Devender Rao     else
279f4682712SMarri Devender Rao     {
280f4682712SMarri Devender Rao         using namespace sdeventplus::source;
281f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
282f4682712SMarri Devender Rao                                           const siginfo_t* si) {
283f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
284f4682712SMarri Devender Rao             if (si->si_status != 0)
285f4682712SMarri Devender Rao             {
286f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
287f4682712SMarri Devender Rao             }
288f4682712SMarri Devender Rao             else
289f4682712SMarri Devender Rao             {
290f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
291f4682712SMarri Devender Rao             }
292f4682712SMarri Devender Rao         };
293f4682712SMarri Devender Rao         try
294f4682712SMarri Devender Rao         {
295f4682712SMarri Devender Rao             sigset_t ss;
296f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
297f4682712SMarri Devender Rao             {
298f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
299f4682712SMarri Devender Rao                 elog<InternalFailure>();
300f4682712SMarri Devender Rao             }
301f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
302f4682712SMarri Devender Rao             {
303f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
304f4682712SMarri Devender Rao                 elog<InternalFailure>();
305f4682712SMarri Devender Rao             }
306f4682712SMarri Devender Rao 
307f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
308f4682712SMarri Devender Rao             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
309f4682712SMarri Devender Rao             {
310f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
311f4682712SMarri Devender Rao                 elog<InternalFailure>();
312f4682712SMarri Devender Rao             }
313f4682712SMarri Devender Rao             if (childPtr)
314f4682712SMarri Devender Rao             {
315f4682712SMarri Devender Rao                 childPtr.reset();
316f4682712SMarri Devender Rao             }
317f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
318f4682712SMarri Devender Rao                                                std::move(callback));
319f4682712SMarri Devender Rao         }
320f4682712SMarri Devender Rao         catch (const InternalFailure& e)
321f4682712SMarri Devender Rao         {
322f4682712SMarri Devender Rao             commit<InternalFailure>();
323f4682712SMarri Devender Rao         }
324f4682712SMarri Devender Rao     }
325f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
326f4682712SMarri Devender Rao     return csrObjectPath;
327f4682712SMarri Devender Rao }
328f4682712SMarri Devender Rao 
329db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
330ffad1ef1SMarri Devender Rao {
331db029c95SKowalski, Kamil     return installedCerts;
332ffad1ef1SMarri Devender Rao }
333ffad1ef1SMarri Devender Rao 
334f4682712SMarri Devender Rao void Manager::generateCSRHelper(
335f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
336f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
337f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
338f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
339f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
340f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
341f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
342f4682712SMarri Devender Rao {
343f4682712SMarri Devender Rao     int ret = 0;
344f4682712SMarri Devender Rao 
345f4682712SMarri Devender Rao     // set version of x509 req
346f4682712SMarri Devender Rao     int nVersion = 1;
347f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
348f4682712SMarri Devender Rao     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
349f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
350f4682712SMarri Devender Rao     if (ret == 0)
351f4682712SMarri Devender Rao     {
352f4682712SMarri Devender Rao         log<level::ERR>("Error occured during X509_REQ_set_version call");
353f4682712SMarri Devender Rao         elog<InternalFailure>();
354f4682712SMarri Devender Rao     }
355f4682712SMarri Devender Rao 
356f4682712SMarri Devender Rao     // set subject of x509 req
357f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
358f4682712SMarri Devender Rao 
359f4682712SMarri Devender Rao     if (!alternativeNames.empty())
360f4682712SMarri Devender Rao     {
361f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
362f4682712SMarri Devender Rao         {
363f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
364f4682712SMarri Devender Rao         }
365f4682712SMarri Devender Rao     }
366f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
367f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
368f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
369f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
370f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
371f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
372f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
373f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
374f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
375f4682712SMarri Devender Rao     if (!keyUsage.empty())
376f4682712SMarri Devender Rao     {
377f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
378f4682712SMarri Devender Rao         {
3797641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
3807641105dSMarri Devender Rao             {
3817641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
3827641105dSMarri Devender Rao             }
3837641105dSMarri Devender Rao             else
3847641105dSMarri Devender Rao             {
385f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
386f4682712SMarri Devender Rao             }
387f4682712SMarri Devender Rao         }
3887641105dSMarri Devender Rao     }
389f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
390dc91fb61SJayanth Othayoth     addEntry(x509Name, "OU", organizationalUnit);
391f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
392f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
393f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
394f4682712SMarri Devender Rao 
3958a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
3968a09b52aSRamesh Iyyar 
3978a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
3988a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
3998a09b52aSRamesh Iyyar 
4008a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
4018a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
402c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
4038a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
404c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
4058a09b52aSRamesh Iyyar     else
4068a09b52aSRamesh Iyyar     {
4078a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
4088a09b52aSRamesh Iyyar                         "RSA and EC only");
4098a09b52aSRamesh Iyyar         elog<InvalidArgument>(
4108a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
4118a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
4128a09b52aSRamesh Iyyar     }
4138a09b52aSRamesh Iyyar 
4148a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
4158a09b52aSRamesh Iyyar     if (ret == 0)
4168a09b52aSRamesh Iyyar     {
4178a09b52aSRamesh Iyyar         log<level::ERR>("Error occured while setting Public key");
4188a09b52aSRamesh Iyyar         elog<InternalFailure>();
4198a09b52aSRamesh Iyyar     }
4208a09b52aSRamesh Iyyar 
4218a09b52aSRamesh Iyyar     // Write private key to file
422c6e58c7eSRamesh Iyyar     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
423f4682712SMarri Devender Rao 
424f4682712SMarri Devender Rao     // set sign key of x509 req
425f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
4268a09b52aSRamesh Iyyar     if (ret == 0)
427f4682712SMarri Devender Rao     {
428f4682712SMarri Devender Rao         log<level::ERR>("Error occured while signing key of x509");
429f4682712SMarri Devender Rao         elog<InternalFailure>();
430f4682712SMarri Devender Rao     }
4318a09b52aSRamesh Iyyar 
432f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
433c6e58c7eSRamesh Iyyar     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
434c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
435f4682712SMarri Devender Rao }
436f4682712SMarri Devender Rao 
4377641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
4387641105dSMarri Devender Rao {
4397641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
4407641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
4417641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
4427641105dSMarri Devender Rao     auto it = std::find_if(
4437641105dSMarri Devender Rao         usageList.begin(), usageList.end(),
4447641105dSMarri Devender Rao         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
4457641105dSMarri Devender Rao     return it != usageList.end();
4467641105dSMarri Devender Rao }
4478a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
448f4682712SMarri Devender Rao {
449f4682712SMarri Devender Rao     int ret = 0;
450f4682712SMarri Devender Rao     // generate rsa key
451f4682712SMarri Devender Rao     BIGNUM_Ptr bne(BN_new(), ::BN_free);
452f4682712SMarri Devender Rao     ret = BN_set_word(bne.get(), RSA_F4);
453f4682712SMarri Devender Rao     if (ret == 0)
454f4682712SMarri Devender Rao     {
455f4682712SMarri Devender Rao         log<level::ERR>("Error occured during BN_set_word call");
456f4682712SMarri Devender Rao         elog<InternalFailure>();
457f4682712SMarri Devender Rao     }
458f4682712SMarri Devender Rao 
4598a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
460f4682712SMarri Devender Rao     // set keybit length to default value if not set
4618a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
462f4682712SMarri Devender Rao     {
4638a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
4648a09b52aSRamesh Iyyar         log<level::INFO>(
4658a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
4668a09b52aSRamesh Iyyar             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
4678a09b52aSRamesh Iyyar         keyBitLen = DEFAULT_KEYBITLENGTH;
468f4682712SMarri Devender Rao     }
469f4682712SMarri Devender Rao     RSA* rsa = RSA_new();
4708a09b52aSRamesh Iyyar     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
471f4682712SMarri Devender Rao     if (ret != 1)
472f4682712SMarri Devender Rao     {
473f4682712SMarri Devender Rao         free(rsa);
474f4682712SMarri Devender Rao         log<level::ERR>("Error occured during RSA_generate_key_ex call",
4758a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
476f4682712SMarri Devender Rao         elog<InternalFailure>();
477f4682712SMarri Devender Rao     }
478f4682712SMarri Devender Rao 
479f4682712SMarri Devender Rao     // set public key of x509 req
480f4682712SMarri Devender Rao     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
4818a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
482f4682712SMarri Devender Rao     if (ret == 0)
483f4682712SMarri Devender Rao     {
4848a09b52aSRamesh Iyyar         free(rsa);
4858a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign rsa key into EVP");
486f4682712SMarri Devender Rao         elog<InternalFailure>();
487f4682712SMarri Devender Rao     }
488f4682712SMarri Devender Rao 
4898a09b52aSRamesh Iyyar     return pKey;
4908a09b52aSRamesh Iyyar }
4918a09b52aSRamesh Iyyar 
4928a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
4938a09b52aSRamesh Iyyar {
4948a09b52aSRamesh Iyyar     std::string curId(curveId);
4958a09b52aSRamesh Iyyar 
4968a09b52aSRamesh Iyyar     if (curId.empty())
4978a09b52aSRamesh Iyyar     {
4988a09b52aSRamesh Iyyar         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
4998a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
5008a09b52aSRamesh Iyyar         log<level::INFO>(
5018a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
5028a09b52aSRamesh Iyyar             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
5038a09b52aSRamesh Iyyar         curId = DEFAULT_KEYCURVEID;
5048a09b52aSRamesh Iyyar     }
5058a09b52aSRamesh Iyyar 
5068a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
5078a09b52aSRamesh Iyyar 
5088a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
5098a09b52aSRamesh Iyyar     {
5108a09b52aSRamesh Iyyar         log<level::ERR>(
5118a09b52aSRamesh Iyyar             "Error occured during convert the curve id string format into NID",
5128a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
5138a09b52aSRamesh Iyyar         elog<InternalFailure>();
5148a09b52aSRamesh Iyyar     }
5158a09b52aSRamesh Iyyar 
5168a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
5178a09b52aSRamesh Iyyar 
5188a09b52aSRamesh Iyyar     if (ecKey == NULL)
5198a09b52aSRamesh Iyyar     {
5208a09b52aSRamesh Iyyar         log<level::ERR>(
5218a09b52aSRamesh Iyyar             "Error occured during create the EC_Key object from NID",
5228a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
5238a09b52aSRamesh Iyyar         elog<InternalFailure>();
5248a09b52aSRamesh Iyyar     }
5258a09b52aSRamesh Iyyar 
5268a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
5278a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
5288a09b52aSRamesh Iyyar     // flag on the key.
5298a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
5308a09b52aSRamesh Iyyar 
5318a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
5328a09b52aSRamesh Iyyar 
5338a09b52aSRamesh Iyyar     if (ret == 0)
5348a09b52aSRamesh Iyyar     {
5358a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5368a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during generate EC key");
5378a09b52aSRamesh Iyyar         elog<InternalFailure>();
5388a09b52aSRamesh Iyyar     }
5398a09b52aSRamesh Iyyar 
5408a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
5418a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
5428a09b52aSRamesh Iyyar     if (ret == 0)
5438a09b52aSRamesh Iyyar     {
5448a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5458a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign EC Key into EVP");
5468a09b52aSRamesh Iyyar         elog<InternalFailure>();
5478a09b52aSRamesh Iyyar     }
5488a09b52aSRamesh Iyyar 
5498a09b52aSRamesh Iyyar     return pKey;
5508a09b52aSRamesh Iyyar }
5518a09b52aSRamesh Iyyar 
552c6e58c7eSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
553c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
5548a09b52aSRamesh Iyyar {
5558a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
556f4682712SMarri Devender Rao     // write private key to file
557c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
558f4682712SMarri Devender Rao 
559f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
560f4682712SMarri Devender Rao     if (fp == NULL)
561f4682712SMarri Devender Rao     {
562f4682712SMarri Devender Rao         log<level::ERR>("Error occured creating private key file");
563f4682712SMarri Devender Rao         elog<InternalFailure>();
564f4682712SMarri Devender Rao     }
5658a09b52aSRamesh Iyyar     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
566f4682712SMarri Devender Rao     std::fclose(fp);
567f4682712SMarri Devender Rao     if (ret == 0)
568f4682712SMarri Devender Rao     {
569f4682712SMarri Devender Rao         log<level::ERR>("Error occured while writing private key to file");
570f4682712SMarri Devender Rao         elog<InternalFailure>();
571f4682712SMarri Devender Rao     }
572f4682712SMarri Devender Rao }
573f4682712SMarri Devender Rao 
574f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
575f4682712SMarri Devender Rao                        const std::string& bytes)
576f4682712SMarri Devender Rao {
577f4682712SMarri Devender Rao     if (bytes.empty())
578f4682712SMarri Devender Rao     {
579f4682712SMarri Devender Rao         return;
580f4682712SMarri Devender Rao     }
581f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
582f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
583f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
584f4682712SMarri Devender Rao     if (ret != 1)
585f4682712SMarri Devender Rao     {
586f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
587f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
588f4682712SMarri Devender Rao         elog<InternalFailure>();
589f4682712SMarri Devender Rao     }
590f4682712SMarri Devender Rao }
591f4682712SMarri Devender Rao 
592f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
593f4682712SMarri Devender Rao {
594f4682712SMarri Devender Rao     if (csrPtr)
595f4682712SMarri Devender Rao     {
596f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
597f4682712SMarri Devender Rao     }
598f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
599f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
600f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
601f4682712SMarri Devender Rao }
602f4682712SMarri Devender Rao 
603f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
604f4682712SMarri Devender Rao {
605f4682712SMarri Devender Rao     if (fs::exists(filePath))
606f4682712SMarri Devender Rao     {
607f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
608f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
609f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
610f4682712SMarri Devender Rao         {
611f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
612f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
613f4682712SMarri Devender Rao             elog<InternalFailure>();
614f4682712SMarri Devender Rao         }
615f4682712SMarri Devender Rao     }
616f4682712SMarri Devender Rao 
617f4682712SMarri Devender Rao     FILE* fp = NULL;
618f4682712SMarri Devender Rao 
619f4682712SMarri Devender Rao     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
620f4682712SMarri Devender Rao     {
621f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
622f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
623f4682712SMarri Devender Rao         elog<InternalFailure>();
624f4682712SMarri Devender Rao     }
625f4682712SMarri Devender Rao 
626f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
627f4682712SMarri Devender Rao     if (!rc)
628f4682712SMarri Devender Rao     {
629f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
630f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
631f4682712SMarri Devender Rao         std::fclose(fp);
632f4682712SMarri Devender Rao         elog<InternalFailure>();
633f4682712SMarri Devender Rao     }
634f4682712SMarri Devender Rao     std::fclose(fp);
635f4682712SMarri Devender Rao }
636f4682712SMarri Devender Rao 
637db029c95SKowalski, Kamil void Manager::createCertificates()
638db029c95SKowalski, Kamil {
639db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
640db029c95SKowalski, Kamil 
641db029c95SKowalski, Kamil     if (certType == phosphor::certs::AUTHORITY)
642db029c95SKowalski, Kamil     {
643fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
644db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
645db029c95SKowalski, Kamil         {
646db029c95SKowalski, Kamil             log<level::ERR>("Certificate installation path exists and it is "
647db029c95SKowalski, Kamil                             "not a directory");
648db029c95SKowalski, Kamil             elog<InternalFailure>();
649db029c95SKowalski, Kamil             return;
650db029c95SKowalski, Kamil         }
651db029c95SKowalski, Kamil 
652db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
653ffad1ef1SMarri Devender Rao         {
654ffad1ef1SMarri Devender Rao             try
655ffad1ef1SMarri Devender Rao             {
6562f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
6572f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
6582f3563ccSZbigniew Lukwinski                 // would add value.
6592f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
6602f3563ccSZbigniew Lukwinski                 {
661db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
662db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
6632f3563ccSZbigniew Lukwinski                         certType, certInstallPath, path.path(), certWatchPtr,
6642f3563ccSZbigniew Lukwinski                         *this));
6652f3563ccSZbigniew Lukwinski                 }
666ffad1ef1SMarri Devender Rao             }
667ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
668ffad1ef1SMarri Devender Rao             {
669ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
670ffad1ef1SMarri Devender Rao             }
671ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
672ffad1ef1SMarri Devender Rao             {
673ffad1ef1SMarri Devender Rao                 report<InvalidCertificate>(
674ffad1ef1SMarri Devender Rao                     Reason("Existing certificate file is corrupted"));
675ffad1ef1SMarri Devender Rao             }
676ffad1ef1SMarri Devender Rao         }
677db029c95SKowalski, Kamil     }
678db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
679db029c95SKowalski, Kamil     {
680db029c95SKowalski, Kamil         try
681db029c95SKowalski, Kamil         {
682db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
6832f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
6842f3563ccSZbigniew Lukwinski                 certInstallPath, certWatchPtr, *this));
685db029c95SKowalski, Kamil         }
686db029c95SKowalski, Kamil         catch (const InternalFailure& e)
687db029c95SKowalski, Kamil         {
688db029c95SKowalski, Kamil             report<InternalFailure>();
689db029c95SKowalski, Kamil         }
690db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
691db029c95SKowalski, Kamil         {
692db029c95SKowalski, Kamil             report<InvalidCertificate>(
693db029c95SKowalski, Kamil                 Reason("Existing certificate file is corrupted"));
694db029c95SKowalski, Kamil         }
695db029c95SKowalski, Kamil     }
696db029c95SKowalski, Kamil }
697c6e58c7eSRamesh Iyyar 
698c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
699c6e58c7eSRamesh Iyyar {
700c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
701c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
702c6e58c7eSRamesh Iyyar 
703c6e58c7eSRamesh Iyyar     try
704c6e58c7eSRamesh Iyyar     {
705c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
706c6e58c7eSRamesh Iyyar         {
707c6e58c7eSRamesh Iyyar             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
708c6e58c7eSRamesh Iyyar                             RSA_PRIV_KEY_FILE_NAME);
709c6e58c7eSRamesh Iyyar         }
710c6e58c7eSRamesh Iyyar     }
711c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
712c6e58c7eSRamesh Iyyar     {
713c6e58c7eSRamesh Iyyar         report<InternalFailure>();
714c6e58c7eSRamesh Iyyar     }
715c6e58c7eSRamesh Iyyar }
716c6e58c7eSRamesh Iyyar 
717c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
718c6e58c7eSRamesh Iyyar {
719c6e58c7eSRamesh Iyyar     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
720c6e58c7eSRamesh Iyyar     {
721c6e58c7eSRamesh Iyyar         log<level::ERR>(
722c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
723c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
724c6e58c7eSRamesh Iyyar             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
725c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
726c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
727c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
728c6e58c7eSRamesh Iyyar     }
729c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
730c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
731c6e58c7eSRamesh Iyyar 
732c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
733c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
734c6e58c7eSRamesh Iyyar     {
735c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
736c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
737c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
738c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
739c6e58c7eSRamesh Iyyar     }
740c6e58c7eSRamesh Iyyar 
741c6e58c7eSRamesh Iyyar     EVP_PKEY_Ptr privateKey(
742c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
743c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
744c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
745c6e58c7eSRamesh Iyyar 
746c6e58c7eSRamesh Iyyar     if (!privateKey)
747c6e58c7eSRamesh Iyyar     {
748c6e58c7eSRamesh Iyyar         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
749c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
750c6e58c7eSRamesh Iyyar     }
751c6e58c7eSRamesh Iyyar     return privateKey;
752c6e58c7eSRamesh Iyyar }
7532f3563ccSZbigniew Lukwinski 
7542f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
7552f3563ccSZbigniew Lukwinski {
7562f3563ccSZbigniew Lukwinski     if (certType == phosphor::certs::AUTHORITY)
7572f3563ccSZbigniew Lukwinski     {
7582f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
7592f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
7602f3563ccSZbigniew Lukwinski         {
7612f3563ccSZbigniew Lukwinski             try
7622f3563ccSZbigniew Lukwinski             {
7632f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
7642f3563ccSZbigniew Lukwinski                 {
7652f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
7662f3563ccSZbigniew Lukwinski                 }
7672f3563ccSZbigniew Lukwinski             }
7682f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
7692f3563ccSZbigniew Lukwinski             {
7702f3563ccSZbigniew Lukwinski                 log<level::ERR>(
7712f3563ccSZbigniew Lukwinski                     "Failed to remove symlink for certificate",
7722f3563ccSZbigniew Lukwinski                     entry("ERR=%s", e.what()),
7732f3563ccSZbigniew Lukwinski                     entry("SYMLINK=%s", certPath.path().string().c_str()));
7742f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
7752f3563ccSZbigniew Lukwinski             }
7762f3563ccSZbigniew Lukwinski         }
7772f3563ccSZbigniew Lukwinski     }
7782f3563ccSZbigniew Lukwinski 
7792f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
7802f3563ccSZbigniew Lukwinski     {
7812f3563ccSZbigniew Lukwinski         cert->storageUpdate();
7822f3563ccSZbigniew Lukwinski     }
7832f3563ccSZbigniew Lukwinski }
7842f3563ccSZbigniew Lukwinski 
7852f3563ccSZbigniew Lukwinski void Manager::reloadOrReset(const UnitsToRestart& unit)
7862f3563ccSZbigniew Lukwinski {
7872f3563ccSZbigniew Lukwinski     if (!unit.empty())
7882f3563ccSZbigniew Lukwinski     {
7892f3563ccSZbigniew Lukwinski         try
7902f3563ccSZbigniew Lukwinski         {
7912f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
7922f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
7932f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_INTERFACE =
7942f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
7952f3563ccSZbigniew Lukwinski 
7962f3563ccSZbigniew Lukwinski             auto method =
7972f3563ccSZbigniew Lukwinski                 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
7982f3563ccSZbigniew Lukwinski                                     SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
7992f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
8002f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
8012f3563ccSZbigniew Lukwinski         }
802ca128117SPatrick Williams         catch (const sdbusplus::exception::exception& e)
8032f3563ccSZbigniew Lukwinski         {
8042f3563ccSZbigniew Lukwinski             log<level::ERR>("Failed to reload or restart service",
8052f3563ccSZbigniew Lukwinski                             entry("ERR=%s", e.what()),
8062f3563ccSZbigniew Lukwinski                             entry("UNIT=%s", unit.c_str()));
8072f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
8082f3563ccSZbigniew Lukwinski         }
8092f3563ccSZbigniew Lukwinski     }
8102f3563ccSZbigniew Lukwinski }
8112f3563ccSZbigniew Lukwinski 
8122f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
8132f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
8142f3563ccSZbigniew Lukwinski {
8152f3563ccSZbigniew Lukwinski     if (std::any_of(
8162f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
8172f3563ccSZbigniew Lukwinski             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
8182f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
8192f3563ccSZbigniew Lukwinski             }))
8202f3563ccSZbigniew Lukwinski     {
8212f3563ccSZbigniew Lukwinski         return false;
8222f3563ccSZbigniew Lukwinski     }
8232f3563ccSZbigniew Lukwinski     else
8242f3563ccSZbigniew Lukwinski     {
8252f3563ccSZbigniew Lukwinski         return true;
8262f3563ccSZbigniew Lukwinski     }
8272f3563ccSZbigniew Lukwinski }
8282f3563ccSZbigniew Lukwinski 
829cfbc8dc8SJayanth Othayoth } // namespace certs
830cfbc8dc8SJayanth Othayoth } // namespace phosphor
831