xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 2f3563cc53a8f32c43b03d20b7219e52b1c1cf28)
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>
10*2f3563ccSZbigniew 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 {
37fe590c4eSZbigniew Lukwinski     // Create certificate directory if not existing.
38fe590c4eSZbigniew Lukwinski     // Set correct certificate directory permitions.
39fe590c4eSZbigniew Lukwinski     fs::path certDirectory;
40b57d75e2SMarri Devender Rao     try
41b57d75e2SMarri Devender Rao     {
42fe590c4eSZbigniew Lukwinski         if (certType == AUTHORITY)
43b57d75e2SMarri Devender Rao         {
44fe590c4eSZbigniew Lukwinski             certDirectory = certInstallPath;
45b57d75e2SMarri Devender Rao         }
46fe590c4eSZbigniew Lukwinski         else
47fe590c4eSZbigniew Lukwinski         {
48fe590c4eSZbigniew Lukwinski             certDirectory = certParentInstallPath;
49fe590c4eSZbigniew Lukwinski         }
50fe590c4eSZbigniew Lukwinski 
51fe590c4eSZbigniew Lukwinski         if (!fs::exists(certDirectory))
52fe590c4eSZbigniew Lukwinski         {
53fe590c4eSZbigniew Lukwinski             fs::create_directories(certDirectory);
54fe590c4eSZbigniew Lukwinski         }
55fe590c4eSZbigniew Lukwinski 
56667286e4SMarri Devender Rao         auto permission = fs::perms::owner_read | fs::perms::owner_write |
57667286e4SMarri Devender Rao                           fs::perms::owner_exec;
58fe590c4eSZbigniew Lukwinski         fs::permissions(certDirectory, permission, fs::perm_options::replace);
59*2f3563ccSZbigniew Lukwinski         storageUpdate();
60b57d75e2SMarri Devender Rao     }
61b57d75e2SMarri Devender Rao     catch (fs::filesystem_error& e)
62b57d75e2SMarri Devender Rao     {
63b57d75e2SMarri Devender Rao         log<level::ERR>("Failed to create directory", entry("ERR=%s", e.what()),
64b57d75e2SMarri Devender Rao                         entry("DIRECTORY=%s", certParentInstallPath.c_str()));
65b57d75e2SMarri Devender Rao         report<InternalFailure>();
66b57d75e2SMarri Devender Rao     }
67b57d75e2SMarri Devender Rao 
68c6e58c7eSRamesh Iyyar     // Generating RSA private key file if certificate type is server/client
69c6e58c7eSRamesh Iyyar     if (certType != AUTHORITY)
70c6e58c7eSRamesh Iyyar     {
71c6e58c7eSRamesh Iyyar         createRSAPrivateKeyFile();
72c6e58c7eSRamesh Iyyar     }
73c6e58c7eSRamesh Iyyar 
74ffad1ef1SMarri Devender Rao     // restore any existing certificates
75db029c95SKowalski, Kamil     createCertificates();
76ffad1ef1SMarri Devender Rao 
77ffad1ef1SMarri Devender Rao     // watch is not required for authority certificates
78ffad1ef1SMarri Devender Rao     if (certType != AUTHORITY)
79ffad1ef1SMarri Devender Rao     {
80ffad1ef1SMarri Devender Rao         // watch for certificate file create/replace
81ffad1ef1SMarri Devender Rao         certWatchPtr = std::make_unique<
82ffad1ef1SMarri Devender Rao             Watch>(event, certInstallPath, [this]() {
83bf7c588cSMarri Devender Rao             try
84bf7c588cSMarri Devender Rao             {
85ffad1ef1SMarri Devender Rao                 // if certificate file existing update it
86db029c95SKowalski, Kamil                 if (!installedCerts.empty())
87ffad1ef1SMarri Devender Rao                 {
88ffad1ef1SMarri Devender Rao                     log<level::INFO>(
89ffad1ef1SMarri Devender Rao                         "Inotify callback to update certificate properties");
90db029c95SKowalski, Kamil                     installedCerts[0]->populateProperties();
91ffad1ef1SMarri Devender Rao                 }
92ffad1ef1SMarri Devender Rao                 else
93ffad1ef1SMarri Devender Rao                 {
94ffad1ef1SMarri Devender Rao                     log<level::INFO>(
95ffad1ef1SMarri Devender Rao                         "Inotify callback to create certificate object");
96db029c95SKowalski, Kamil                     createCertificates();
97ffad1ef1SMarri Devender Rao                 }
98bf7c588cSMarri Devender Rao             }
99bf7c588cSMarri Devender Rao             catch (const InternalFailure& e)
100bf7c588cSMarri Devender Rao             {
101ffad1ef1SMarri Devender Rao                 commit<InternalFailure>();
102bf7c588cSMarri Devender Rao             }
103bf7c588cSMarri Devender Rao             catch (const InvalidCertificate& e)
104bf7c588cSMarri Devender Rao             {
105ffad1ef1SMarri Devender Rao                 commit<InvalidCertificate>();
106bf7c588cSMarri Devender Rao             }
107ffad1ef1SMarri Devender Rao         });
108bf7c588cSMarri Devender Rao     }
109db029c95SKowalski, Kamil     else
110db029c95SKowalski, Kamil     {
111db029c95SKowalski, Kamil         const std::string signleCertPath = "/etc/ssl/certs/Root-CA.pem";
112db029c95SKowalski, Kamil         if (fs::exists(signleCertPath) && !fs::is_empty(signleCertPath))
113db029c95SKowalski, Kamil         {
114db029c95SKowalski, Kamil             log<level::NOTICE>(
115db029c95SKowalski, Kamil                 "Legacy certificate detected, will be installed from: ",
116db029c95SKowalski, Kamil                 entry("SINGLE_CERTPATH=%s", signleCertPath.c_str()));
117db029c95SKowalski, Kamil             install(signleCertPath);
118db029c95SKowalski, Kamil             if (!fs::remove(signleCertPath))
119db029c95SKowalski, Kamil             {
120db029c95SKowalski, Kamil                 log<level::ERR>(
121db029c95SKowalski, Kamil                     "Unable to remove old certificate from: ",
122db029c95SKowalski, Kamil                     entry("SINGLE_CERTPATH=%s", signleCertPath.c_str()));
123db029c95SKowalski, Kamil                 elog<InternalFailure>();
124db029c95SKowalski, Kamil             }
125db029c95SKowalski, Kamil         }
126db029c95SKowalski, Kamil     }
127dd74bd20SJayanth Othayoth }
128589159f2SJayanth Othayoth 
12906a69d7bSZbigniew Kurzynski std::string Manager::install(const std::string filePath)
130cfbc8dc8SJayanth Othayoth {
1311396511dSMarri Devender Rao     using NotAllowed =
1321396511dSMarri Devender Rao         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
1331396511dSMarri Devender Rao     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
134db029c95SKowalski, Kamil 
135db029c95SKowalski, Kamil     if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty())
1361396511dSMarri Devender Rao     {
1371396511dSMarri Devender Rao         elog<NotAllowed>(Reason("Certificate already exist"));
1381396511dSMarri Devender Rao     }
1393b07b77aSZbigniew Lukwinski     else if (certType == phosphor::certs::AUTHORITY &&
1403b07b77aSZbigniew Lukwinski              installedCerts.size() >= AUTHORITY_CERTIFICATES_LIMIT)
1413b07b77aSZbigniew Lukwinski     {
1423b07b77aSZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificates limit reached"));
1433b07b77aSZbigniew Lukwinski     }
144ffad1ef1SMarri Devender Rao 
145*2f3563ccSZbigniew Lukwinski     std::string certObjectPath;
146*2f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath))
147*2f3563ccSZbigniew Lukwinski     {
148*2f3563ccSZbigniew Lukwinski         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
149db029c95SKowalski, Kamil         installedCerts.emplace_back(std::make_unique<Certificate>(
150*2f3563ccSZbigniew Lukwinski             bus, certObjectPath, certType, certInstallPath, filePath,
151*2f3563ccSZbigniew Lukwinski             certWatchPtr, *this));
152*2f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
153*2f3563ccSZbigniew Lukwinski         certIdCounter++;
154*2f3563ccSZbigniew Lukwinski     }
155*2f3563ccSZbigniew Lukwinski     else
156*2f3563ccSZbigniew Lukwinski     {
157*2f3563ccSZbigniew Lukwinski         elog<NotAllowed>(Reason("Certificate already exist"));
158*2f3563ccSZbigniew Lukwinski     }
159*2f3563ccSZbigniew Lukwinski 
16006a69d7bSZbigniew Kurzynski     return certObjectPath;
161589159f2SJayanth Othayoth }
162ae70b3daSDeepak Kodihalli 
163a3bb38fbSZbigniew Kurzynski void Manager::deleteAll()
164ae70b3daSDeepak Kodihalli {
1656ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
1666ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
1676ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
1686ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
1696ceec40bSMarri Devender Rao     // deletion of certificates
170db029c95SKowalski, Kamil     installedCerts.clear();
171*2f3563ccSZbigniew Lukwinski     storageUpdate();
172*2f3563ccSZbigniew Lukwinski     reloadOrReset(unitToRestart);
173ae70b3daSDeepak Kodihalli }
174f4682712SMarri Devender Rao 
175*2f3563ccSZbigniew Lukwinski void Manager::deleteCertificate(const Certificate* const certificate)
176a3bb38fbSZbigniew Kurzynski {
177a3bb38fbSZbigniew Kurzynski     std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
178a3bb38fbSZbigniew Kurzynski         std::find_if(installedCerts.begin(), installedCerts.end(),
179*2f3563ccSZbigniew Lukwinski                      [certificate](std::unique_ptr<Certificate> const& cert) {
180*2f3563ccSZbigniew Lukwinski                          return (cert.get() == certificate);
181a3bb38fbSZbigniew Kurzynski                      });
182a3bb38fbSZbigniew Kurzynski     if (certIt != installedCerts.end())
183a3bb38fbSZbigniew Kurzynski     {
184a3bb38fbSZbigniew Kurzynski         installedCerts.erase(certIt);
185*2f3563ccSZbigniew Lukwinski         storageUpdate();
186*2f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
187a3bb38fbSZbigniew Kurzynski     }
188a3bb38fbSZbigniew Kurzynski     else
189a3bb38fbSZbigniew Kurzynski     {
190a3bb38fbSZbigniew Kurzynski         log<level::ERR>("Certificate does not exist",
191*2f3563ccSZbigniew Lukwinski                         entry("ID=%s", certificate->getCertId().c_str()));
192*2f3563ccSZbigniew Lukwinski         elog<InternalFailure>();
193*2f3563ccSZbigniew Lukwinski     }
194*2f3563ccSZbigniew Lukwinski }
195*2f3563ccSZbigniew Lukwinski 
196*2f3563ccSZbigniew Lukwinski void Manager::replaceCertificate(Certificate* const certificate,
197*2f3563ccSZbigniew Lukwinski                                  const std::string& filePath)
198*2f3563ccSZbigniew Lukwinski {
199*2f3563ccSZbigniew Lukwinski     if (isCertificateUnique(filePath, certificate))
200*2f3563ccSZbigniew Lukwinski     {
201*2f3563ccSZbigniew Lukwinski         certificate->install(filePath);
202*2f3563ccSZbigniew Lukwinski         storageUpdate();
203*2f3563ccSZbigniew Lukwinski         reloadOrReset(unitToRestart);
204*2f3563ccSZbigniew Lukwinski     }
205*2f3563ccSZbigniew Lukwinski     else
206*2f3563ccSZbigniew Lukwinski     {
207*2f3563ccSZbigniew Lukwinski         log<level::ERR>("Certificate already exist");
208a3bb38fbSZbigniew Kurzynski         elog<InternalFailure>();
209a3bb38fbSZbigniew Kurzynski     }
210a3bb38fbSZbigniew Kurzynski }
211a3bb38fbSZbigniew Kurzynski 
212f4682712SMarri Devender Rao std::string Manager::generateCSR(
213f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
214f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
215f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
216f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
217f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
218f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
219f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
220f4682712SMarri Devender Rao {
221f4682712SMarri Devender Rao     // We support only one CSR.
222f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
223f4682712SMarri Devender Rao     auto pid = fork();
224f4682712SMarri Devender Rao     if (pid == -1)
225f4682712SMarri Devender Rao     {
226f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
227f4682712SMarri Devender Rao         report<InternalFailure>();
228f4682712SMarri Devender Rao     }
229f4682712SMarri Devender Rao     else if (pid == 0)
230f4682712SMarri Devender Rao     {
231f4682712SMarri Devender Rao         try
232f4682712SMarri Devender Rao         {
233f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
234f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
235f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
236f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
237f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
238f4682712SMarri Devender Rao                               unstructuredName);
239f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
240f4682712SMarri Devender Rao         }
241f4682712SMarri Devender Rao         catch (const InternalFailure& e)
242f4682712SMarri Devender Rao         {
243f4682712SMarri Devender Rao             // commit the error reported in child process and exit
244f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
245f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
246f4682712SMarri Devender Rao             commit<InternalFailure>();
247f4682712SMarri Devender Rao         }
248f4682712SMarri Devender Rao     }
249f4682712SMarri Devender Rao     else
250f4682712SMarri Devender Rao     {
251f4682712SMarri Devender Rao         using namespace sdeventplus::source;
252f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
253f4682712SMarri Devender Rao                                           const siginfo_t* si) {
254f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
255f4682712SMarri Devender Rao             if (si->si_status != 0)
256f4682712SMarri Devender Rao             {
257f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
258f4682712SMarri Devender Rao             }
259f4682712SMarri Devender Rao             else
260f4682712SMarri Devender Rao             {
261f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
262f4682712SMarri Devender Rao             }
263f4682712SMarri Devender Rao         };
264f4682712SMarri Devender Rao         try
265f4682712SMarri Devender Rao         {
266f4682712SMarri Devender Rao             sigset_t ss;
267f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
268f4682712SMarri Devender Rao             {
269f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
270f4682712SMarri Devender Rao                 elog<InternalFailure>();
271f4682712SMarri Devender Rao             }
272f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
273f4682712SMarri Devender Rao             {
274f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
275f4682712SMarri Devender Rao                 elog<InternalFailure>();
276f4682712SMarri Devender Rao             }
277f4682712SMarri Devender Rao 
278f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
279f4682712SMarri Devender Rao             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
280f4682712SMarri Devender Rao             {
281f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
282f4682712SMarri Devender Rao                 elog<InternalFailure>();
283f4682712SMarri Devender Rao             }
284f4682712SMarri Devender Rao             if (childPtr)
285f4682712SMarri Devender Rao             {
286f4682712SMarri Devender Rao                 childPtr.reset();
287f4682712SMarri Devender Rao             }
288f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
289f4682712SMarri Devender Rao                                                std::move(callback));
290f4682712SMarri Devender Rao         }
291f4682712SMarri Devender Rao         catch (const InternalFailure& e)
292f4682712SMarri Devender Rao         {
293f4682712SMarri Devender Rao             commit<InternalFailure>();
294f4682712SMarri Devender Rao         }
295f4682712SMarri Devender Rao     }
296f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
297f4682712SMarri Devender Rao     return csrObjectPath;
298f4682712SMarri Devender Rao }
299f4682712SMarri Devender Rao 
300db029c95SKowalski, Kamil std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
301ffad1ef1SMarri Devender Rao {
302db029c95SKowalski, Kamil     return installedCerts;
303ffad1ef1SMarri Devender Rao }
304ffad1ef1SMarri Devender Rao 
305f4682712SMarri Devender Rao void Manager::generateCSRHelper(
306f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
307f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
308f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
309f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
310f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
311f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
312f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
313f4682712SMarri Devender Rao {
314f4682712SMarri Devender Rao     int ret = 0;
315f4682712SMarri Devender Rao 
316f4682712SMarri Devender Rao     // set version of x509 req
317f4682712SMarri Devender Rao     int nVersion = 1;
318f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
319f4682712SMarri Devender Rao     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
320f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
321f4682712SMarri Devender Rao     if (ret == 0)
322f4682712SMarri Devender Rao     {
323f4682712SMarri Devender Rao         log<level::ERR>("Error occured during X509_REQ_set_version call");
324f4682712SMarri Devender Rao         elog<InternalFailure>();
325f4682712SMarri Devender Rao     }
326f4682712SMarri Devender Rao 
327f4682712SMarri Devender Rao     // set subject of x509 req
328f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
329f4682712SMarri Devender Rao 
330f4682712SMarri Devender Rao     if (!alternativeNames.empty())
331f4682712SMarri Devender Rao     {
332f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
333f4682712SMarri Devender Rao         {
334f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
335f4682712SMarri Devender Rao         }
336f4682712SMarri Devender Rao     }
337f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
338f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
339f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
340f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
341f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
342f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
343f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
344f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
345f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
346f4682712SMarri Devender Rao     if (!keyUsage.empty())
347f4682712SMarri Devender Rao     {
348f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
349f4682712SMarri Devender Rao         {
3507641105dSMarri Devender Rao             if (isExtendedKeyUsage(usage))
3517641105dSMarri Devender Rao             {
3527641105dSMarri Devender Rao                 addEntry(x509Name, "extendedKeyUsage", usage);
3537641105dSMarri Devender Rao             }
3547641105dSMarri Devender Rao             else
3557641105dSMarri Devender Rao             {
356f4682712SMarri Devender Rao                 addEntry(x509Name, "keyUsage", usage);
357f4682712SMarri Devender Rao             }
358f4682712SMarri Devender Rao         }
3597641105dSMarri Devender Rao     }
360f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
361f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
362f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
363f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
364f4682712SMarri Devender Rao 
3658a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
3668a09b52aSRamesh Iyyar 
3678a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
3688a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
3698a09b52aSRamesh Iyyar 
3708a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
3718a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
372c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
3738a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
374c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
3758a09b52aSRamesh Iyyar     else
3768a09b52aSRamesh Iyyar     {
3778a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
3788a09b52aSRamesh Iyyar                         "RSA and EC only");
3798a09b52aSRamesh Iyyar         elog<InvalidArgument>(
3808a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
3818a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
3828a09b52aSRamesh Iyyar     }
3838a09b52aSRamesh Iyyar 
3848a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
3858a09b52aSRamesh Iyyar     if (ret == 0)
3868a09b52aSRamesh Iyyar     {
3878a09b52aSRamesh Iyyar         log<level::ERR>("Error occured while setting Public key");
3888a09b52aSRamesh Iyyar         elog<InternalFailure>();
3898a09b52aSRamesh Iyyar     }
3908a09b52aSRamesh Iyyar 
3918a09b52aSRamesh Iyyar     // Write private key to file
392c6e58c7eSRamesh Iyyar     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
393f4682712SMarri Devender Rao 
394f4682712SMarri Devender Rao     // set sign key of x509 req
395f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
3968a09b52aSRamesh Iyyar     if (ret == 0)
397f4682712SMarri Devender Rao     {
398f4682712SMarri Devender Rao         log<level::ERR>("Error occured while signing key of x509");
399f4682712SMarri Devender Rao         elog<InternalFailure>();
400f4682712SMarri Devender Rao     }
4018a09b52aSRamesh Iyyar 
402f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
403c6e58c7eSRamesh Iyyar     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
404c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
405f4682712SMarri Devender Rao }
406f4682712SMarri Devender Rao 
4077641105dSMarri Devender Rao bool Manager::isExtendedKeyUsage(const std::string& usage)
4087641105dSMarri Devender Rao {
4097641105dSMarri Devender Rao     const static std::array<const char*, 6> usageList = {
4107641105dSMarri Devender Rao         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
4117641105dSMarri Devender Rao         "Timestamping",         "CodeSigning",          "EmailProtection"};
4127641105dSMarri Devender Rao     auto it = std::find_if(
4137641105dSMarri Devender Rao         usageList.begin(), usageList.end(),
4147641105dSMarri Devender Rao         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
4157641105dSMarri Devender Rao     return it != usageList.end();
4167641105dSMarri Devender Rao }
4178a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
418f4682712SMarri Devender Rao {
419f4682712SMarri Devender Rao     int ret = 0;
420f4682712SMarri Devender Rao     // generate rsa key
421f4682712SMarri Devender Rao     BIGNUM_Ptr bne(BN_new(), ::BN_free);
422f4682712SMarri Devender Rao     ret = BN_set_word(bne.get(), RSA_F4);
423f4682712SMarri Devender Rao     if (ret == 0)
424f4682712SMarri Devender Rao     {
425f4682712SMarri Devender Rao         log<level::ERR>("Error occured during BN_set_word call");
426f4682712SMarri Devender Rao         elog<InternalFailure>();
427f4682712SMarri Devender Rao     }
428f4682712SMarri Devender Rao 
4298a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
430f4682712SMarri Devender Rao     // set keybit length to default value if not set
4318a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
432f4682712SMarri Devender Rao     {
4338a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
4348a09b52aSRamesh Iyyar         log<level::INFO>(
4358a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
4368a09b52aSRamesh Iyyar             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
4378a09b52aSRamesh Iyyar         keyBitLen = DEFAULT_KEYBITLENGTH;
438f4682712SMarri Devender Rao     }
439f4682712SMarri Devender Rao     RSA* rsa = RSA_new();
4408a09b52aSRamesh Iyyar     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
441f4682712SMarri Devender Rao     if (ret != 1)
442f4682712SMarri Devender Rao     {
443f4682712SMarri Devender Rao         free(rsa);
444f4682712SMarri Devender Rao         log<level::ERR>("Error occured during RSA_generate_key_ex call",
4458a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
446f4682712SMarri Devender Rao         elog<InternalFailure>();
447f4682712SMarri Devender Rao     }
448f4682712SMarri Devender Rao 
449f4682712SMarri Devender Rao     // set public key of x509 req
450f4682712SMarri Devender Rao     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
4518a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
452f4682712SMarri Devender Rao     if (ret == 0)
453f4682712SMarri Devender Rao     {
4548a09b52aSRamesh Iyyar         free(rsa);
4558a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign rsa key into EVP");
456f4682712SMarri Devender Rao         elog<InternalFailure>();
457f4682712SMarri Devender Rao     }
458f4682712SMarri Devender Rao 
4598a09b52aSRamesh Iyyar     return pKey;
4608a09b52aSRamesh Iyyar }
4618a09b52aSRamesh Iyyar 
4628a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
4638a09b52aSRamesh Iyyar {
4648a09b52aSRamesh Iyyar     std::string curId(curveId);
4658a09b52aSRamesh Iyyar 
4668a09b52aSRamesh Iyyar     if (curId.empty())
4678a09b52aSRamesh Iyyar     {
4688a09b52aSRamesh Iyyar         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
4698a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
4708a09b52aSRamesh Iyyar         log<level::INFO>(
4718a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
4728a09b52aSRamesh Iyyar             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
4738a09b52aSRamesh Iyyar         curId = DEFAULT_KEYCURVEID;
4748a09b52aSRamesh Iyyar     }
4758a09b52aSRamesh Iyyar 
4768a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
4778a09b52aSRamesh Iyyar 
4788a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
4798a09b52aSRamesh Iyyar     {
4808a09b52aSRamesh Iyyar         log<level::ERR>(
4818a09b52aSRamesh Iyyar             "Error occured during convert the curve id string format into NID",
4828a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
4838a09b52aSRamesh Iyyar         elog<InternalFailure>();
4848a09b52aSRamesh Iyyar     }
4858a09b52aSRamesh Iyyar 
4868a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
4878a09b52aSRamesh Iyyar 
4888a09b52aSRamesh Iyyar     if (ecKey == NULL)
4898a09b52aSRamesh Iyyar     {
4908a09b52aSRamesh Iyyar         log<level::ERR>(
4918a09b52aSRamesh Iyyar             "Error occured during create the EC_Key object from NID",
4928a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
4938a09b52aSRamesh Iyyar         elog<InternalFailure>();
4948a09b52aSRamesh Iyyar     }
4958a09b52aSRamesh Iyyar 
4968a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
4978a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
4988a09b52aSRamesh Iyyar     // flag on the key.
4998a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
5008a09b52aSRamesh Iyyar 
5018a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
5028a09b52aSRamesh Iyyar 
5038a09b52aSRamesh Iyyar     if (ret == 0)
5048a09b52aSRamesh Iyyar     {
5058a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5068a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during generate EC key");
5078a09b52aSRamesh Iyyar         elog<InternalFailure>();
5088a09b52aSRamesh Iyyar     }
5098a09b52aSRamesh Iyyar 
5108a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
5118a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
5128a09b52aSRamesh Iyyar     if (ret == 0)
5138a09b52aSRamesh Iyyar     {
5148a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
5158a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign EC Key into EVP");
5168a09b52aSRamesh Iyyar         elog<InternalFailure>();
5178a09b52aSRamesh Iyyar     }
5188a09b52aSRamesh Iyyar 
5198a09b52aSRamesh Iyyar     return pKey;
5208a09b52aSRamesh Iyyar }
5218a09b52aSRamesh Iyyar 
522c6e58c7eSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
523c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
5248a09b52aSRamesh Iyyar {
5258a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
526f4682712SMarri Devender Rao     // write private key to file
527c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
528f4682712SMarri Devender Rao 
529f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
530f4682712SMarri Devender Rao     if (fp == NULL)
531f4682712SMarri Devender Rao     {
532f4682712SMarri Devender Rao         log<level::ERR>("Error occured creating private key file");
533f4682712SMarri Devender Rao         elog<InternalFailure>();
534f4682712SMarri Devender Rao     }
5358a09b52aSRamesh Iyyar     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
536f4682712SMarri Devender Rao     std::fclose(fp);
537f4682712SMarri Devender Rao     if (ret == 0)
538f4682712SMarri Devender Rao     {
539f4682712SMarri Devender Rao         log<level::ERR>("Error occured while writing private key to file");
540f4682712SMarri Devender Rao         elog<InternalFailure>();
541f4682712SMarri Devender Rao     }
542f4682712SMarri Devender Rao }
543f4682712SMarri Devender Rao 
544f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
545f4682712SMarri Devender Rao                        const std::string& bytes)
546f4682712SMarri Devender Rao {
547f4682712SMarri Devender Rao     if (bytes.empty())
548f4682712SMarri Devender Rao     {
549f4682712SMarri Devender Rao         return;
550f4682712SMarri Devender Rao     }
551f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
552f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
553f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
554f4682712SMarri Devender Rao     if (ret != 1)
555f4682712SMarri Devender Rao     {
556f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
557f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
558f4682712SMarri Devender Rao         elog<InternalFailure>();
559f4682712SMarri Devender Rao     }
560f4682712SMarri Devender Rao }
561f4682712SMarri Devender Rao 
562f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
563f4682712SMarri Devender Rao {
564f4682712SMarri Devender Rao     if (csrPtr)
565f4682712SMarri Devender Rao     {
566f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
567f4682712SMarri Devender Rao     }
568f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
569f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
570f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
571f4682712SMarri Devender Rao }
572f4682712SMarri Devender Rao 
573f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
574f4682712SMarri Devender Rao {
575f4682712SMarri Devender Rao     if (fs::exists(filePath))
576f4682712SMarri Devender Rao     {
577f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
578f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
579f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
580f4682712SMarri Devender Rao         {
581f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
582f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
583f4682712SMarri Devender Rao             elog<InternalFailure>();
584f4682712SMarri Devender Rao         }
585f4682712SMarri Devender Rao     }
586f4682712SMarri Devender Rao 
587f4682712SMarri Devender Rao     FILE* fp = NULL;
588f4682712SMarri Devender Rao 
589f4682712SMarri Devender Rao     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
590f4682712SMarri Devender Rao     {
591f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
592f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
593f4682712SMarri Devender Rao         elog<InternalFailure>();
594f4682712SMarri Devender Rao     }
595f4682712SMarri Devender Rao 
596f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
597f4682712SMarri Devender Rao     if (!rc)
598f4682712SMarri Devender Rao     {
599f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
600f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
601f4682712SMarri Devender Rao         std::fclose(fp);
602f4682712SMarri Devender Rao         elog<InternalFailure>();
603f4682712SMarri Devender Rao     }
604f4682712SMarri Devender Rao     std::fclose(fp);
605f4682712SMarri Devender Rao }
606f4682712SMarri Devender Rao 
607db029c95SKowalski, Kamil void Manager::createCertificates()
608db029c95SKowalski, Kamil {
609db029c95SKowalski, Kamil     auto certObjectPath = objectPath + '/';
610db029c95SKowalski, Kamil 
611db029c95SKowalski, Kamil     if (certType == phosphor::certs::AUTHORITY)
612db029c95SKowalski, Kamil     {
613fe590c4eSZbigniew Lukwinski         // Check whether install path is a directory.
614db029c95SKowalski, Kamil         if (!fs::is_directory(certInstallPath))
615db029c95SKowalski, Kamil         {
616db029c95SKowalski, Kamil             log<level::ERR>("Certificate installation path exists and it is "
617db029c95SKowalski, Kamil                             "not a directory");
618db029c95SKowalski, Kamil             elog<InternalFailure>();
619db029c95SKowalski, Kamil             return;
620db029c95SKowalski, Kamil         }
621db029c95SKowalski, Kamil 
622db029c95SKowalski, Kamil         for (auto& path : fs::directory_iterator(certInstallPath))
623ffad1ef1SMarri Devender Rao         {
624ffad1ef1SMarri Devender Rao             try
625ffad1ef1SMarri Devender Rao             {
626*2f3563ccSZbigniew Lukwinski                 // Assume here any regular file located in certificate directory
627*2f3563ccSZbigniew Lukwinski                 // contains certificates body. Do not want to use soft links
628*2f3563ccSZbigniew Lukwinski                 // would add value.
629*2f3563ccSZbigniew Lukwinski                 if (fs::is_regular_file(path))
630*2f3563ccSZbigniew Lukwinski                 {
631db029c95SKowalski, Kamil                     installedCerts.emplace_back(std::make_unique<Certificate>(
632db029c95SKowalski, Kamil                         bus, certObjectPath + std::to_string(certIdCounter++),
633*2f3563ccSZbigniew Lukwinski                         certType, certInstallPath, path.path(), certWatchPtr,
634*2f3563ccSZbigniew Lukwinski                         *this));
635*2f3563ccSZbigniew Lukwinski                 }
636ffad1ef1SMarri Devender Rao             }
637ffad1ef1SMarri Devender Rao             catch (const InternalFailure& e)
638ffad1ef1SMarri Devender Rao             {
639ffad1ef1SMarri Devender Rao                 report<InternalFailure>();
640ffad1ef1SMarri Devender Rao             }
641ffad1ef1SMarri Devender Rao             catch (const InvalidCertificate& e)
642ffad1ef1SMarri Devender Rao             {
643ffad1ef1SMarri Devender Rao                 report<InvalidCertificate>(
644ffad1ef1SMarri Devender Rao                     Reason("Existing certificate file is corrupted"));
645ffad1ef1SMarri Devender Rao             }
646ffad1ef1SMarri Devender Rao         }
647db029c95SKowalski, Kamil     }
648db029c95SKowalski, Kamil     else if (fs::exists(certInstallPath))
649db029c95SKowalski, Kamil     {
650db029c95SKowalski, Kamil         try
651db029c95SKowalski, Kamil         {
652db029c95SKowalski, Kamil             installedCerts.emplace_back(std::make_unique<Certificate>(
653*2f3563ccSZbigniew Lukwinski                 bus, certObjectPath + '1', certType, certInstallPath,
654*2f3563ccSZbigniew Lukwinski                 certInstallPath, certWatchPtr, *this));
655db029c95SKowalski, Kamil         }
656db029c95SKowalski, Kamil         catch (const InternalFailure& e)
657db029c95SKowalski, Kamil         {
658db029c95SKowalski, Kamil             report<InternalFailure>();
659db029c95SKowalski, Kamil         }
660db029c95SKowalski, Kamil         catch (const InvalidCertificate& e)
661db029c95SKowalski, Kamil         {
662db029c95SKowalski, Kamil             report<InvalidCertificate>(
663db029c95SKowalski, Kamil                 Reason("Existing certificate file is corrupted"));
664db029c95SKowalski, Kamil         }
665db029c95SKowalski, Kamil     }
666db029c95SKowalski, Kamil }
667c6e58c7eSRamesh Iyyar 
668c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
669c6e58c7eSRamesh Iyyar {
670c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
671c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
672c6e58c7eSRamesh Iyyar 
673c6e58c7eSRamesh Iyyar     try
674c6e58c7eSRamesh Iyyar     {
675c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
676c6e58c7eSRamesh Iyyar         {
677c6e58c7eSRamesh Iyyar             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
678c6e58c7eSRamesh Iyyar                             RSA_PRIV_KEY_FILE_NAME);
679c6e58c7eSRamesh Iyyar         }
680c6e58c7eSRamesh Iyyar     }
681c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
682c6e58c7eSRamesh Iyyar     {
683c6e58c7eSRamesh Iyyar         report<InternalFailure>();
684c6e58c7eSRamesh Iyyar     }
685c6e58c7eSRamesh Iyyar }
686c6e58c7eSRamesh Iyyar 
687c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
688c6e58c7eSRamesh Iyyar {
689c6e58c7eSRamesh Iyyar     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
690c6e58c7eSRamesh Iyyar     {
691c6e58c7eSRamesh Iyyar         log<level::ERR>(
692c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
693c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
694c6e58c7eSRamesh Iyyar             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
695c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
696c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
697c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
698c6e58c7eSRamesh Iyyar     }
699c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
700c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
701c6e58c7eSRamesh Iyyar 
702c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
703c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
704c6e58c7eSRamesh Iyyar     {
705c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
706c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
707c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
708c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
709c6e58c7eSRamesh Iyyar     }
710c6e58c7eSRamesh Iyyar 
711c6e58c7eSRamesh Iyyar     EVP_PKEY_Ptr privateKey(
712c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
713c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
714c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
715c6e58c7eSRamesh Iyyar 
716c6e58c7eSRamesh Iyyar     if (!privateKey)
717c6e58c7eSRamesh Iyyar     {
718c6e58c7eSRamesh Iyyar         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
719c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
720c6e58c7eSRamesh Iyyar     }
721c6e58c7eSRamesh Iyyar     return privateKey;
722c6e58c7eSRamesh Iyyar }
723*2f3563ccSZbigniew Lukwinski 
724*2f3563ccSZbigniew Lukwinski void Manager::storageUpdate()
725*2f3563ccSZbigniew Lukwinski {
726*2f3563ccSZbigniew Lukwinski     if (certType == phosphor::certs::AUTHORITY)
727*2f3563ccSZbigniew Lukwinski     {
728*2f3563ccSZbigniew Lukwinski         // Remove symbolic links in the certificate directory
729*2f3563ccSZbigniew Lukwinski         for (auto& certPath : fs::directory_iterator(certInstallPath))
730*2f3563ccSZbigniew Lukwinski         {
731*2f3563ccSZbigniew Lukwinski             try
732*2f3563ccSZbigniew Lukwinski             {
733*2f3563ccSZbigniew Lukwinski                 if (fs::is_symlink(certPath))
734*2f3563ccSZbigniew Lukwinski                 {
735*2f3563ccSZbigniew Lukwinski                     fs::remove(certPath);
736*2f3563ccSZbigniew Lukwinski                 }
737*2f3563ccSZbigniew Lukwinski             }
738*2f3563ccSZbigniew Lukwinski             catch (const std::exception& e)
739*2f3563ccSZbigniew Lukwinski             {
740*2f3563ccSZbigniew Lukwinski                 log<level::ERR>(
741*2f3563ccSZbigniew Lukwinski                     "Failed to remove symlink for certificate",
742*2f3563ccSZbigniew Lukwinski                     entry("ERR=%s", e.what()),
743*2f3563ccSZbigniew Lukwinski                     entry("SYMLINK=%s", certPath.path().string().c_str()));
744*2f3563ccSZbigniew Lukwinski                 elog<InternalFailure>();
745*2f3563ccSZbigniew Lukwinski             }
746*2f3563ccSZbigniew Lukwinski         }
747*2f3563ccSZbigniew Lukwinski     }
748*2f3563ccSZbigniew Lukwinski 
749*2f3563ccSZbigniew Lukwinski     for (const auto& cert : installedCerts)
750*2f3563ccSZbigniew Lukwinski     {
751*2f3563ccSZbigniew Lukwinski         cert->storageUpdate();
752*2f3563ccSZbigniew Lukwinski     }
753*2f3563ccSZbigniew Lukwinski }
754*2f3563ccSZbigniew Lukwinski 
755*2f3563ccSZbigniew Lukwinski void Manager::reloadOrReset(const UnitsToRestart& unit)
756*2f3563ccSZbigniew Lukwinski {
757*2f3563ccSZbigniew Lukwinski     if (!unit.empty())
758*2f3563ccSZbigniew Lukwinski     {
759*2f3563ccSZbigniew Lukwinski         try
760*2f3563ccSZbigniew Lukwinski         {
761*2f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
762*2f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
763*2f3563ccSZbigniew Lukwinski             constexpr auto SYSTEMD_INTERFACE =
764*2f3563ccSZbigniew Lukwinski                 "org.freedesktop.systemd1.Manager";
765*2f3563ccSZbigniew Lukwinski 
766*2f3563ccSZbigniew Lukwinski             auto method =
767*2f3563ccSZbigniew Lukwinski                 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
768*2f3563ccSZbigniew Lukwinski                                     SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
769*2f3563ccSZbigniew Lukwinski             method.append(unit, "replace");
770*2f3563ccSZbigniew Lukwinski             bus.call_noreply(method);
771*2f3563ccSZbigniew Lukwinski         }
772*2f3563ccSZbigniew Lukwinski         catch (const sdbusplus::exception::SdBusError& e)
773*2f3563ccSZbigniew Lukwinski         {
774*2f3563ccSZbigniew Lukwinski             log<level::ERR>("Failed to reload or restart service",
775*2f3563ccSZbigniew Lukwinski                             entry("ERR=%s", e.what()),
776*2f3563ccSZbigniew Lukwinski                             entry("UNIT=%s", unit.c_str()));
777*2f3563ccSZbigniew Lukwinski             elog<InternalFailure>();
778*2f3563ccSZbigniew Lukwinski         }
779*2f3563ccSZbigniew Lukwinski     }
780*2f3563ccSZbigniew Lukwinski }
781*2f3563ccSZbigniew Lukwinski 
782*2f3563ccSZbigniew Lukwinski bool Manager::isCertificateUnique(const std::string& filePath,
783*2f3563ccSZbigniew Lukwinski                                   const Certificate* const certToDrop)
784*2f3563ccSZbigniew Lukwinski {
785*2f3563ccSZbigniew Lukwinski     if (std::any_of(
786*2f3563ccSZbigniew Lukwinski             installedCerts.begin(), installedCerts.end(),
787*2f3563ccSZbigniew Lukwinski             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
788*2f3563ccSZbigniew Lukwinski                 return cert.get() != certToDrop && cert->isSame(filePath);
789*2f3563ccSZbigniew Lukwinski             }))
790*2f3563ccSZbigniew Lukwinski     {
791*2f3563ccSZbigniew Lukwinski         return false;
792*2f3563ccSZbigniew Lukwinski     }
793*2f3563ccSZbigniew Lukwinski     else
794*2f3563ccSZbigniew Lukwinski     {
795*2f3563ccSZbigniew Lukwinski         return true;
796*2f3563ccSZbigniew Lukwinski     }
797*2f3563ccSZbigniew Lukwinski }
798*2f3563ccSZbigniew Lukwinski 
799cfbc8dc8SJayanth Othayoth } // namespace certs
800cfbc8dc8SJayanth Othayoth } // namespace phosphor
801