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     }
271     else
272     {
273         using namespace sdeventplus::source;
274         Child::Callback callback = [this](Child& eventSource,
275                                           const siginfo_t* si) {
276             eventSource.set_enabled(Enabled::On);
277             if (si->si_status != 0)
278             {
279                 this->createCSRObject(Status::FAILURE);
280             }
281             else
282             {
283                 this->createCSRObject(Status::SUCCESS);
284             }
285         };
286         try
287         {
288             sigset_t ss;
289             if (sigemptyset(&ss) < 0)
290             {
291                 log<level::ERR>("Unable to initialize signal set");
292                 elog<InternalFailure>();
293             }
294             if (sigaddset(&ss, SIGCHLD) < 0)
295             {
296                 log<level::ERR>("Unable to add signal to signal set");
297                 elog<InternalFailure>();
298             }
299 
300             // Block SIGCHLD first, so that the event loop can handle it
301             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
302             {
303                 log<level::ERR>("Unable to block signal");
304                 elog<InternalFailure>();
305             }
306             if (childPtr)
307             {
308                 childPtr.reset();
309             }
310             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
311                                                std::move(callback));
312         }
313         catch (const InternalFailure& e)
314         {
315             commit<InternalFailure>();
316         }
317     }
318     auto csrObjectPath = objectPath + '/' + "csr";
319     return csrObjectPath;
320 }
321 
322 std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
323 {
324     return installedCerts;
325 }
326 
327 void Manager::generateCSRHelper(
328     std::vector<std::string> alternativeNames, std::string challengePassword,
329     std::string city, std::string commonName, std::string contactPerson,
330     std::string country, std::string email, std::string givenName,
331     std::string initials, int64_t keyBitLength, std::string keyCurveId,
332     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
333     std::string organization, std::string organizationalUnit, std::string state,
334     std::string surname, std::string unstructuredName)
335 {
336     int ret = 0;
337 
338     // set version of x509 req
339     int nVersion = 1;
340     // TODO: Issue#6 need to make version number configurable
341     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
342     ret = X509_REQ_set_version(x509Req.get(), nVersion);
343     if (ret == 0)
344     {
345         log<level::ERR>("Error occured during X509_REQ_set_version call");
346         elog<InternalFailure>();
347     }
348 
349     // set subject of x509 req
350     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
351 
352     if (!alternativeNames.empty())
353     {
354         for (auto& name : alternativeNames)
355         {
356             addEntry(x509Name, "subjectAltName", name);
357         }
358     }
359     addEntry(x509Name, "challengePassword", challengePassword);
360     addEntry(x509Name, "L", city);
361     addEntry(x509Name, "CN", commonName);
362     addEntry(x509Name, "name", contactPerson);
363     addEntry(x509Name, "C", country);
364     addEntry(x509Name, "emailAddress", email);
365     addEntry(x509Name, "GN", givenName);
366     addEntry(x509Name, "initials", initials);
367     addEntry(x509Name, "algorithm", keyPairAlgorithm);
368     if (!keyUsage.empty())
369     {
370         for (auto& usage : keyUsage)
371         {
372             if (isExtendedKeyUsage(usage))
373             {
374                 addEntry(x509Name, "extendedKeyUsage", usage);
375             }
376             else
377             {
378                 addEntry(x509Name, "keyUsage", usage);
379             }
380         }
381     }
382     addEntry(x509Name, "O", organization);
383     addEntry(x509Name, "ST", state);
384     addEntry(x509Name, "SN", surname);
385     addEntry(x509Name, "unstructuredName", unstructuredName);
386 
387     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
388 
389     log<level::INFO>("Given Key pair algorithm",
390                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
391 
392     // Used EC algorithm as default if user did not give algorithm type.
393     if (keyPairAlgorithm == "RSA")
394         pKey = getRSAKeyPair(keyBitLength);
395     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
396         pKey = generateECKeyPair(keyCurveId);
397     else
398     {
399         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
400                         "RSA and EC only");
401         elog<InvalidArgument>(
402             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
403             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
404     }
405 
406     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
407     if (ret == 0)
408     {
409         log<level::ERR>("Error occured while setting Public key");
410         elog<InternalFailure>();
411     }
412 
413     // Write private key to file
414     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
415 
416     // set sign key of x509 req
417     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
418     if (ret == 0)
419     {
420         log<level::ERR>("Error occured while signing key of x509");
421         elog<InternalFailure>();
422     }
423 
424     log<level::INFO>("Writing CSR to file");
425     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
426     writeCSR(csrFilePath.string(), x509Req);
427 }
428 
429 bool Manager::isExtendedKeyUsage(const std::string& usage)
430 {
431     const static std::array<const char*, 6> usageList = {
432         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
433         "Timestamping",         "CodeSigning",          "EmailProtection"};
434     auto it = std::find_if(
435         usageList.begin(), usageList.end(),
436         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
437     return it != usageList.end();
438 }
439 EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
440 {
441     int ret = 0;
442     // generate rsa key
443     BIGNUM_Ptr bne(BN_new(), ::BN_free);
444     ret = BN_set_word(bne.get(), RSA_F4);
445     if (ret == 0)
446     {
447         log<level::ERR>("Error occured during BN_set_word call");
448         elog<InternalFailure>();
449     }
450 
451     int64_t keyBitLen = keyBitLength;
452     // set keybit length to default value if not set
453     if (keyBitLen <= 0)
454     {
455         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
456         log<level::INFO>(
457             "KeyBitLength is not given.Hence, using default KeyBitLength",
458             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
459         keyBitLen = DEFAULT_KEYBITLENGTH;
460     }
461     RSA* rsa = RSA_new();
462     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
463     if (ret != 1)
464     {
465         free(rsa);
466         log<level::ERR>("Error occured during RSA_generate_key_ex call",
467                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
468         elog<InternalFailure>();
469     }
470 
471     // set public key of x509 req
472     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
473     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
474     if (ret == 0)
475     {
476         free(rsa);
477         log<level::ERR>("Error occured during assign rsa key into EVP");
478         elog<InternalFailure>();
479     }
480 
481     return pKey;
482 }
483 
484 EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
485 {
486     std::string curId(curveId);
487 
488     if (curId.empty())
489     {
490         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
491         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
492         log<level::INFO>(
493             "KeyCurveId is not given. Hence using default curve id",
494             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
495         curId = DEFAULT_KEYCURVEID;
496     }
497 
498     int ecGrp = OBJ_txt2nid(curId.c_str());
499 
500     if (ecGrp == NID_undef)
501     {
502         log<level::ERR>(
503             "Error occured during convert the curve id string format into NID",
504             entry("KEYCURVEID=%s", curId.c_str()));
505         elog<InternalFailure>();
506     }
507 
508     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
509 
510     if (ecKey == NULL)
511     {
512         log<level::ERR>(
513             "Error occured during create the EC_Key object from NID",
514             entry("ECGROUP=%d", ecGrp));
515         elog<InternalFailure>();
516     }
517 
518     // If you want to save a key and later load it with
519     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
520     // flag on the key.
521     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
522 
523     int ret = EC_KEY_generate_key(ecKey);
524 
525     if (ret == 0)
526     {
527         EC_KEY_free(ecKey);
528         log<level::ERR>("Error occured during generate EC key");
529         elog<InternalFailure>();
530     }
531 
532     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
533     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
534     if (ret == 0)
535     {
536         EC_KEY_free(ecKey);
537         log<level::ERR>("Error occured during assign EC Key into EVP");
538         elog<InternalFailure>();
539     }
540 
541     return pKey;
542 }
543 
544 void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
545                               const std::string& privKeyFileName)
546 {
547     log<level::INFO>("Writing private key to file");
548     // write private key to file
549     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
550 
551     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
552     if (fp == NULL)
553     {
554         log<level::ERR>("Error occured creating private key file");
555         elog<InternalFailure>();
556     }
557     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
558     std::fclose(fp);
559     if (ret == 0)
560     {
561         log<level::ERR>("Error occured while writing private key to file");
562         elog<InternalFailure>();
563     }
564 }
565 
566 void Manager::addEntry(X509_NAME* x509Name, const char* field,
567                        const std::string& bytes)
568 {
569     if (bytes.empty())
570     {
571         return;
572     }
573     int ret = X509_NAME_add_entry_by_txt(
574         x509Name, field, MBSTRING_ASC,
575         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
576     if (ret != 1)
577     {
578         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
579                         entry("VALUE=%s", bytes.c_str()));
580         elog<InternalFailure>();
581     }
582 }
583 
584 void Manager::createCSRObject(const Status& status)
585 {
586     if (csrPtr)
587     {
588         csrPtr.reset(nullptr);
589     }
590     auto csrObjectPath = objectPath + '/' + "csr";
591     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
592                                    certInstallPath.c_str(), status);
593 }
594 
595 void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
596 {
597     if (fs::exists(filePath))
598     {
599         log<level::INFO>("Removing the existing file",
600                          entry("FILENAME=%s", filePath.c_str()));
601         if (!fs::remove(filePath.c_str()))
602         {
603             log<level::ERR>("Unable to remove the file",
604                             entry("FILENAME=%s", filePath.c_str()));
605             elog<InternalFailure>();
606         }
607     }
608 
609     FILE* fp = NULL;
610 
611     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
612     {
613         log<level::ERR>("Error opening the file to write the CSR",
614                         entry("FILENAME=%s", filePath.c_str()));
615         elog<InternalFailure>();
616     }
617 
618     int rc = PEM_write_X509_REQ(fp, x509Req.get());
619     if (!rc)
620     {
621         log<level::ERR>("PEM write routine failed",
622                         entry("FILENAME=%s", filePath.c_str()));
623         std::fclose(fp);
624         elog<InternalFailure>();
625     }
626     std::fclose(fp);
627 }
628 
629 void Manager::createCertificates()
630 {
631     auto certObjectPath = objectPath + '/';
632 
633     if (certType == phosphor::certs::AUTHORITY)
634     {
635         // Check whether install path is a directory.
636         if (!fs::is_directory(certInstallPath))
637         {
638             log<level::ERR>("Certificate installation path exists and it is "
639                             "not a directory");
640             elog<InternalFailure>();
641             return;
642         }
643 
644         for (auto& path : fs::directory_iterator(certInstallPath))
645         {
646             try
647             {
648                 // Assume here any regular file located in certificate directory
649                 // contains certificates body. Do not want to use soft links
650                 // would add value.
651                 if (fs::is_regular_file(path))
652                 {
653                     installedCerts.emplace_back(std::make_unique<Certificate>(
654                         bus, certObjectPath + std::to_string(certIdCounter++),
655                         certType, certInstallPath, path.path(), certWatchPtr,
656                         *this));
657                 }
658             }
659             catch (const InternalFailure& e)
660             {
661                 report<InternalFailure>();
662             }
663             catch (const InvalidCertificate& e)
664             {
665                 report<InvalidCertificate>(
666                     Reason("Existing certificate file is corrupted"));
667             }
668         }
669     }
670     else if (fs::exists(certInstallPath))
671     {
672         try
673         {
674             installedCerts.emplace_back(std::make_unique<Certificate>(
675                 bus, certObjectPath + '1', certType, certInstallPath,
676                 certInstallPath, certWatchPtr, *this));
677         }
678         catch (const InternalFailure& e)
679         {
680             report<InternalFailure>();
681         }
682         catch (const InvalidCertificate& e)
683         {
684             report<InvalidCertificate>(
685                 Reason("Existing certificate file is corrupted"));
686         }
687     }
688 }
689 
690 void Manager::createRSAPrivateKeyFile()
691 {
692     fs::path rsaPrivateKeyFileName =
693         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
694 
695     try
696     {
697         if (!fs::exists(rsaPrivateKeyFileName))
698         {
699             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
700                             RSA_PRIV_KEY_FILE_NAME);
701         }
702     }
703     catch (const InternalFailure& e)
704     {
705         report<InternalFailure>();
706     }
707 }
708 
709 EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
710 {
711     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
712     {
713         log<level::ERR>(
714             "Given Key bit length is not supported",
715             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
716             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
717         elog<InvalidArgument>(
718             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
719             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
720     }
721     fs::path rsaPrivateKeyFileName =
722         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
723 
724     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
725     if (!privateKeyFile)
726     {
727         log<level::ERR>("Unable to open RSA private key file to read",
728                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
729                         entry("ERRORREASON=%s", strerror(errno)));
730         elog<InternalFailure>();
731     }
732 
733     EVP_PKEY_Ptr privateKey(
734         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
735         ::EVP_PKEY_free);
736     std::fclose(privateKeyFile);
737 
738     if (!privateKey)
739     {
740         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
741         elog<InternalFailure>();
742     }
743     return privateKey;
744 }
745 
746 void Manager::storageUpdate()
747 {
748     if (certType == phosphor::certs::AUTHORITY)
749     {
750         // Remove symbolic links in the certificate directory
751         for (auto& certPath : fs::directory_iterator(certInstallPath))
752         {
753             try
754             {
755                 if (fs::is_symlink(certPath))
756                 {
757                     fs::remove(certPath);
758                 }
759             }
760             catch (const std::exception& e)
761             {
762                 log<level::ERR>(
763                     "Failed to remove symlink for certificate",
764                     entry("ERR=%s", e.what()),
765                     entry("SYMLINK=%s", certPath.path().string().c_str()));
766                 elog<InternalFailure>();
767             }
768         }
769     }
770 
771     for (const auto& cert : installedCerts)
772     {
773         cert->storageUpdate();
774     }
775 }
776 
777 void Manager::reloadOrReset(const UnitsToRestart& unit)
778 {
779     if (!unit.empty())
780     {
781         try
782         {
783             constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
784             constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
785             constexpr auto SYSTEMD_INTERFACE =
786                 "org.freedesktop.systemd1.Manager";
787 
788             auto method =
789                 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
790                                     SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
791             method.append(unit, "replace");
792             bus.call_noreply(method);
793         }
794         catch (const sdbusplus::exception::SdBusError& e)
795         {
796             log<level::ERR>("Failed to reload or restart service",
797                             entry("ERR=%s", e.what()),
798                             entry("UNIT=%s", unit.c_str()));
799             elog<InternalFailure>();
800         }
801     }
802 }
803 
804 bool Manager::isCertificateUnique(const std::string& filePath,
805                                   const Certificate* const certToDrop)
806 {
807     if (std::any_of(
808             installedCerts.begin(), installedCerts.end(),
809             [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
810                 return cert.get() != certToDrop && cert->isSame(filePath);
811             }))
812     {
813         return false;
814     }
815     else
816     {
817         return true;
818     }
819 }
820 
821 } // namespace certs
822 } // namespace phosphor
823