xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision f2646271e5fc66e4c5f3f8bfd6eeb68b6be3f103)
1 #include "config.h"
2 
3 #include "certs_manager.hpp"
4 
5 #include "x509_utils.hpp"
6 
7 #include <openssl/asn1.h>
8 #include <openssl/bn.h>
9 #include <openssl/ec.h>
10 #include <openssl/evp.h>
11 #include <openssl/obj_mac.h>
12 #include <openssl/objects.h>
13 #include <openssl/opensslv.h>
14 #include <openssl/pem.h>
15 #include <openssl/rsa.h>
16 #include <unistd.h>
17 
18 #include <phosphor-logging/elog-errors.hpp>
19 #include <phosphor-logging/elog.hpp>
20 #include <phosphor-logging/lg2.hpp>
21 #include <sdbusplus/bus.hpp>
22 #include <sdbusplus/exception.hpp>
23 #include <sdbusplus/message.hpp>
24 #include <sdeventplus/source/base.hpp>
25 #include <sdeventplus/source/child.hpp>
26 #include <xyz/openbmc_project/Certs/error.hpp>
27 #include <xyz/openbmc_project/Common/error.hpp>
28 
29 #include <algorithm>
30 #include <array>
31 #include <cerrno>
32 #include <chrono>
33 #include <csignal>
34 #include <cstdio>
35 #include <cstdlib>
36 #include <cstring>
37 #include <exception>
38 #include <fstream>
39 #include <utility>
40 
41 namespace phosphor::certs
42 {
43 namespace
44 {
45 namespace fs = std::filesystem;
46 using ::phosphor::logging::commit;
47 using ::phosphor::logging::elog;
48 using ::phosphor::logging::report;
49 
50 using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
51 using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
52 using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
53 using NotAllowedReason =
54     ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
55 using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
56     Certs::InvalidCertificate::REASON;
57 using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
58 using Argument =
59     ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
60 
61 // RAII support for openSSL functions.
62 using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
63 using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
64 using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
65 using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
66 
67 constexpr int supportedKeyBitLength = 2048;
68 constexpr int defaultKeyBitLength = 2048;
69 // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
70 constexpr auto defaultKeyCurveID = "secp224r1";
71 // PEM certificate block markers, defined in go/rfc/7468.
72 constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
73 constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
74 
75 /**
76  * @brief Splits the given authorities list file and returns an array of
77  * individual PEM encoded x509 certificate.
78  *
79  * @param[in] sourceFilePath - Path to the authorities list file.
80  *
81  * @return An array of individual PEM encoded x509 certificate
82  */
83 std::vector<std::string> splitCertificates(const std::string& sourceFilePath)
84 {
85     std::ifstream inputCertFileStream;
86     inputCertFileStream.exceptions(
87         std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
88 
89     std::stringstream pemStream;
90     std::vector<std::string> certificatesList;
91     try
92     {
93         inputCertFileStream.open(sourceFilePath);
94         pemStream << inputCertFileStream.rdbuf();
95         inputCertFileStream.close();
96     }
97     catch (const std::exception& e)
98     {
99         lg2::error("Failed to read certificates list, ERR:{ERR}, SRC:{SRC}",
100                    "ERR", e, "SRC", sourceFilePath);
101         elog<InternalFailure>();
102     }
103     std::string pem = pemStream.str();
104     size_t begin = 0;
105     // |begin| points to the current start position for searching the next
106     // |beginCertificate| block. When we find the beginning of the certificate,
107     // we extract the content between the beginning and the end of the current
108     // certificate. And finally we move |begin| to the end of the current
109     // certificate to start searching the next potential certificate.
110     for (begin = pem.find(beginCertificate, begin); begin != std::string::npos;
111          begin = pem.find(beginCertificate, begin))
112     {
113         size_t end = pem.find(endCertificate, begin);
114         if (end == std::string::npos)
115         {
116             lg2::error(
117                 "invalid PEM contains a BEGIN identifier without an END");
118             elog<InvalidCertificate>(InvalidCertificateReason(
119                 "invalid PEM contains a BEGIN identifier without an END"));
120         }
121         end += endCertificate.size();
122         certificatesList.emplace_back(pem.substr(begin, end - begin));
123         begin = end;
124     }
125     return certificatesList;
126 }
127 
128 } // namespace
129 
130 Manager::Manager(sdbusplus::bus_t& bus, sdeventplus::Event& event,
131                  const char* path, CertificateType type,
132                  const std::string& unit, const std::string& installPath) :
133     internal::ManagerInterface(bus, path),
134     bus(bus), event(event), objectPath(path), certType(type),
135     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
136     certParentInstallPath(fs::path(certInstallPath).parent_path())
137 {
138     try
139     {
140         // Create certificate directory if not existing.
141         // Set correct certificate directory permissions.
142         fs::path certDirectory;
143         try
144         {
145             if (certType == CertificateType::authority)
146             {
147                 certDirectory = certInstallPath;
148             }
149             else
150             {
151                 certDirectory = certParentInstallPath;
152             }
153 
154             if (!fs::exists(certDirectory))
155             {
156                 fs::create_directories(certDirectory);
157             }
158 
159             auto permission = fs::perms::owner_read | fs::perms::owner_write |
160                               fs::perms::owner_exec;
161             fs::permissions(certDirectory, permission,
162                             fs::perm_options::replace);
163             storageUpdate();
164         }
165         catch (const fs::filesystem_error& e)
166         {
167             lg2::error(
168                 "Failed to create directory, ERR:{ERR}, DIRECTORY:{DIRECTORY}",
169                 "ERR", e, "DIRECTORY", certParentInstallPath);
170             report<InternalFailure>();
171         }
172 
173         // Generating RSA private key file if certificate type is server/client
174         if (certType != CertificateType::authority)
175         {
176             createRSAPrivateKeyFile();
177         }
178 
179         // restore any existing certificates
180         createCertificates();
181 
182         // watch is not required for authority certificates
183         if (certType != CertificateType::authority)
184         {
185             // watch for certificate file create/replace
186             certWatchPtr = std::make_unique<Watch>(event, certInstallPath,
187                                                    [this]() {
188                 try
189                 {
190                     // if certificate file existing update it
191                     if (!installedCerts.empty())
192                     {
193                         lg2::info("Inotify callback to update "
194                                   "certificate properties");
195                         installedCerts[0]->populateProperties();
196                     }
197                     else
198                     {
199                         lg2::info(
200                             "Inotify callback to create certificate object");
201                         createCertificates();
202                     }
203                 }
204                 catch (const InternalFailure& e)
205                 {
206                     commit<InternalFailure>();
207                 }
208                 catch (const InvalidCertificate& e)
209                 {
210                     commit<InvalidCertificate>();
211                 }
212             });
213         }
214         else
215         {
216             try
217             {
218                 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
219                 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
220                 {
221                     lg2::notice(
222                         "Legacy certificate detected, will be installed from,"
223                         "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
224                         "SINGLE_CERTPATH", singleCertPath);
225                     install(singleCertPath);
226                     if (!fs::remove(singleCertPath))
227                     {
228                         lg2::error("Unable to remove old certificate from,"
229                                    "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
230                                    "SINGLE_CERTPATH", singleCertPath);
231                         elog<InternalFailure>();
232                     }
233                 }
234             }
235             catch (const std::exception& ex)
236             {
237                 lg2::error(
238                     "Error in restoring legacy certificate, ERROR_STR:{ERROR_STR}",
239                     "ERROR_STR", ex);
240             }
241         }
242     }
243     catch (const std::exception& ex)
244     {
245         lg2::error(
246             "Error in certificate manager constructor, ERROR_STR:{ERROR_STR}",
247             "ERROR_STR", ex);
248     }
249 }
250 
251 std::string Manager::install(const std::string filePath)
252 {
253     if (certType != CertificateType::authority && !installedCerts.empty())
254     {
255         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
256     }
257     else if (certType == CertificateType::authority &&
258              installedCerts.size() >= maxNumAuthorityCertificates)
259     {
260         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
261     }
262 
263     std::string certObjectPath;
264     if (isCertificateUnique(filePath))
265     {
266         certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
267         installedCerts.emplace_back(std::make_unique<Certificate>(
268             bus, certObjectPath, certType, certInstallPath, filePath,
269             certWatchPtr.get(), *this, /*restore=*/false));
270         reloadOrReset(unitToRestart);
271         certIdCounter++;
272     }
273     else
274     {
275         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
276     }
277 
278     return certObjectPath;
279 }
280 
281 std::vector<sdbusplus::message::object_path>
282     Manager::installAll(const std::string filePath)
283 {
284     if (certType != CertificateType::authority)
285     {
286         elog<NotAllowed>(
287             NotAllowedReason("The InstallAll interface is only allowed for "
288                              "Authority certificates"));
289     }
290 
291     if (!installedCerts.empty())
292     {
293         elog<NotAllowed>(NotAllowedReason(
294             "There are already root certificates; Call DeleteAll then "
295             "InstallAll, or use ReplaceAll"));
296     }
297 
298     fs::path sourceFile(filePath);
299     if (!fs::exists(sourceFile))
300     {
301         lg2::error("File is Missing, FILE:{FILE}", "FILE", filePath);
302         elog<InternalFailure>();
303     }
304     std::vector<std::string> authorities = splitCertificates(sourceFile);
305     if (authorities.size() > maxNumAuthorityCertificates)
306     {
307         elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
308     }
309 
310     lg2::info("Starts authority list install");
311 
312     fs::path authorityStore(certInstallPath);
313     fs::path authoritiesListFile = authorityStore /
314                                    defaultAuthoritiesListFileName;
315 
316     // Atomically install all the certificates
317     fs::path tempPath = Certificate::generateUniqueFilePath(authorityStore);
318     fs::create_directory(tempPath);
319     // Copies the authorities list
320     Certificate::copyCertificate(sourceFile,
321                                  tempPath / defaultAuthoritiesListFileName);
322     std::vector<std::unique_ptr<Certificate>> tempCertificates;
323     uint64_t tempCertIdCounter = certIdCounter;
324     X509StorePtr x509Store = getX509Store(sourceFile);
325     for (const auto& authority : authorities)
326     {
327         std::string certObjectPath = objectPath + '/' +
328                                      std::to_string(tempCertIdCounter);
329         tempCertificates.emplace_back(std::make_unique<Certificate>(
330             bus, certObjectPath, certType, tempPath, *x509Store, authority,
331             certWatchPtr.get(), *this, /*restore=*/false));
332         tempCertIdCounter++;
333     }
334 
335     // We are good now, issue swap
336     installedCerts = std::move(tempCertificates);
337     certIdCounter = tempCertIdCounter;
338     // Rename all the certificates including the authorities list
339     for (const fs::path& f : fs::directory_iterator(tempPath))
340     {
341         if (fs::is_symlink(f))
342         {
343             continue;
344         }
345         fs::rename(/*from=*/f, /*to=*/certInstallPath / f.filename());
346     }
347     // Update file locations and create symbol links
348     for (const auto& cert : installedCerts)
349     {
350         cert->setCertInstallPath(certInstallPath);
351         cert->setCertFilePath(certInstallPath /
352                               fs::path(cert->getCertFilePath()).filename());
353         cert->storageUpdate();
354     }
355     // Remove the temporary folder
356     fs::remove_all(tempPath);
357 
358     std::vector<sdbusplus::message::object_path> objects;
359     for (const auto& certificate : installedCerts)
360     {
361         objects.emplace_back(certificate->getObjectPath());
362     }
363 
364     lg2::info("Finishes authority list install; reload units starts");
365     reloadOrReset(unitToRestart);
366     return objects;
367 }
368 
369 std::vector<sdbusplus::message::object_path>
370     Manager::replaceAll(std::string filePath)
371 {
372     installedCerts.clear();
373     certIdCounter = 1;
374     storageUpdate();
375     return installAll(std::move(filePath));
376 }
377 
378 void Manager::deleteAll()
379 {
380     // TODO: #Issue 4 when a certificate is deleted system auto generates
381     // certificate file. At present we are not supporting creation of
382     // certificate object for the auto-generated certificate file as
383     // deletion if only applicable for REST server and Bmcweb does not allow
384     // deletion of certificates
385     installedCerts.clear();
386     // If the authorities list exists, delete it as well
387     if (certType == CertificateType::authority)
388     {
389         if (fs::path authoritiesList = fs::path(certInstallPath) /
390                                        defaultAuthoritiesListFileName;
391             fs::exists(authoritiesList))
392         {
393             fs::remove(authoritiesList);
394         }
395     }
396     certIdCounter = 1;
397     storageUpdate();
398     reloadOrReset(unitToRestart);
399 }
400 
401 void Manager::deleteCertificate(const Certificate* const certificate)
402 {
403     const std::vector<std::unique_ptr<Certificate>>::iterator& certIt =
404         std::find_if(installedCerts.begin(), installedCerts.end(),
405                      [certificate](const std::unique_ptr<Certificate>& cert) {
406         return (cert.get() == certificate);
407         });
408     if (certIt != installedCerts.end())
409     {
410         installedCerts.erase(certIt);
411         storageUpdate();
412         reloadOrReset(unitToRestart);
413     }
414     else
415     {
416         lg2::error("Certificate does not exist, ID:{ID}", "ID",
417                    certificate->getCertId());
418         elog<InternalFailure>();
419     }
420 }
421 
422 void Manager::replaceCertificate(Certificate* const certificate,
423                                  const std::string& filePath)
424 {
425     if (isCertificateUnique(filePath, certificate))
426     {
427         certificate->install(filePath, false);
428         storageUpdate();
429         reloadOrReset(unitToRestart);
430     }
431     else
432     {
433         elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
434     }
435 }
436 
437 std::string Manager::generateCSR(
438     std::vector<std::string> alternativeNames, std::string challengePassword,
439     std::string city, std::string commonName, std::string contactPerson,
440     std::string country, std::string email, std::string givenName,
441     std::string initials, int64_t keyBitLength, std::string keyCurveId,
442     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
443     std::string organization, std::string organizationalUnit, std::string state,
444     std::string surname, std::string unstructuredName)
445 {
446     // We support only one CSR.
447     csrPtr.reset(nullptr);
448     auto pid = fork();
449     if (pid == -1)
450     {
451         lg2::error("Error occurred during forking process");
452         report<InternalFailure>();
453     }
454     else if (pid == 0)
455     {
456         try
457         {
458             generateCSRHelper(alternativeNames, challengePassword, city,
459                               commonName, contactPerson, country, email,
460                               givenName, initials, keyBitLength, keyCurveId,
461                               keyPairAlgorithm, keyUsage, organization,
462                               organizationalUnit, state, surname,
463                               unstructuredName);
464             exit(EXIT_SUCCESS);
465         }
466         catch (const InternalFailure& e)
467         {
468             // commit the error reported in child process and exit
469             // Callback method from SDEvent Loop looks for exit status
470             exit(EXIT_FAILURE);
471             commit<InternalFailure>();
472         }
473         catch (const InvalidArgument& e)
474         {
475             // commit the error reported in child process and exit
476             // Callback method from SDEvent Loop looks for exit status
477             exit(EXIT_FAILURE);
478             commit<InvalidArgument>();
479         }
480     }
481     else
482     {
483         using namespace sdeventplus::source;
484         Child::Callback callback =
485             [this](Child& eventSource, const siginfo_t* si) {
486             eventSource.set_enabled(Enabled::On);
487             if (si->si_status != 0)
488             {
489                 this->createCSRObject(Status::failure);
490             }
491             else
492             {
493                 this->createCSRObject(Status::success);
494             }
495         };
496         try
497         {
498             sigset_t ss;
499             if (sigemptyset(&ss) < 0)
500             {
501                 lg2::error("Unable to initialize signal set");
502                 elog<InternalFailure>();
503             }
504             if (sigaddset(&ss, SIGCHLD) < 0)
505             {
506                 lg2::error("Unable to add signal to signal set");
507                 elog<InternalFailure>();
508             }
509 
510             // Block SIGCHLD first, so that the event loop can handle it
511             if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
512             {
513                 lg2::error("Unable to block signal");
514                 elog<InternalFailure>();
515             }
516             if (childPtr)
517             {
518                 childPtr.reset();
519             }
520             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
521                                                std::move(callback));
522         }
523         catch (const InternalFailure& e)
524         {
525             commit<InternalFailure>();
526         }
527     }
528     auto csrObjectPath = objectPath + '/' + "csr";
529     return csrObjectPath;
530 }
531 
532 std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
533 {
534     return installedCerts;
535 }
536 
537 void Manager::generateCSRHelper(
538     std::vector<std::string> alternativeNames, std::string challengePassword,
539     std::string city, std::string commonName, std::string contactPerson,
540     std::string country, std::string email, std::string givenName,
541     std::string initials, int64_t keyBitLength, std::string keyCurveId,
542     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
543     std::string organization, std::string organizationalUnit, std::string state,
544     std::string surname, std::string unstructuredName)
545 {
546     int ret = 0;
547 
548     // set version of x509 req
549     int nVersion = 1;
550     // TODO: Issue#6 need to make version number configurable
551     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
552     ret = X509_REQ_set_version(x509Req.get(), nVersion);
553     if (ret == 0)
554     {
555         lg2::error("Error occurred during X509_REQ_set_version call");
556         elog<InternalFailure>();
557     }
558 
559     // set subject of x509 req
560     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
561 
562     if (!alternativeNames.empty())
563     {
564         for (auto& name : alternativeNames)
565         {
566             addEntry(x509Name, "subjectAltName", name);
567         }
568     }
569     addEntry(x509Name, "challengePassword", challengePassword);
570     addEntry(x509Name, "L", city);
571     addEntry(x509Name, "CN", commonName);
572     addEntry(x509Name, "name", contactPerson);
573     addEntry(x509Name, "C", country);
574     addEntry(x509Name, "emailAddress", email);
575     addEntry(x509Name, "GN", givenName);
576     addEntry(x509Name, "initials", initials);
577     addEntry(x509Name, "algorithm", keyPairAlgorithm);
578     if (!keyUsage.empty())
579     {
580         for (auto& usage : keyUsage)
581         {
582             if (isExtendedKeyUsage(usage))
583             {
584                 addEntry(x509Name, "extendedKeyUsage", usage);
585             }
586             else
587             {
588                 addEntry(x509Name, "keyUsage", usage);
589             }
590         }
591     }
592     addEntry(x509Name, "O", organization);
593     addEntry(x509Name, "OU", organizationalUnit);
594     addEntry(x509Name, "ST", state);
595     addEntry(x509Name, "SN", surname);
596     addEntry(x509Name, "unstructuredName", unstructuredName);
597 
598     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
599 
600     lg2::info("Given Key pair algorithm, KEYPAIRALGORITHM:{KEYPAIRALGORITHM}",
601               "KEYPAIRALGORITHM", keyPairAlgorithm);
602 
603     // Used EC algorithm as default if user did not give algorithm type.
604     if (keyPairAlgorithm == "RSA")
605         pKey = getRSAKeyPair(keyBitLength);
606     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
607         pKey = generateECKeyPair(keyCurveId);
608     else
609     {
610         lg2::error("Given Key pair algorithm is not supported. Supporting "
611                    "RSA and EC only");
612         elog<InvalidArgument>(
613             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
614             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
615     }
616 
617     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
618     if (ret == 0)
619     {
620         lg2::error("Error occurred while setting Public key");
621         elog<InternalFailure>();
622     }
623 
624     // Write private key to file
625     writePrivateKey(pKey, defaultPrivateKeyFileName);
626 
627     // set sign key of x509 req
628     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
629     if (ret == 0)
630     {
631         lg2::error("Error occurred while signing key of x509");
632         elog<InternalFailure>();
633     }
634 
635     lg2::info("Writing CSR to file");
636     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
637     writeCSR(csrFilePath.string(), x509Req);
638 }
639 
640 bool Manager::isExtendedKeyUsage(const std::string& usage)
641 {
642     const static std::array<const char*, 6> usageList = {
643         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
644         "Timestamping",         "CodeSigning",          "EmailProtection"};
645     auto it = std::find_if(usageList.begin(), usageList.end(),
646                            [&usage](const char* s) {
647         return (strcmp(s, usage.c_str()) == 0);
648     });
649     return it != usageList.end();
650 }
651 EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
652 {
653     int64_t keyBitLen = keyBitLength;
654     // set keybit length to default value if not set
655     if (keyBitLen <= 0)
656     {
657         lg2::info("KeyBitLength is not given.Hence, using default KeyBitLength:"
658                   "{DEFAULTKEYBITLENGTH}",
659                   "DEFAULTKEYBITLENGTH", defaultKeyBitLength);
660         keyBitLen = defaultKeyBitLength;
661     }
662 
663 #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
664 
665     // generate rsa key
666     BignumPtr bne(BN_new(), ::BN_free);
667     auto ret = BN_set_word(bne.get(), RSA_F4);
668     if (ret == 0)
669     {
670         lg2::error("Error occurred during BN_set_word call");
671         elog<InternalFailure>();
672     }
673     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
674     RSAPtr rsa(RSA_new(), ::RSA_free);
675     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
676     if (ret != 1)
677     {
678         lg2::error(
679             "Error occurred during RSA_generate_key_ex call: {KEYBITLENGTH}",
680             "KEYBITLENGTH", keyBitLen);
681         elog<InternalFailure>();
682     }
683 
684     // set public key of x509 req
685     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
686     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
687     if (ret == 0)
688     {
689         lg2::error("Error occurred during assign rsa key into EVP");
690         elog<InternalFailure>();
691     }
692     // Now |rsa| is managed by |pKey|
693     rsa.release();
694     return pKey;
695 
696 #else
697     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
698         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
699     if (!ctx)
700     {
701         lg2::error("Error occurred creating EVP_PKEY_CTX from algorithm");
702         elog<InternalFailure>();
703     }
704 
705     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
706         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
707 
708     {
709         lg2::error("Error occurred initializing keygen context");
710         elog<InternalFailure>();
711     }
712 
713     EVP_PKEY* pKey = nullptr;
714     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
715     {
716         lg2::error("Error occurred during generate EC key");
717         elog<InternalFailure>();
718     }
719 
720     return {pKey, &::EVP_PKEY_free};
721 #endif
722 }
723 
724 EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
725 {
726     std::string curId(curveId);
727 
728     if (curId.empty())
729     {
730         lg2::info("KeyCurveId is not given. Hence using default curve id,"
731                   "DEFAULTKEYCURVEID:{DEFAULTKEYCURVEID}",
732                   "DEFAULTKEYCURVEID", defaultKeyCurveID);
733         curId = defaultKeyCurveID;
734     }
735 
736     int ecGrp = OBJ_txt2nid(curId.c_str());
737     if (ecGrp == NID_undef)
738     {
739         lg2::error(
740             "Error occurred during convert the curve id string format into NID,"
741             "KEYCURVEID:{KEYCURVEID}",
742             "KEYCURVEID", curId);
743         elog<InternalFailure>();
744     }
745 
746 #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
747 
748     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
749 
750     if (ecKey == nullptr)
751     {
752         lg2::error(
753             "Error occurred during create the EC_Key object from NID, ECGROUP:{ECGROUP}",
754             "ECGROUP", ecGrp);
755         elog<InternalFailure>();
756     }
757 
758     // If you want to save a key and later load it with
759     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
760     // flag on the key.
761     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
762 
763     int ret = EC_KEY_generate_key(ecKey);
764 
765     if (ret == 0)
766     {
767         EC_KEY_free(ecKey);
768         lg2::error("Error occurred during generate EC key");
769         elog<InternalFailure>();
770     }
771 
772     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
773     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
774     if (ret == 0)
775     {
776         EC_KEY_free(ecKey);
777         lg2::error("Error occurred during assign EC Key into EVP");
778         elog<InternalFailure>();
779     }
780 
781     return pKey;
782 
783 #else
784     auto holderOfKey = [](EVP_PKEY* key) {
785         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
786             key, &::EVP_PKEY_free};
787     };
788 
789     // Create context to set up curve parameters.
790     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
791         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
792     if (!ctx)
793     {
794         lg2::error("Error occurred creating EVP_PKEY_CTX for params");
795         elog<InternalFailure>();
796     }
797 
798     // Set up curve parameters.
799     EVP_PKEY* params = nullptr;
800 
801     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
802         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
803          0) ||
804         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
805         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
806     {
807         lg2::error("Error occurred setting curve parameters");
808         elog<InternalFailure>();
809     }
810 
811     // Move parameters to RAII holder.
812     auto pparms = holderOfKey(params);
813 
814     // Create new context for key.
815     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
816 
817     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
818     {
819         lg2::error("Error occurred initializing keygen context");
820         elog<InternalFailure>();
821     }
822 
823     EVP_PKEY* pKey = nullptr;
824     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
825     {
826         lg2::error("Error occurred during generate EC key");
827         elog<InternalFailure>();
828     }
829 
830     return holderOfKey(pKey);
831 #endif
832 }
833 
834 void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
835                               const std::string& privKeyFileName)
836 {
837     lg2::info("Writing private key to file");
838     // write private key to file
839     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
840 
841     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
842     if (fp == nullptr)
843     {
844         lg2::error("Error occurred creating private key file");
845         elog<InternalFailure>();
846     }
847     int ret = PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0,
848                                    nullptr);
849     std::fclose(fp);
850     if (ret == 0)
851     {
852         lg2::error("Error occurred while writing private key to file");
853         elog<InternalFailure>();
854     }
855 }
856 
857 void Manager::addEntry(X509_NAME* x509Name, const char* field,
858                        const std::string& bytes)
859 {
860     if (bytes.empty())
861     {
862         return;
863     }
864     int ret = X509_NAME_add_entry_by_txt(
865         x509Name, field, MBSTRING_ASC,
866         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
867     if (ret != 1)
868     {
869         lg2::error("Unable to set entry, FIELD:{FIELD}, VALUE:{VALUE}", "FIELD",
870                    field, "VALUE", bytes);
871         elog<InternalFailure>();
872     }
873 }
874 
875 void Manager::createCSRObject(const Status& status)
876 {
877     if (csrPtr)
878     {
879         csrPtr.reset(nullptr);
880     }
881     auto csrObjectPath = objectPath + '/' + "csr";
882     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
883                                    certInstallPath.c_str(), status);
884 }
885 
886 void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
887 {
888     if (fs::exists(filePath))
889     {
890         lg2::info("Removing the existing file, FILENAME:{FILENAME}", "FILENAME",
891                   filePath);
892         if (!fs::remove(filePath.c_str()))
893         {
894             lg2::error("Unable to remove the file, FILENAME:{FILENAME}",
895                        "FILENAME", filePath);
896             elog<InternalFailure>();
897         }
898     }
899 
900     FILE* fp = nullptr;
901 
902     if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
903     {
904         lg2::error(
905             "Error opening the file to write the CSR, FILENAME:{FILENAME}",
906             "FILENAME", filePath);
907         elog<InternalFailure>();
908     }
909 
910     int rc = PEM_write_X509_REQ(fp, x509Req.get());
911     if (!rc)
912     {
913         lg2::error("PEM write routine failed, FILENAME:{FILENAME}", "FILENAME",
914                    filePath);
915         std::fclose(fp);
916         elog<InternalFailure>();
917     }
918     std::fclose(fp);
919 }
920 
921 void Manager::createCertificates()
922 {
923     auto certObjectPath = objectPath + '/';
924 
925     if (certType == CertificateType::authority)
926     {
927         // Check whether install path is a directory.
928         if (!fs::is_directory(certInstallPath))
929         {
930             lg2::error("Certificate installation path exists and it is "
931                        "not a directory");
932             elog<InternalFailure>();
933         }
934 
935         // If the authorities list exists, recover from it and return
936         if (fs::path authoritiesListFilePath = fs::path(certInstallPath) /
937                                                defaultAuthoritiesListFileName;
938             fs::exists(authoritiesListFilePath))
939         {
940             // remove all other files and directories
941             for (auto& path : fs::directory_iterator(certInstallPath))
942             {
943                 if (path.path() != authoritiesListFilePath)
944                 {
945                     fs::remove_all(path);
946                 }
947             }
948             installAll(authoritiesListFilePath);
949             return;
950         }
951 
952         for (auto& path : fs::directory_iterator(certInstallPath))
953         {
954             try
955             {
956                 // Assume here any regular file located in certificate directory
957                 // contains certificates body. Do not want to use soft links
958                 // would add value.
959                 if (fs::is_regular_file(path))
960                 {
961                     installedCerts.emplace_back(std::make_unique<Certificate>(
962                         bus, certObjectPath + std::to_string(certIdCounter++),
963                         certType, certInstallPath, path.path(),
964                         certWatchPtr.get(), *this, /*restore=*/true));
965                 }
966             }
967             catch (const InternalFailure& e)
968             {
969                 report<InternalFailure>();
970             }
971             catch (const InvalidCertificate& e)
972             {
973                 report<InvalidCertificate>(InvalidCertificateReason(
974                     "Existing certificate file is corrupted"));
975             }
976         }
977     }
978     else if (fs::exists(certInstallPath))
979     {
980         try
981         {
982             installedCerts.emplace_back(std::make_unique<Certificate>(
983                 bus, certObjectPath + '1', certType, certInstallPath,
984                 certInstallPath, certWatchPtr.get(), *this, /*restore=*/false));
985         }
986         catch (const InternalFailure& e)
987         {
988             report<InternalFailure>();
989         }
990         catch (const InvalidCertificate& e)
991         {
992             report<InvalidCertificate>(InvalidCertificateReason(
993                 "Existing certificate file is corrupted"));
994         }
995     }
996 }
997 
998 void Manager::createRSAPrivateKeyFile()
999 {
1000     fs::path rsaPrivateKeyFileName = certParentInstallPath /
1001                                      defaultRSAPrivateKeyFileName;
1002 
1003     try
1004     {
1005         if (!fs::exists(rsaPrivateKeyFileName))
1006         {
1007             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
1008                             defaultRSAPrivateKeyFileName);
1009         }
1010     }
1011     catch (const InternalFailure& e)
1012     {
1013         report<InternalFailure>();
1014     }
1015 }
1016 
1017 EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
1018 {
1019     if (keyBitLength != supportedKeyBitLength)
1020     {
1021         lg2::error(
1022             "Given Key bit length is not supported, GIVENKEYBITLENGTH:"
1023             "{GIVENKEYBITLENGTH}, SUPPORTEDKEYBITLENGTH:{SUPPORTEDKEYBITLENGTH}",
1024             "GIVENKEYBITLENGTH", keyBitLength, "SUPPORTEDKEYBITLENGTH",
1025             supportedKeyBitLength);
1026         elog<InvalidArgument>(
1027             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1028             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1029     }
1030     fs::path rsaPrivateKeyFileName = certParentInstallPath /
1031                                      defaultRSAPrivateKeyFileName;
1032 
1033     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1034     if (!privateKeyFile)
1035     {
1036         lg2::error(
1037             "Unable to open RSA private key file to read, RSAKEYFILE:{RSAKEYFILE},"
1038             "ERRORREASON:{ERRORREASON}",
1039             "RSAKEYFILE", rsaPrivateKeyFileName, "ERRORREASON",
1040             strerror(errno));
1041         elog<InternalFailure>();
1042     }
1043 
1044     EVPPkeyPtr privateKey(
1045         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1046         ::EVP_PKEY_free);
1047     std::fclose(privateKeyFile);
1048 
1049     if (!privateKey)
1050     {
1051         lg2::error("Error occurred during PEM_read_PrivateKey call");
1052         elog<InternalFailure>();
1053     }
1054     return privateKey;
1055 }
1056 
1057 void Manager::storageUpdate()
1058 {
1059     if (certType == CertificateType::authority)
1060     {
1061         // Remove symbolic links in the certificate directory
1062         for (auto& certPath : fs::directory_iterator(certInstallPath))
1063         {
1064             try
1065             {
1066                 if (fs::is_symlink(certPath))
1067                 {
1068                     fs::remove(certPath);
1069                 }
1070             }
1071             catch (const std::exception& e)
1072             {
1073                 lg2::error(
1074                     "Failed to remove symlink for certificate, ERR:{ERR} SYMLINK:{SYMLINK}",
1075                     "ERR", e, "SYMLINK", certPath.path().string());
1076                 elog<InternalFailure>();
1077             }
1078         }
1079     }
1080 
1081     for (const auto& cert : installedCerts)
1082     {
1083         cert->storageUpdate();
1084     }
1085 }
1086 
1087 void Manager::reloadOrReset(const std::string& unit)
1088 {
1089     if (!unit.empty())
1090     {
1091         try
1092         {
1093             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1094             constexpr auto defaultSystemdObjectPath =
1095                 "/org/freedesktop/systemd1";
1096             constexpr auto defaultSystemdInterface =
1097                 "org.freedesktop.systemd1.Manager";
1098             auto method = bus.new_method_call(
1099                 defaultSystemdService, defaultSystemdObjectPath,
1100                 defaultSystemdInterface, "ReloadOrRestartUnit");
1101             method.append(unit, "replace");
1102             bus.call_noreply(method);
1103         }
1104         catch (const sdbusplus::exception_t& e)
1105         {
1106             lg2::error(
1107                 "Failed to reload or restart service, ERR:{ERR}, UNIT:{UNIT}",
1108                 "ERR", e, "UNIT", unit);
1109             elog<InternalFailure>();
1110         }
1111     }
1112 }
1113 
1114 bool Manager::isCertificateUnique(const std::string& filePath,
1115                                   const Certificate* const certToDrop)
1116 {
1117     if (std::any_of(
1118             installedCerts.begin(), installedCerts.end(),
1119             [&filePath, certToDrop](const std::unique_ptr<Certificate>& cert) {
1120         return cert.get() != certToDrop && cert->isSame(filePath);
1121             }))
1122     {
1123         return false;
1124     }
1125     else
1126     {
1127         return true;
1128     }
1129 }
1130 
1131 } // namespace phosphor::certs
1132