xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision db5c6fc872e3337cdd5a229811ce3f787a900bcc)
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 {
37*db5c6fc8SMarri Devender Rao     try
38*db5c6fc8SMarri 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;
60*db5c6fc8SMarri Devender Rao             fs::permissions(certDirectory, permission,
61*db5c6fc8SMarri Devender Rao                             fs::perm_options::replace);
622f3563ccSZbigniew Lukwinski             storageUpdate();
63b57d75e2SMarri Devender Rao         }
64b57d75e2SMarri Devender Rao         catch (fs::filesystem_error& e)
65b57d75e2SMarri Devender Rao         {
66*db5c6fc8SMarri Devender Rao             log<level::ERR>(
67*db5c6fc8SMarri 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                     {
92*db5c6fc8SMarri Devender Rao                         log<level::INFO>("Inotify callback to update "
93*db5c6fc8SMarri 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         {
115*db5c6fc8SMarri Devender Rao             try
116*db5c6fc8SMarri Devender Rao             {
117*db5c6fc8SMarri Devender Rao                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
118*db5c6fc8SMarri 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: ",
122*db5c6fc8SMarri Devender Rao                         entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
123*db5c6fc8SMarri Devender Rao                     install(singleCertPath);
124*db5c6fc8SMarri Devender Rao                     if (!fs::remove(singleCertPath))
125db029c95SKowalski, Kamil                     {
126db029c95SKowalski, Kamil                         log<level::ERR>(
127db029c95SKowalski, Kamil                             "Unable to remove old certificate from: ",
128*db5c6fc8SMarri Devender Rao                             entry("SINGLE_CERTPATH=%s",
129*db5c6fc8SMarri Devender Rao                                   singleCertPath.c_str()));
130db029c95SKowalski, Kamil                         elog<InternalFailure>();
131db029c95SKowalski, Kamil                     }
132db029c95SKowalski, Kamil                 }
133db029c95SKowalski, Kamil             }
134*db5c6fc8SMarri Devender Rao             catch (const std::exception& ex)
135*db5c6fc8SMarri Devender Rao             {
136*db5c6fc8SMarri Devender Rao                 log<level::ERR>("Error in restoring legacy certificate",
137*db5c6fc8SMarri Devender Rao                                 entry("ERROR_STR=%s", ex.what()));
138*db5c6fc8SMarri Devender Rao             }
139*db5c6fc8SMarri Devender Rao         }
140*db5c6fc8SMarri Devender Rao     }
141*db5c6fc8SMarri Devender Rao     catch (std::exception& ex)
142*db5c6fc8SMarri Devender Rao     {
143*db5c6fc8SMarri Devender Rao         log<level::ERR>("Error in certificate manager constructor",
144*db5c6fc8SMarri Devender Rao                         entry("ERROR_STR=%s", ex.what()));
145*db5c6fc8SMarri 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         }
270f4682712SMarri Devender Rao     }
271f4682712SMarri Devender Rao     else
272f4682712SMarri Devender Rao     {
273f4682712SMarri Devender Rao         using namespace sdeventplus::source;
274f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
275f4682712SMarri Devender Rao                                           const siginfo_t* si) {
276f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
277f4682712SMarri Devender Rao             if (si->si_status != 0)
278f4682712SMarri Devender Rao             {
279f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
280f4682712SMarri Devender Rao             }
281f4682712SMarri Devender Rao             else
282f4682712SMarri Devender Rao             {
283f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
284f4682712SMarri Devender Rao             }
285f4682712SMarri Devender Rao         };
286f4682712SMarri Devender Rao         try
287f4682712SMarri Devender Rao         {
288f4682712SMarri Devender Rao             sigset_t ss;
289f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
290f4682712SMarri Devender Rao             {
291f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
292f4682712SMarri Devender Rao                 elog<InternalFailure>();
293f4682712SMarri Devender Rao             }
294f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
295f4682712SMarri Devender Rao             {
296f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
297f4682712SMarri Devender Rao                 elog<InternalFailure>();
298f4682712SMarri Devender Rao             }
299f4682712SMarri Devender Rao 
300f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
301f4682712SMarri Devender Rao             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
302f4682712SMarri Devender Rao             {
303f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
304f4682712SMarri Devender Rao                 elog<InternalFailure>();
305f4682712SMarri Devender Rao             }
306f4682712SMarri Devender Rao             if (childPtr)
307f4682712SMarri Devender Rao             {
308f4682712SMarri Devender Rao                 childPtr.reset();
309f4682712SMarri Devender Rao             }
310f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
311f4682712SMarri Devender Rao                                                std::move(callback));
312f4682712SMarri Devender Rao         }
313f4682712SMarri Devender Rao         catch (const InternalFailure& e)
314f4682712SMarri Devender Rao         {
315f4682712SMarri Devender Rao             commit<InternalFailure>();
316f4682712SMarri Devender Rao         }
317f4682712SMarri Devender Rao     }
318f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
319f4682712SMarri Devender Rao     return csrObjectPath;
320f4682712SMarri Devender Rao }
321f4682712SMarri Devender Rao 
322db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
323ffad1ef1SMarri Devender Rao {
324db029c95SKowalski, Kamil     return installedCerts;
325ffad1ef1SMarri Devender Rao }
326ffad1ef1SMarri Devender Rao 
327f4682712SMarri Devender Rao void Manager::generateCSRHelper(
328f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
329f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
330f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
331f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
332f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
333f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
334f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
335f4682712SMarri Devender Rao {
336f4682712SMarri Devender Rao     int ret = 0;
337f4682712SMarri Devender Rao 
338f4682712SMarri Devender Rao     // set version of x509 req
339f4682712SMarri Devender Rao     int nVersion = 1;
340f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
341f4682712SMarri Devender Rao     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
342f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
343f4682712SMarri Devender Rao     if (ret == 0)
344f4682712SMarri Devender Rao     {
345f4682712SMarri Devender Rao         log<level::ERR>("Error occured during X509_REQ_set_version call");
346f4682712SMarri Devender Rao         elog<InternalFailure>();
347f4682712SMarri Devender Rao     }
348f4682712SMarri Devender Rao 
349f4682712SMarri Devender Rao     // set subject of x509 req
350f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
351f4682712SMarri Devender Rao 
352f4682712SMarri Devender Rao     if (!alternativeNames.empty())
353f4682712SMarri Devender Rao     {
354f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
355f4682712SMarri Devender Rao         {
356f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
357f4682712SMarri Devender Rao         }
358f4682712SMarri Devender Rao     }
359f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
360f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
361f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
362f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
363f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
364f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
365f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
366f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
367f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
368f4682712SMarri Devender Rao     if (!keyUsage.empty())
369f4682712SMarri Devender Rao     {
370f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
371f4682712SMarri Devender Rao         {
3727641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
3737641105dSMarri Devender Rao             {
3747641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
3757641105dSMarri Devender Rao             }
3767641105dSMarri Devender Rao             else
3777641105dSMarri Devender Rao             {
378f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
379f4682712SMarri Devender Rao             }
380f4682712SMarri Devender Rao         }
3817641105dSMarri Devender Rao     }
382f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
383f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
384f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
385f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
386f4682712SMarri Devender Rao 
3878a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
3888a09b52aSRamesh Iyyar 
3898a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
3908a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
3918a09b52aSRamesh Iyyar 
3928a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
3938a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
394c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
3958a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
396c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
3978a09b52aSRamesh Iyyar     else
3988a09b52aSRamesh Iyyar     {
3998a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
4008a09b52aSRamesh Iyyar                         "RSA and EC only");
4018a09b52aSRamesh Iyyar         elog<InvalidArgument>(
4028a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
4038a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
4048a09b52aSRamesh Iyyar     }
4058a09b52aSRamesh Iyyar 
4068a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
4078a09b52aSRamesh Iyyar     if (ret == 0)
4088a09b52aSRamesh Iyyar     {
4098a09b52aSRamesh Iyyar         log<level::ERR>("Error occured while setting Public key");
4108a09b52aSRamesh Iyyar         elog<InternalFailure>();
4118a09b52aSRamesh Iyyar     }
4128a09b52aSRamesh Iyyar 
4138a09b52aSRamesh Iyyar     // Write private key to file
414c6e58c7eSRamesh Iyyar     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
415f4682712SMarri Devender Rao 
416f4682712SMarri Devender Rao     // set sign key of x509 req
417f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
4188a09b52aSRamesh Iyyar     if (ret == 0)
419f4682712SMarri Devender Rao     {
420f4682712SMarri Devender Rao         log<level::ERR>("Error occured while signing key of x509");
421f4682712SMarri Devender Rao         elog<InternalFailure>();
422f4682712SMarri Devender Rao     }
4238a09b52aSRamesh Iyyar 
424f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
425c6e58c7eSRamesh Iyyar     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
426c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
427f4682712SMarri Devender Rao }
428f4682712SMarri Devender Rao 
4297641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
4307641105dSMarri Devender Rao {
4317641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
4327641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
4337641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
4347641105dSMarri Devender Rao     auto it = std::find_if(
4357641105dSMarri Devender Rao         usageList.begin(), usageList.end(),
4367641105dSMarri Devender Rao         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
4377641105dSMarri Devender Rao     return it != usageList.end();
4387641105dSMarri Devender Rao }
4398a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
440f4682712SMarri Devender Rao {
441f4682712SMarri Devender Rao     int ret = 0;
442f4682712SMarri Devender Rao     // generate rsa key
443f4682712SMarri Devender Rao     BIGNUM_Ptr bne(BN_new(), ::BN_free);
444f4682712SMarri Devender Rao     ret = BN_set_word(bne.get(), RSA_F4);
445f4682712SMarri Devender Rao     if (ret == 0)
446f4682712SMarri Devender Rao     {
447f4682712SMarri Devender Rao         log<level::ERR>("Error occured during BN_set_word call");
448f4682712SMarri Devender Rao         elog<InternalFailure>();
449f4682712SMarri Devender Rao     }
450f4682712SMarri Devender Rao 
4518a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
452f4682712SMarri Devender Rao     // set keybit length to default value if not set
4538a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
454f4682712SMarri Devender Rao     {
4558a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
4568a09b52aSRamesh Iyyar         log<level::INFO>(
4578a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
4588a09b52aSRamesh Iyyar             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
4598a09b52aSRamesh Iyyar         keyBitLen = DEFAULT_KEYBITLENGTH;
460f4682712SMarri Devender Rao     }
461f4682712SMarri Devender Rao     RSA* rsa = RSA_new();
4628a09b52aSRamesh Iyyar     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
463f4682712SMarri Devender Rao     if (ret != 1)
464f4682712SMarri Devender Rao     {
465f4682712SMarri Devender Rao         free(rsa);
466f4682712SMarri Devender Rao         log<level::ERR>("Error occured during RSA_generate_key_ex call",
4678a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
468f4682712SMarri Devender Rao         elog<InternalFailure>();
469f4682712SMarri Devender Rao     }
470f4682712SMarri Devender Rao 
471f4682712SMarri Devender Rao     // set public key of x509 req
472f4682712SMarri Devender Rao     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
4738a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
474f4682712SMarri Devender Rao     if (ret == 0)
475f4682712SMarri Devender Rao     {
4768a09b52aSRamesh Iyyar         free(rsa);
4778a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign rsa key into EVP");
478f4682712SMarri Devender Rao         elog<InternalFailure>();
479f4682712SMarri Devender Rao     }
480f4682712SMarri Devender Rao 
4818a09b52aSRamesh Iyyar     return pKey;
4828a09b52aSRamesh Iyyar }
4838a09b52aSRamesh Iyyar 
4848a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
4858a09b52aSRamesh Iyyar {
4868a09b52aSRamesh Iyyar     std::string curId(curveId);
4878a09b52aSRamesh Iyyar 
4888a09b52aSRamesh Iyyar     if (curId.empty())
4898a09b52aSRamesh Iyyar     {
4908a09b52aSRamesh Iyyar         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
4918a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
4928a09b52aSRamesh Iyyar         log<level::INFO>(
4938a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
4948a09b52aSRamesh Iyyar             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
4958a09b52aSRamesh Iyyar         curId = DEFAULT_KEYCURVEID;
4968a09b52aSRamesh Iyyar     }
4978a09b52aSRamesh Iyyar 
4988a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
4998a09b52aSRamesh Iyyar 
5008a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
5018a09b52aSRamesh Iyyar     {
5028a09b52aSRamesh Iyyar         log<level::ERR>(
5038a09b52aSRamesh Iyyar             "Error occured during convert the curve id string format into NID",
5048a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
5058a09b52aSRamesh Iyyar         elog<InternalFailure>();
5068a09b52aSRamesh Iyyar     }
5078a09b52aSRamesh Iyyar 
5088a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
5098a09b52aSRamesh Iyyar 
5108a09b52aSRamesh Iyyar     if (ecKey == NULL)
5118a09b52aSRamesh Iyyar     {
5128a09b52aSRamesh Iyyar         log<level::ERR>(
5138a09b52aSRamesh Iyyar             "Error occured during create the EC_Key object from NID",
5148a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
5158a09b52aSRamesh Iyyar         elog<InternalFailure>();
5168a09b52aSRamesh Iyyar     }
5178a09b52aSRamesh Iyyar 
5188a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
5198a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
5208a09b52aSRamesh Iyyar     // flag on the key.
5218a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
5228a09b52aSRamesh Iyyar 
5238a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
5248a09b52aSRamesh Iyyar 
5258a09b52aSRamesh Iyyar     if (ret == 0)
5268a09b52aSRamesh Iyyar     {
5278a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5288a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during generate EC key");
5298a09b52aSRamesh Iyyar         elog<InternalFailure>();
5308a09b52aSRamesh Iyyar     }
5318a09b52aSRamesh Iyyar 
5328a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
5338a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
5348a09b52aSRamesh Iyyar     if (ret == 0)
5358a09b52aSRamesh Iyyar     {
5368a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5378a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign EC Key into EVP");
5388a09b52aSRamesh Iyyar         elog<InternalFailure>();
5398a09b52aSRamesh Iyyar     }
5408a09b52aSRamesh Iyyar 
5418a09b52aSRamesh Iyyar     return pKey;
5428a09b52aSRamesh Iyyar }
5438a09b52aSRamesh Iyyar 
544c6e58c7eSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
545c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
5468a09b52aSRamesh Iyyar {
5478a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
548f4682712SMarri Devender Rao     // write private key to file
549c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
550f4682712SMarri Devender Rao 
551f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
552f4682712SMarri Devender Rao     if (fp == NULL)
553f4682712SMarri Devender Rao     {
554f4682712SMarri Devender Rao         log<level::ERR>("Error occured creating private key file");
555f4682712SMarri Devender Rao         elog<InternalFailure>();
556f4682712SMarri Devender Rao     }
5578a09b52aSRamesh Iyyar     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
558f4682712SMarri Devender Rao     std::fclose(fp);
559f4682712SMarri Devender Rao     if (ret == 0)
560f4682712SMarri Devender Rao     {
561f4682712SMarri Devender Rao         log<level::ERR>("Error occured while writing private key to file");
562f4682712SMarri Devender Rao         elog<InternalFailure>();
563f4682712SMarri Devender Rao     }
564f4682712SMarri Devender Rao }
565f4682712SMarri Devender Rao 
566f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
567f4682712SMarri Devender Rao                        const std::string& bytes)
568f4682712SMarri Devender Rao {
569f4682712SMarri Devender Rao     if (bytes.empty())
570f4682712SMarri Devender Rao     {
571f4682712SMarri Devender Rao         return;
572f4682712SMarri Devender Rao     }
573f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
574f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
575f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
576f4682712SMarri Devender Rao     if (ret != 1)
577f4682712SMarri Devender Rao     {
578f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
579f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
580f4682712SMarri Devender Rao         elog<InternalFailure>();
581f4682712SMarri Devender Rao     }
582f4682712SMarri Devender Rao }
583f4682712SMarri Devender Rao 
584f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
585f4682712SMarri Devender Rao {
586f4682712SMarri Devender Rao     if (csrPtr)
587f4682712SMarri Devender Rao     {
588f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
589f4682712SMarri Devender Rao     }
590f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
591f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
592f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
593f4682712SMarri Devender Rao }
594f4682712SMarri Devender Rao 
595f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
596f4682712SMarri Devender Rao {
597f4682712SMarri Devender Rao     if (fs::exists(filePath))
598f4682712SMarri Devender Rao     {
599f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
600f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
601f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
602f4682712SMarri Devender Rao         {
603f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
604f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
605f4682712SMarri Devender Rao             elog<InternalFailure>();
606f4682712SMarri Devender Rao         }
607f4682712SMarri Devender Rao     }
608f4682712SMarri Devender Rao 
609f4682712SMarri Devender Rao     FILE* fp = NULL;
610f4682712SMarri Devender Rao 
611f4682712SMarri Devender Rao     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
612f4682712SMarri Devender Rao     {
613f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
614f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
615f4682712SMarri Devender Rao         elog<InternalFailure>();
616f4682712SMarri Devender Rao     }
617f4682712SMarri Devender Rao 
618f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
619f4682712SMarri Devender Rao     if (!rc)
620f4682712SMarri Devender Rao     {
621f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
622f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
623f4682712SMarri Devender Rao         std::fclose(fp);
624f4682712SMarri Devender Rao         elog<InternalFailure>();
625f4682712SMarri Devender Rao     }
626f4682712SMarri Devender Rao     std::fclose(fp);
627f4682712SMarri Devender Rao }
628f4682712SMarri Devender Rao 
629db029c95SKowalski, Kamil void Manager::createCertificates()
630db029c95SKowalski, Kamil {
631db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
632db029c95SKowalski, Kamil 
633db029c95SKowalski, Kamil     if (certType == phosphor::certs::AUTHORITY)
634db029c95SKowalski, Kamil     {
635fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
636db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
637db029c95SKowalski, Kamil         {
638db029c95SKowalski, Kamil             log<level::ERR>("Certificate installation path exists and it is "
639db029c95SKowalski, Kamil                             "not a directory");
640db029c95SKowalski, Kamil             elog<InternalFailure>();
641db029c95SKowalski, Kamil             return;
642db029c95SKowalski, Kamil         }
643db029c95SKowalski, Kamil 
644db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
645ffad1ef1SMarri Devender Rao         {
646ffad1ef1SMarri Devender Rao             try
647ffad1ef1SMarri Devender Rao             {
6482f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
6492f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
6502f3563ccSZbigniew Lukwinski                 // would add value.
6512f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
6522f3563ccSZbigniew Lukwinski                 {
653db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
654db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
6552f3563ccSZbigniew Lukwinski                         certType, certInstallPath, path.path(), certWatchPtr,
6562f3563ccSZbigniew Lukwinski                         *this));
6572f3563ccSZbigniew Lukwinski                 }
658ffad1ef1SMarri Devender Rao             }
659ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
660ffad1ef1SMarri Devender Rao             {
661ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
662ffad1ef1SMarri Devender Rao             }
663ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
664ffad1ef1SMarri Devender Rao             {
665ffad1ef1SMarri Devender Rao                 report<InvalidCertificate>(
666ffad1ef1SMarri Devender Rao                     Reason("Existing certificate file is corrupted"));
667ffad1ef1SMarri Devender Rao             }
668ffad1ef1SMarri Devender Rao         }
669db029c95SKowalski, Kamil     }
670db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
671db029c95SKowalski, Kamil     {
672db029c95SKowalski, Kamil         try
673db029c95SKowalski, Kamil         {
674db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
6752f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
6762f3563ccSZbigniew Lukwinski                 certInstallPath, certWatchPtr, *this));
677db029c95SKowalski, Kamil         }
678db029c95SKowalski, Kamil         catch (const InternalFailure& e)
679db029c95SKowalski, Kamil         {
680db029c95SKowalski, Kamil             report<InternalFailure>();
681db029c95SKowalski, Kamil         }
682db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
683db029c95SKowalski, Kamil         {
684db029c95SKowalski, Kamil             report<InvalidCertificate>(
685db029c95SKowalski, Kamil                 Reason("Existing certificate file is corrupted"));
686db029c95SKowalski, Kamil         }
687db029c95SKowalski, Kamil     }
688db029c95SKowalski, Kamil }
689c6e58c7eSRamesh Iyyar 
690c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
691c6e58c7eSRamesh Iyyar {
692c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
693c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
694c6e58c7eSRamesh Iyyar 
695c6e58c7eSRamesh Iyyar     try
696c6e58c7eSRamesh Iyyar     {
697c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
698c6e58c7eSRamesh Iyyar         {
699c6e58c7eSRamesh Iyyar             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
700c6e58c7eSRamesh Iyyar                             RSA_PRIV_KEY_FILE_NAME);
701c6e58c7eSRamesh Iyyar         }
702c6e58c7eSRamesh Iyyar     }
703c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
704c6e58c7eSRamesh Iyyar     {
705c6e58c7eSRamesh Iyyar         report<InternalFailure>();
706c6e58c7eSRamesh Iyyar     }
707c6e58c7eSRamesh Iyyar }
708c6e58c7eSRamesh Iyyar 
709c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
710c6e58c7eSRamesh Iyyar {
711c6e58c7eSRamesh Iyyar     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
712c6e58c7eSRamesh Iyyar     {
713c6e58c7eSRamesh Iyyar         log<level::ERR>(
714c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
715c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
716c6e58c7eSRamesh Iyyar             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
717c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
718c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
719c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
720c6e58c7eSRamesh Iyyar     }
721c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
722c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
723c6e58c7eSRamesh Iyyar 
724c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
725c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
726c6e58c7eSRamesh Iyyar     {
727c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
728c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
729c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
730c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
731c6e58c7eSRamesh Iyyar     }
732c6e58c7eSRamesh Iyyar 
733c6e58c7eSRamesh Iyyar     EVP_PKEY_Ptr privateKey(
734c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
735c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
736c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
737c6e58c7eSRamesh Iyyar 
738c6e58c7eSRamesh Iyyar     if (!privateKey)
739c6e58c7eSRamesh Iyyar     {
740c6e58c7eSRamesh Iyyar         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
741c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
742c6e58c7eSRamesh Iyyar     }
743c6e58c7eSRamesh Iyyar     return privateKey;
744c6e58c7eSRamesh Iyyar }
7452f3563ccSZbigniew Lukwinski 
7462f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
7472f3563ccSZbigniew Lukwinski {
7482f3563ccSZbigniew Lukwinski     if (certType == phosphor::certs::AUTHORITY)
7492f3563ccSZbigniew Lukwinski     {
7502f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
7512f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
7522f3563ccSZbigniew Lukwinski         {
7532f3563ccSZbigniew Lukwinski             try
7542f3563ccSZbigniew Lukwinski             {
7552f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
7562f3563ccSZbigniew Lukwinski                 {
7572f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
7582f3563ccSZbigniew Lukwinski                 }
7592f3563ccSZbigniew Lukwinski             }
7602f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
7612f3563ccSZbigniew Lukwinski             {
7622f3563ccSZbigniew Lukwinski                 log<level::ERR>(
7632f3563ccSZbigniew Lukwinski                     "Failed to remove symlink for certificate",
7642f3563ccSZbigniew Lukwinski                     entry("ERR=%s", e.what()),
7652f3563ccSZbigniew Lukwinski                     entry("SYMLINK=%s", certPath.path().string().c_str()));
7662f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
7672f3563ccSZbigniew Lukwinski             }
7682f3563ccSZbigniew Lukwinski         }
7692f3563ccSZbigniew Lukwinski     }
7702f3563ccSZbigniew Lukwinski 
7712f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
7722f3563ccSZbigniew Lukwinski     {
7732f3563ccSZbigniew Lukwinski         cert->storageUpdate();
7742f3563ccSZbigniew Lukwinski     }
7752f3563ccSZbigniew Lukwinski }
7762f3563ccSZbigniew Lukwinski 
7772f3563ccSZbigniew Lukwinski void Manager::reloadOrReset(const UnitsToRestart& unit)
7782f3563ccSZbigniew Lukwinski {
7792f3563ccSZbigniew Lukwinski     if (!unit.empty())
7802f3563ccSZbigniew Lukwinski     {
7812f3563ccSZbigniew Lukwinski         try
7822f3563ccSZbigniew Lukwinski         {
7832f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
7842f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
7852f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_INTERFACE =
7862f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
7872f3563ccSZbigniew Lukwinski 
7882f3563ccSZbigniew Lukwinski             auto method =
7892f3563ccSZbigniew Lukwinski                 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
7902f3563ccSZbigniew Lukwinski                                     SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
7912f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
7922f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
7932f3563ccSZbigniew Lukwinski         }
7942f3563ccSZbigniew Lukwinski         catch (const sdbusplus::exception::SdBusError& e)
7952f3563ccSZbigniew Lukwinski         {
7962f3563ccSZbigniew Lukwinski             log<level::ERR>("Failed to reload or restart service",
7972f3563ccSZbigniew Lukwinski                             entry("ERR=%s", e.what()),
7982f3563ccSZbigniew Lukwinski                             entry("UNIT=%s", unit.c_str()));
7992f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
8002f3563ccSZbigniew Lukwinski         }
8012f3563ccSZbigniew Lukwinski     }
8022f3563ccSZbigniew Lukwinski }
8032f3563ccSZbigniew Lukwinski 
8042f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
8052f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
8062f3563ccSZbigniew Lukwinski {
8072f3563ccSZbigniew Lukwinski     if (std::any_of(
8082f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
8092f3563ccSZbigniew Lukwinski             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
8102f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
8112f3563ccSZbigniew Lukwinski             }))
8122f3563ccSZbigniew Lukwinski     {
8132f3563ccSZbigniew Lukwinski         return false;
8142f3563ccSZbigniew Lukwinski     }
8152f3563ccSZbigniew Lukwinski     else
8162f3563ccSZbigniew Lukwinski     {
8172f3563ccSZbigniew Lukwinski         return true;
8182f3563ccSZbigniew Lukwinski     }
8192f3563ccSZbigniew Lukwinski }
8202f3563ccSZbigniew Lukwinski 
821cfbc8dc8SJayanth Othayoth } // namespace certs
822cfbc8dc8SJayanth Othayoth } // namespace phosphor
823