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