xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 71957992588d1b239c33ba25cf713b48b4014521)
1 #include "certs_manager.hpp"
2 
3 #include <openssl/pem.h>
4 #include <unistd.h>
5 
6 #include <algorithm>
7 #include <phosphor-logging/elog-errors.hpp>
8 #include <xyz/openbmc_project/Certs/error.hpp>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 
11 namespace phosphor
12 {
13 namespace certs
14 {
15 using InternalFailure =
16     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
17 using InvalidCertificate =
18     sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
19 using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
20 
21 using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
22 using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
23 using InvalidArgument =
24     sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
25 using Argument = xyz::openbmc_project::Common::InvalidArgument;
26 
27 constexpr auto SUPPORTED_KEYBITLENGTH = 2048;
28 
29 Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
30                  const char* path, const CertificateType& type,
31                  UnitsToRestart&& unit, CertInstallPath&& installPath) :
32     Ifaces(bus, path),
33     bus(bus), event(event), objectPath(path), certType(type),
34     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
35     certParentInstallPath(fs::path(certInstallPath).parent_path())
36 {
37     try
38     {
39         // Create certificate directory if not existing.
40         // Set correct certificate directory permitions.
41         fs::path certDirectory;
42         try
43         {
44             if (certType == AUTHORITY)
45             {
46                 certDirectory = certInstallPath;
47             }
48             else
49             {
50                 certDirectory = certParentInstallPath;
51             }
52 
53             if (!fs::exists(certDirectory))
54             {
55                 fs::create_directories(certDirectory);
56             }
57 
58             auto permission = fs::perms::owner_read | fs::perms::owner_write |
59                               fs::perms::owner_exec;
60             fs::permissions(certDirectory, permission,
61                             fs::perm_options::replace);
62             storageUpdate();
63         }
64         catch (const fs::filesystem_error& e)
65         {
66             log<level::ERR>(
67                 "Failed to create directory", entry("ERR=%s", e.what()),
68                 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
69             report<InternalFailure>();
70         }
71 
72         // Generating RSA private key file if certificate type is server/client
73         if (certType != AUTHORITY)
74         {
75             createRSAPrivateKeyFile();
76         }
77 
78         // restore any existing certificates
79         createCertificates();
80 
81         // watch is not required for authority certificates
82         if (certType != AUTHORITY)
83         {
84             // watch for certificate file create/replace
85             certWatchPtr = std::make_unique<
86                 Watch>(event, certInstallPath, [this]() {
87                 try
88                 {
89                     // if certificate file existing update it
90                     if (!installedCerts.empty())
91                     {
92                         log<level::INFO>("Inotify callback to update "
93                                          "certificate properties");
94                         installedCerts[0]->populateProperties();
95                     }
96                     else
97                     {
98                         log<level::INFO>(
99                             "Inotify callback to create certificate object");
100                         createCertificates();
101                     }
102                 }
103                 catch (const InternalFailure& e)
104                 {
105                     commit<InternalFailure>();
106                 }
107                 catch (const InvalidCertificate& e)
108                 {
109                     commit<InvalidCertificate>();
110                 }
111             });
112         }
113         else
114         {
115             try
116             {
117                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
118                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
119                 {
120                     log<level::NOTICE>(
121                         "Legacy certificate detected, will be installed from: ",
122                         entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
123                     install(singleCertPath);
124                     if (!fs::remove(singleCertPath))
125                     {
126                         log<level::ERR>(
127                             "Unable to remove old certificate from: ",
128                             entry("SINGLE_CERTPATH=%s",
129                                   singleCertPath.c_str()));
130                         elog<InternalFailure>();
131                     }
132                 }
133             }
134             catch (const std::exception& ex)
135             {
136                 log<level::ERR>("Error in restoring legacy certificate",
137                                 entry("ERROR_STR=%s", ex.what()));
138             }
139         }
140     }
141     catch (const std::exception& ex)
142     {
143         log<level::ERR>("Error in certificate manager constructor",
144                         entry("ERROR_STR=%s", ex.what()));
145     }
146 }
147 
148 std::string Manager::install(const std::string filePath)
149 {
150     using NotAllowed =
151         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
152     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
153 
154     if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty())
155     {
156         elog<NotAllowed>(Reason("Certificate already exist"));
157     }
158     else if (certType == phosphor::certs::AUTHORITY &&
159              installedCerts.size() >= AUTHORITY_CERTIFICATES_LIMIT)
160     {
161         elog<NotAllowed>(Reason("Certificates limit reached"));
162     }
163 
164     std::string certObjectPath;
165     if (isCertificateUnique(filePath))
166     {
167         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
168         installedCerts.emplace_back(std::make_unique<Certificate>(
169             bus, certObjectPath, certType, certInstallPath, filePath,
170             certWatchPtr, *this));
171         reloadOrReset(unitToRestart);
172         certIdCounter++;
173     }
174     else
175     {
176         elog<NotAllowed>(Reason("Certificate already exist"));
177     }
178 
179     return certObjectPath;
180 }
181 
182 void Manager::deleteAll()
183 {
184     // TODO: #Issue 4 when a certificate is deleted system auto generates
185     // certificate file. At present we are not supporting creation of
186     // certificate object for the auto-generated certificate file as
187     // deletion if only applicable for REST server and Bmcweb does not allow
188     // deletion of certificates
189     installedCerts.clear();
190     storageUpdate();
191     reloadOrReset(unitToRestart);
192 }
193 
194 void Manager::deleteCertificate(const Certificate* const certificate)
195 {
196     std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
197         std::find_if(installedCerts.begin(), installedCerts.end(),
198                      [certificate](std::unique_ptr<Certificate> const& cert) {
199                          return (cert.get() == certificate);
200                      });
201     if (certIt != installedCerts.end())
202     {
203         installedCerts.erase(certIt);
204         storageUpdate();
205         reloadOrReset(unitToRestart);
206     }
207     else
208     {
209         log<level::ERR>("Certificate does not exist",
210                         entry("ID=%s", certificate->getCertId().c_str()));
211         elog<InternalFailure>();
212     }
213 }
214 
215 void Manager::replaceCertificate(Certificate* const certificate,
216                                  const std::string& filePath)
217 {
218     if (isCertificateUnique(filePath, certificate))
219     {
220         certificate->install(filePath);
221         storageUpdate();
222         reloadOrReset(unitToRestart);
223     }
224     else
225     {
226         using NotAllowed =
227             sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
228         using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
229 
230         elog<NotAllowed>(Reason("Certificate already exist"));
231     }
232 }
233 
234 std::string Manager::generateCSR(
235     std::vector<std::string> alternativeNames, std::string challengePassword,
236     std::string city, std::string commonName, std::string contactPerson,
237     std::string country, std::string email, std::string givenName,
238     std::string initials, int64_t keyBitLength, std::string keyCurveId,
239     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
240     std::string organization, std::string organizationalUnit, std::string state,
241     std::string surname, std::string unstructuredName)
242 {
243     // We support only one CSR.
244     csrPtr.reset(nullptr);
245     auto pid = fork();
246     if (pid == -1)
247     {
248         log<level::ERR>("Error occurred during forking process");
249         report<InternalFailure>();
250     }
251     else if (pid == 0)
252     {
253         try
254         {
255             generateCSRHelper(alternativeNames, challengePassword, city,
256                               commonName, contactPerson, country, email,
257                               givenName, initials, keyBitLength, keyCurveId,
258                               keyPairAlgorithm, keyUsage, organization,
259                               organizationalUnit, state, surname,
260                               unstructuredName);
261             exit(EXIT_SUCCESS);
262         }
263         catch (const InternalFailure& e)
264         {
265             // commit the error reported in child process and exit
266             // Callback method from SDEvent Loop looks for exit status
267             exit(EXIT_FAILURE);
268             commit<InternalFailure>();
269         }
270         catch (const InvalidArgument& e)
271         {
272             // commit the error reported in child process and exit
273             // Callback method from SDEvent Loop looks for exit status
274             exit(EXIT_FAILURE);
275             commit<InvalidArgument>();
276         }
277     }
278     else
279     {
280         using namespace sdeventplus::source;
281         Child::Callback callback = [this](Child& eventSource,
282                                           const siginfo_t* si) {
283             eventSource.set_enabled(Enabled::On);
284             if (si->si_status != 0)
285             {
286                 this->createCSRObject(Status::FAILURE);
287             }
288             else
289             {
290                 this->createCSRObject(Status::SUCCESS);
291             }
292         };
293         try
294         {
295             sigset_t ss;
296             if (sigemptyset(&ss) < 0)
297             {
298                 log<level::ERR>("Unable to initialize signal set");
299                 elog<InternalFailure>();
300             }
301             if (sigaddset(&ss, SIGCHLD) < 0)
302             {
303                 log<level::ERR>("Unable to add signal to signal set");
304                 elog<InternalFailure>();
305             }
306 
307             // Block SIGCHLD first, so that the event loop can handle it
308             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
309             {
310                 log<level::ERR>("Unable to block signal");
311                 elog<InternalFailure>();
312             }
313             if (childPtr)
314             {
315                 childPtr.reset();
316             }
317             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
318                                                std::move(callback));
319         }
320         catch (const InternalFailure& e)
321         {
322             commit<InternalFailure>();
323         }
324     }
325     auto csrObjectPath = objectPath + '/' + "csr";
326     return csrObjectPath;
327 }
328 
329 std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
330 {
331     return installedCerts;
332 }
333 
334 void Manager::generateCSRHelper(
335     std::vector<std::string> alternativeNames, std::string challengePassword,
336     std::string city, std::string commonName, std::string contactPerson,
337     std::string country, std::string email, std::string givenName,
338     std::string initials, int64_t keyBitLength, std::string keyCurveId,
339     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
340     std::string organization, std::string organizationalUnit, std::string state,
341     std::string surname, std::string unstructuredName)
342 {
343     int ret = 0;
344 
345     // set version of x509 req
346     int nVersion = 1;
347     // TODO: Issue#6 need to make version number configurable
348     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
349     ret = X509_REQ_set_version(x509Req.get(), nVersion);
350     if (ret == 0)
351     {
352         log<level::ERR>("Error occured during X509_REQ_set_version call");
353         elog<InternalFailure>();
354     }
355 
356     // set subject of x509 req
357     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
358 
359     if (!alternativeNames.empty())
360     {
361         for (auto& name : alternativeNames)
362         {
363             addEntry(x509Name, "subjectAltName", name);
364         }
365     }
366     addEntry(x509Name, "challengePassword", challengePassword);
367     addEntry(x509Name, "L", city);
368     addEntry(x509Name, "CN", commonName);
369     addEntry(x509Name, "name", contactPerson);
370     addEntry(x509Name, "C", country);
371     addEntry(x509Name, "emailAddress", email);
372     addEntry(x509Name, "GN", givenName);
373     addEntry(x509Name, "initials", initials);
374     addEntry(x509Name, "algorithm", keyPairAlgorithm);
375     if (!keyUsage.empty())
376     {
377         for (auto& usage : keyUsage)
378         {
379             if (isExtendedKeyUsage(usage))
380             {
381                 addEntry(x509Name, "extendedKeyUsage", usage);
382             }
383             else
384             {
385                 addEntry(x509Name, "keyUsage", usage);
386             }
387         }
388     }
389     addEntry(x509Name, "O", organization);
390     addEntry(x509Name, "OU", organizationalUnit);
391     addEntry(x509Name, "ST", state);
392     addEntry(x509Name, "SN", surname);
393     addEntry(x509Name, "unstructuredName", unstructuredName);
394 
395     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
396 
397     log<level::INFO>("Given Key pair algorithm",
398                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
399 
400     // Used EC algorithm as default if user did not give algorithm type.
401     if (keyPairAlgorithm == "RSA")
402         pKey = getRSAKeyPair(keyBitLength);
403     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
404         pKey = generateECKeyPair(keyCurveId);
405     else
406     {
407         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
408                         "RSA and EC only");
409         elog<InvalidArgument>(
410             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
411             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
412     }
413 
414     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
415     if (ret == 0)
416     {
417         log<level::ERR>("Error occured while setting Public key");
418         elog<InternalFailure>();
419     }
420 
421     // Write private key to file
422     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
423 
424     // set sign key of x509 req
425     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
426     if (ret == 0)
427     {
428         log<level::ERR>("Error occured while signing key of x509");
429         elog<InternalFailure>();
430     }
431 
432     log<level::INFO>("Writing CSR to file");
433     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
434     writeCSR(csrFilePath.string(), x509Req);
435 }
436 
437 bool Manager::isExtendedKeyUsage(const std::string& usage)
438 {
439     const static std::array<const char*, 6> usageList = {
440         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
441         "Timestamping",         "CodeSigning",          "EmailProtection"};
442     auto it = std::find_if(
443         usageList.begin(), usageList.end(),
444         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
445     return it != usageList.end();
446 }
447 EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
448 {
449     int ret = 0;
450     // generate rsa key
451     BIGNUM_Ptr bne(BN_new(), ::BN_free);
452     ret = BN_set_word(bne.get(), RSA_F4);
453     if (ret == 0)
454     {
455         log<level::ERR>("Error occured during BN_set_word call");
456         elog<InternalFailure>();
457     }
458 
459     int64_t keyBitLen = keyBitLength;
460     // set keybit length to default value if not set
461     if (keyBitLen <= 0)
462     {
463         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
464         log<level::INFO>(
465             "KeyBitLength is not given.Hence, using default KeyBitLength",
466             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
467         keyBitLen = DEFAULT_KEYBITLENGTH;
468     }
469     RSA* rsa = RSA_new();
470     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
471     if (ret != 1)
472     {
473         free(rsa);
474         log<level::ERR>("Error occured during RSA_generate_key_ex call",
475                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
476         elog<InternalFailure>();
477     }
478 
479     // set public key of x509 req
480     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
481     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
482     if (ret == 0)
483     {
484         free(rsa);
485         log<level::ERR>("Error occured during assign rsa key into EVP");
486         elog<InternalFailure>();
487     }
488 
489     return pKey;
490 }
491 
492 EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
493 {
494     std::string curId(curveId);
495 
496     if (curId.empty())
497     {
498         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
499         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
500         log<level::INFO>(
501             "KeyCurveId is not given. Hence using default curve id",
502             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
503         curId = DEFAULT_KEYCURVEID;
504     }
505 
506     int ecGrp = OBJ_txt2nid(curId.c_str());
507 
508     if (ecGrp == NID_undef)
509     {
510         log<level::ERR>(
511             "Error occured during convert the curve id string format into NID",
512             entry("KEYCURVEID=%s", curId.c_str()));
513         elog<InternalFailure>();
514     }
515 
516     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
517 
518     if (ecKey == NULL)
519     {
520         log<level::ERR>(
521             "Error occured during create the EC_Key object from NID",
522             entry("ECGROUP=%d", ecGrp));
523         elog<InternalFailure>();
524     }
525 
526     // If you want to save a key and later load it with
527     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
528     // flag on the key.
529     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
530 
531     int ret = EC_KEY_generate_key(ecKey);
532 
533     if (ret == 0)
534     {
535         EC_KEY_free(ecKey);
536         log<level::ERR>("Error occured during generate EC key");
537         elog<InternalFailure>();
538     }
539 
540     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
541     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
542     if (ret == 0)
543     {
544         EC_KEY_free(ecKey);
545         log<level::ERR>("Error occured during assign EC Key into EVP");
546         elog<InternalFailure>();
547     }
548 
549     return pKey;
550 }
551 
552 void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
553                               const std::string& privKeyFileName)
554 {
555     log<level::INFO>("Writing private key to file");
556     // write private key to file
557     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
558 
559     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
560     if (fp == NULL)
561     {
562         log<level::ERR>("Error occured creating private key file");
563         elog<InternalFailure>();
564     }
565     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
566     std::fclose(fp);
567     if (ret == 0)
568     {
569         log<level::ERR>("Error occured while writing private key to file");
570         elog<InternalFailure>();
571     }
572 }
573 
574 void Manager::addEntry(X509_NAME* x509Name, const char* field,
575                        const std::string& bytes)
576 {
577     if (bytes.empty())
578     {
579         return;
580     }
581     int ret = X509_NAME_add_entry_by_txt(
582         x509Name, field, MBSTRING_ASC,
583         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
584     if (ret != 1)
585     {
586         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
587                         entry("VALUE=%s", bytes.c_str()));
588         elog<InternalFailure>();
589     }
590 }
591 
592 void Manager::createCSRObject(const Status& status)
593 {
594     if (csrPtr)
595     {
596         csrPtr.reset(nullptr);
597     }
598     auto csrObjectPath = objectPath + '/' + "csr";
599     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
600                                    certInstallPath.c_str(), status);
601 }
602 
603 void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
604 {
605     if (fs::exists(filePath))
606     {
607         log<level::INFO>("Removing the existing file",
608                          entry("FILENAME=%s", filePath.c_str()));
609         if (!fs::remove(filePath.c_str()))
610         {
611             log<level::ERR>("Unable to remove the file",
612                             entry("FILENAME=%s", filePath.c_str()));
613             elog<InternalFailure>();
614         }
615     }
616 
617     FILE* fp = NULL;
618 
619     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
620     {
621         log<level::ERR>("Error opening the file to write the CSR",
622                         entry("FILENAME=%s", filePath.c_str()));
623         elog<InternalFailure>();
624     }
625 
626     int rc = PEM_write_X509_REQ(fp, x509Req.get());
627     if (!rc)
628     {
629         log<level::ERR>("PEM write routine failed",
630                         entry("FILENAME=%s", filePath.c_str()));
631         std::fclose(fp);
632         elog<InternalFailure>();
633     }
634     std::fclose(fp);
635 }
636 
637 void Manager::createCertificates()
638 {
639     auto certObjectPath = objectPath + '/';
640 
641     if (certType == phosphor::certs::AUTHORITY)
642     {
643         // Check whether install path is a directory.
644         if (!fs::is_directory(certInstallPath))
645         {
646             log<level::ERR>("Certificate installation path exists and it is "
647                             "not a directory");
648             elog<InternalFailure>();
649             return;
650         }
651 
652         for (auto& path : fs::directory_iterator(certInstallPath))
653         {
654             try
655             {
656                 // Assume here any regular file located in certificate directory
657                 // contains certificates body. Do not want to use soft links
658                 // would add value.
659                 if (fs::is_regular_file(path))
660                 {
661                     installedCerts.emplace_back(std::make_unique<Certificate>(
662                         bus, certObjectPath + std::to_string(certIdCounter++),
663                         certType, certInstallPath, path.path(), certWatchPtr,
664                         *this));
665                 }
666             }
667             catch (const InternalFailure& e)
668             {
669                 report<InternalFailure>();
670             }
671             catch (const InvalidCertificate& e)
672             {
673                 report<InvalidCertificate>(
674                     Reason("Existing certificate file is corrupted"));
675             }
676         }
677     }
678     else if (fs::exists(certInstallPath))
679     {
680         try
681         {
682             installedCerts.emplace_back(std::make_unique<Certificate>(
683                 bus, certObjectPath + '1', certType, certInstallPath,
684                 certInstallPath, certWatchPtr, *this));
685         }
686         catch (const InternalFailure& e)
687         {
688             report<InternalFailure>();
689         }
690         catch (const InvalidCertificate& e)
691         {
692             report<InvalidCertificate>(
693                 Reason("Existing certificate file is corrupted"));
694         }
695     }
696 }
697 
698 void Manager::createRSAPrivateKeyFile()
699 {
700     fs::path rsaPrivateKeyFileName =
701         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
702 
703     try
704     {
705         if (!fs::exists(rsaPrivateKeyFileName))
706         {
707             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
708                             RSA_PRIV_KEY_FILE_NAME);
709         }
710     }
711     catch (const InternalFailure& e)
712     {
713         report<InternalFailure>();
714     }
715 }
716 
717 EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
718 {
719     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
720     {
721         log<level::ERR>(
722             "Given Key bit length is not supported",
723             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
724             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
725         elog<InvalidArgument>(
726             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
727             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
728     }
729     fs::path rsaPrivateKeyFileName =
730         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
731 
732     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
733     if (!privateKeyFile)
734     {
735         log<level::ERR>("Unable to open RSA private key file to read",
736                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
737                         entry("ERRORREASON=%s", strerror(errno)));
738         elog<InternalFailure>();
739     }
740 
741     EVP_PKEY_Ptr privateKey(
742         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
743         ::EVP_PKEY_free);
744     std::fclose(privateKeyFile);
745 
746     if (!privateKey)
747     {
748         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
749         elog<InternalFailure>();
750     }
751     return privateKey;
752 }
753 
754 void Manager::storageUpdate()
755 {
756     if (certType == phosphor::certs::AUTHORITY)
757     {
758         // Remove symbolic links in the certificate directory
759         for (auto& certPath : fs::directory_iterator(certInstallPath))
760         {
761             try
762             {
763                 if (fs::is_symlink(certPath))
764                 {
765                     fs::remove(certPath);
766                 }
767             }
768             catch (const std::exception& e)
769             {
770                 log<level::ERR>(
771                     "Failed to remove symlink for certificate",
772                     entry("ERR=%s", e.what()),
773                     entry("SYMLINK=%s", certPath.path().string().c_str()));
774                 elog<InternalFailure>();
775             }
776         }
777     }
778 
779     for (const auto& cert : installedCerts)
780     {
781         cert->storageUpdate();
782     }
783 }
784 
785 void Manager::reloadOrReset(const UnitsToRestart& unit)
786 {
787     if (!unit.empty())
788     {
789         try
790         {
791             constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
792             constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
793             constexpr auto SYSTEMD_INTERFACE =
794                 "org.freedesktop.systemd1.Manager";
795 
796             auto method =
797                 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
798                                     SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
799             method.append(unit, "replace");
800             bus.call_noreply(method);
801         }
802         catch (const sdbusplus::exception::exception& e)
803         {
804             log<level::ERR>("Failed to reload or restart service",
805                             entry("ERR=%s", e.what()),
806                             entry("UNIT=%s", unit.c_str()));
807             elog<InternalFailure>();
808         }
809     }
810 }
811 
812 bool Manager::isCertificateUnique(const std::string& filePath,
813                                   const Certificate* const certToDrop)
814 {
815     if (std::any_of(
816             installedCerts.begin(), installedCerts.end(),
817             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
818                 return cert.get() != certToDrop && cert->isSame(filePath);
819             }))
820     {
821         return false;
822     }
823     else
824     {
825         return true;
826     }
827 }
828 
829 } // namespace certs
830 } // namespace phosphor
831