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 (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 (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, "ST", state);
391     addEntry(x509Name, "SN", surname);
392     addEntry(x509Name, "unstructuredName", unstructuredName);
393 
394     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
395 
396     log<level::INFO>("Given Key pair algorithm",
397                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
398 
399     // Used EC algorithm as default if user did not give algorithm type.
400     if (keyPairAlgorithm == "RSA")
401         pKey = getRSAKeyPair(keyBitLength);
402     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
403         pKey = generateECKeyPair(keyCurveId);
404     else
405     {
406         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
407                         "RSA and EC only");
408         elog<InvalidArgument>(
409             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
410             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
411     }
412 
413     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
414     if (ret == 0)
415     {
416         log<level::ERR>("Error occured while setting Public key");
417         elog<InternalFailure>();
418     }
419 
420     // Write private key to file
421     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
422 
423     // set sign key of x509 req
424     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
425     if (ret == 0)
426     {
427         log<level::ERR>("Error occured while signing key of x509");
428         elog<InternalFailure>();
429     }
430 
431     log<level::INFO>("Writing CSR to file");
432     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
433     writeCSR(csrFilePath.string(), x509Req);
434 }
435 
436 bool Manager::isExtendedKeyUsage(const std::string& usage)
437 {
438     const static std::array<const char*, 6> usageList = {
439         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
440         "Timestamping",         "CodeSigning",          "EmailProtection"};
441     auto it = std::find_if(
442         usageList.begin(), usageList.end(),
443         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
444     return it != usageList.end();
445 }
446 EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
447 {
448     int ret = 0;
449     // generate rsa key
450     BIGNUM_Ptr bne(BN_new(), ::BN_free);
451     ret = BN_set_word(bne.get(), RSA_F4);
452     if (ret == 0)
453     {
454         log<level::ERR>("Error occured during BN_set_word call");
455         elog<InternalFailure>();
456     }
457 
458     int64_t keyBitLen = keyBitLength;
459     // set keybit length to default value if not set
460     if (keyBitLen <= 0)
461     {
462         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
463         log<level::INFO>(
464             "KeyBitLength is not given.Hence, using default KeyBitLength",
465             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
466         keyBitLen = DEFAULT_KEYBITLENGTH;
467     }
468     RSA* rsa = RSA_new();
469     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
470     if (ret != 1)
471     {
472         free(rsa);
473         log<level::ERR>("Error occured during RSA_generate_key_ex call",
474                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
475         elog<InternalFailure>();
476     }
477 
478     // set public key of x509 req
479     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
480     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
481     if (ret == 0)
482     {
483         free(rsa);
484         log<level::ERR>("Error occured during assign rsa key into EVP");
485         elog<InternalFailure>();
486     }
487 
488     return pKey;
489 }
490 
491 EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
492 {
493     std::string curId(curveId);
494 
495     if (curId.empty())
496     {
497         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
498         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
499         log<level::INFO>(
500             "KeyCurveId is not given. Hence using default curve id",
501             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
502         curId = DEFAULT_KEYCURVEID;
503     }
504 
505     int ecGrp = OBJ_txt2nid(curId.c_str());
506 
507     if (ecGrp == NID_undef)
508     {
509         log<level::ERR>(
510             "Error occured during convert the curve id string format into NID",
511             entry("KEYCURVEID=%s", curId.c_str()));
512         elog<InternalFailure>();
513     }
514 
515     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
516 
517     if (ecKey == NULL)
518     {
519         log<level::ERR>(
520             "Error occured during create the EC_Key object from NID",
521             entry("ECGROUP=%d", ecGrp));
522         elog<InternalFailure>();
523     }
524 
525     // If you want to save a key and later load it with
526     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
527     // flag on the key.
528     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
529 
530     int ret = EC_KEY_generate_key(ecKey);
531 
532     if (ret == 0)
533     {
534         EC_KEY_free(ecKey);
535         log<level::ERR>("Error occured during generate EC key");
536         elog<InternalFailure>();
537     }
538 
539     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
540     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
541     if (ret == 0)
542     {
543         EC_KEY_free(ecKey);
544         log<level::ERR>("Error occured during assign EC Key into EVP");
545         elog<InternalFailure>();
546     }
547 
548     return pKey;
549 }
550 
551 void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
552                               const std::string& privKeyFileName)
553 {
554     log<level::INFO>("Writing private key to file");
555     // write private key to file
556     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
557 
558     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
559     if (fp == NULL)
560     {
561         log<level::ERR>("Error occured creating private key file");
562         elog<InternalFailure>();
563     }
564     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
565     std::fclose(fp);
566     if (ret == 0)
567     {
568         log<level::ERR>("Error occured while writing private key to file");
569         elog<InternalFailure>();
570     }
571 }
572 
573 void Manager::addEntry(X509_NAME* x509Name, const char* field,
574                        const std::string& bytes)
575 {
576     if (bytes.empty())
577     {
578         return;
579     }
580     int ret = X509_NAME_add_entry_by_txt(
581         x509Name, field, MBSTRING_ASC,
582         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
583     if (ret != 1)
584     {
585         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
586                         entry("VALUE=%s", bytes.c_str()));
587         elog<InternalFailure>();
588     }
589 }
590 
591 void Manager::createCSRObject(const Status& status)
592 {
593     if (csrPtr)
594     {
595         csrPtr.reset(nullptr);
596     }
597     auto csrObjectPath = objectPath + '/' + "csr";
598     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
599                                    certInstallPath.c_str(), status);
600 }
601 
602 void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
603 {
604     if (fs::exists(filePath))
605     {
606         log<level::INFO>("Removing the existing file",
607                          entry("FILENAME=%s", filePath.c_str()));
608         if (!fs::remove(filePath.c_str()))
609         {
610             log<level::ERR>("Unable to remove the file",
611                             entry("FILENAME=%s", filePath.c_str()));
612             elog<InternalFailure>();
613         }
614     }
615 
616     FILE* fp = NULL;
617 
618     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
619     {
620         log<level::ERR>("Error opening the file to write the CSR",
621                         entry("FILENAME=%s", filePath.c_str()));
622         elog<InternalFailure>();
623     }
624 
625     int rc = PEM_write_X509_REQ(fp, x509Req.get());
626     if (!rc)
627     {
628         log<level::ERR>("PEM write routine failed",
629                         entry("FILENAME=%s", filePath.c_str()));
630         std::fclose(fp);
631         elog<InternalFailure>();
632     }
633     std::fclose(fp);
634 }
635 
636 void Manager::createCertificates()
637 {
638     auto certObjectPath = objectPath + '/';
639 
640     if (certType == phosphor::certs::AUTHORITY)
641     {
642         // Check whether install path is a directory.
643         if (!fs::is_directory(certInstallPath))
644         {
645             log<level::ERR>("Certificate installation path exists and it is "
646                             "not a directory");
647             elog<InternalFailure>();
648             return;
649         }
650 
651         for (auto& path : fs::directory_iterator(certInstallPath))
652         {
653             try
654             {
655                 // Assume here any regular file located in certificate directory
656                 // contains certificates body. Do not want to use soft links
657                 // would add value.
658                 if (fs::is_regular_file(path))
659                 {
660                     installedCerts.emplace_back(std::make_unique<Certificate>(
661                         bus, certObjectPath + std::to_string(certIdCounter++),
662                         certType, certInstallPath, path.path(), certWatchPtr,
663                         *this));
664                 }
665             }
666             catch (const InternalFailure& e)
667             {
668                 report<InternalFailure>();
669             }
670             catch (const InvalidCertificate& e)
671             {
672                 report<InvalidCertificate>(
673                     Reason("Existing certificate file is corrupted"));
674             }
675         }
676     }
677     else if (fs::exists(certInstallPath))
678     {
679         try
680         {
681             installedCerts.emplace_back(std::make_unique<Certificate>(
682                 bus, certObjectPath + '1', certType, certInstallPath,
683                 certInstallPath, certWatchPtr, *this));
684         }
685         catch (const InternalFailure& e)
686         {
687             report<InternalFailure>();
688         }
689         catch (const InvalidCertificate& e)
690         {
691             report<InvalidCertificate>(
692                 Reason("Existing certificate file is corrupted"));
693         }
694     }
695 }
696 
697 void Manager::createRSAPrivateKeyFile()
698 {
699     fs::path rsaPrivateKeyFileName =
700         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
701 
702     try
703     {
704         if (!fs::exists(rsaPrivateKeyFileName))
705         {
706             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
707                             RSA_PRIV_KEY_FILE_NAME);
708         }
709     }
710     catch (const InternalFailure& e)
711     {
712         report<InternalFailure>();
713     }
714 }
715 
716 EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
717 {
718     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
719     {
720         log<level::ERR>(
721             "Given Key bit length is not supported",
722             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
723             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
724         elog<InvalidArgument>(
725             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
726             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
727     }
728     fs::path rsaPrivateKeyFileName =
729         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
730 
731     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
732     if (!privateKeyFile)
733     {
734         log<level::ERR>("Unable to open RSA private key file to read",
735                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
736                         entry("ERRORREASON=%s", strerror(errno)));
737         elog<InternalFailure>();
738     }
739 
740     EVP_PKEY_Ptr privateKey(
741         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
742         ::EVP_PKEY_free);
743     std::fclose(privateKeyFile);
744 
745     if (!privateKey)
746     {
747         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
748         elog<InternalFailure>();
749     }
750     return privateKey;
751 }
752 
753 void Manager::storageUpdate()
754 {
755     if (certType == phosphor::certs::AUTHORITY)
756     {
757         // Remove symbolic links in the certificate directory
758         for (auto& certPath : fs::directory_iterator(certInstallPath))
759         {
760             try
761             {
762                 if (fs::is_symlink(certPath))
763                 {
764                     fs::remove(certPath);
765                 }
766             }
767             catch (const std::exception& e)
768             {
769                 log<level::ERR>(
770                     "Failed to remove symlink for certificate",
771                     entry("ERR=%s", e.what()),
772                     entry("SYMLINK=%s", certPath.path().string().c_str()));
773                 elog<InternalFailure>();
774             }
775         }
776     }
777 
778     for (const auto& cert : installedCerts)
779     {
780         cert->storageUpdate();
781     }
782 }
783 
784 void Manager::reloadOrReset(const UnitsToRestart& unit)
785 {
786     if (!unit.empty())
787     {
788         try
789         {
790             constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
791             constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
792             constexpr auto SYSTEMD_INTERFACE =
793                 "org.freedesktop.systemd1.Manager";
794 
795             auto method =
796                 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
797                                     SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
798             method.append(unit, "replace");
799             bus.call_noreply(method);
800         }
801         catch (const sdbusplus::exception::SdBusError& e)
802         {
803             log<level::ERR>("Failed to reload or restart service",
804                             entry("ERR=%s", e.what()),
805                             entry("UNIT=%s", unit.c_str()));
806             elog<InternalFailure>();
807         }
808     }
809 }
810 
811 bool Manager::isCertificateUnique(const std::string& filePath,
812                                   const Certificate* const certToDrop)
813 {
814     if (std::any_of(
815             installedCerts.begin(), installedCerts.end(),
816             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
817                 return cert.get() != certToDrop && cert->isSame(filePath);
818             }))
819     {
820         return false;
821     }
822     else
823     {
824         return true;
825     }
826 }
827 
828 } // namespace certs
829 } // namespace phosphor
830