xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision d96b81cac9113a55e98281fda983c64fd7d83c7d)
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 = [this](Child& eventSource,
485                                           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     X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
551     ret = X509_REQ_set_version(x509Req.get(), nVersion);
552     if (ret == 0)
553     {
554         lg2::error("Error occurred during X509_REQ_set_version call");
555         elog<InternalFailure>();
556     }
557 
558     // set subject of x509 req
559     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
560 
561     if (!alternativeNames.empty())
562     {
563         for (auto& name : alternativeNames)
564         {
565             addEntry(x509Name, "subjectAltName", name);
566         }
567     }
568     addEntry(x509Name, "challengePassword", challengePassword);
569     addEntry(x509Name, "L", city);
570     addEntry(x509Name, "CN", commonName);
571     addEntry(x509Name, "name", contactPerson);
572     addEntry(x509Name, "C", country);
573     addEntry(x509Name, "emailAddress", email);
574     addEntry(x509Name, "GN", givenName);
575     addEntry(x509Name, "initials", initials);
576     addEntry(x509Name, "algorithm", keyPairAlgorithm);
577     if (!keyUsage.empty())
578     {
579         for (auto& usage : keyUsage)
580         {
581             if (isExtendedKeyUsage(usage))
582             {
583                 addEntry(x509Name, "extendedKeyUsage", usage);
584             }
585             else
586             {
587                 addEntry(x509Name, "keyUsage", usage);
588             }
589         }
590     }
591     addEntry(x509Name, "O", organization);
592     addEntry(x509Name, "OU", organizationalUnit);
593     addEntry(x509Name, "ST", state);
594     addEntry(x509Name, "SN", surname);
595     addEntry(x509Name, "unstructuredName", unstructuredName);
596 
597     EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
598 
599     lg2::info("Given Key pair algorithm, KEYPAIRALGORITHM:{KEYPAIRALGORITHM}",
600               "KEYPAIRALGORITHM", keyPairAlgorithm);
601 
602     // Used EC algorithm as default if user did not give algorithm type.
603     if (keyPairAlgorithm == "RSA")
604         pKey = getRSAKeyPair(keyBitLength);
605     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
606         pKey = generateECKeyPair(keyCurveId);
607     else
608     {
609         lg2::error("Given Key pair algorithm is not supported. Supporting "
610                    "RSA and EC only");
611         elog<InvalidArgument>(
612             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
613             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
614     }
615 
616     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
617     if (ret == 0)
618     {
619         lg2::error("Error occurred while setting Public key");
620         elog<InternalFailure>();
621     }
622 
623     // Write private key to file
624     writePrivateKey(pKey, defaultPrivateKeyFileName);
625 
626     // set sign key of x509 req
627     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
628     if (ret == 0)
629     {
630         lg2::error("Error occurred while signing key of x509");
631         elog<InternalFailure>();
632     }
633 
634     lg2::info("Writing CSR to file");
635     fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
636     writeCSR(csrFilePath.string(), x509Req);
637 }
638 
639 bool Manager::isExtendedKeyUsage(const std::string& usage)
640 {
641     const static std::array<const char*, 6> usageList = {
642         "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
643         "Timestamping",         "CodeSigning",          "EmailProtection"};
644     auto it = std::find_if(
645         usageList.begin(), usageList.end(),
646         [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
647     return it != usageList.end();
648 }
649 EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
650 {
651     int64_t keyBitLen = keyBitLength;
652     // set keybit length to default value if not set
653     if (keyBitLen <= 0)
654     {
655         lg2::info("KeyBitLength is not given.Hence, using default KeyBitLength:"
656                   "{DEFAULTKEYBITLENGTH}",
657                   "DEFAULTKEYBITLENGTH", defaultKeyBitLength);
658         keyBitLen = defaultKeyBitLength;
659     }
660 
661 #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
662 
663     // generate rsa key
664     BignumPtr bne(BN_new(), ::BN_free);
665     auto ret = BN_set_word(bne.get(), RSA_F4);
666     if (ret == 0)
667     {
668         lg2::error("Error occurred during BN_set_word call");
669         elog<InternalFailure>();
670     }
671     using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
672     RSAPtr rsa(RSA_new(), ::RSA_free);
673     ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
674     if (ret != 1)
675     {
676         lg2::error(
677             "Error occurred during RSA_generate_key_ex call: {KEYBITLENGTH}",
678             "KEYBITLENGTH", keyBitLen);
679         elog<InternalFailure>();
680     }
681 
682     // set public key of x509 req
683     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
684     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
685     if (ret == 0)
686     {
687         lg2::error("Error occurred during assign rsa key into EVP");
688         elog<InternalFailure>();
689     }
690     // Now |rsa| is managed by |pKey|
691     rsa.release();
692     return pKey;
693 
694 #else
695     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
696         EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
697     if (!ctx)
698     {
699         lg2::error("Error occurred creating EVP_PKEY_CTX from algorithm");
700         elog<InternalFailure>();
701     }
702 
703     if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
704         (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
705 
706     {
707         lg2::error("Error occurred initializing keygen context");
708         elog<InternalFailure>();
709     }
710 
711     EVP_PKEY* pKey = nullptr;
712     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
713     {
714         lg2::error("Error occurred during generate EC key");
715         elog<InternalFailure>();
716     }
717 
718     return {pKey, &::EVP_PKEY_free};
719 #endif
720 }
721 
722 EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
723 {
724     std::string curId(curveId);
725 
726     if (curId.empty())
727     {
728         lg2::info("KeyCurveId is not given. Hence using default curve id,"
729                   "DEFAULTKEYCURVEID:{DEFAULTKEYCURVEID}",
730                   "DEFAULTKEYCURVEID", defaultKeyCurveID);
731         curId = defaultKeyCurveID;
732     }
733 
734     int ecGrp = OBJ_txt2nid(curId.c_str());
735     if (ecGrp == NID_undef)
736     {
737         lg2::error(
738             "Error occurred during convert the curve id string format into NID,"
739             "KEYCURVEID:{KEYCURVEID}",
740             "KEYCURVEID", curId);
741         elog<InternalFailure>();
742     }
743 
744 #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
745 
746     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
747 
748     if (ecKey == nullptr)
749     {
750         lg2::error(
751             "Error occurred during create the EC_Key object from NID, ECGROUP:{ECGROUP}",
752             "ECGROUP", ecGrp);
753         elog<InternalFailure>();
754     }
755 
756     // If you want to save a key and later load it with
757     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
758     // flag on the key.
759     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
760 
761     int ret = EC_KEY_generate_key(ecKey);
762 
763     if (ret == 0)
764     {
765         EC_KEY_free(ecKey);
766         lg2::error("Error occurred during generate EC key");
767         elog<InternalFailure>();
768     }
769 
770     EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
771     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
772     if (ret == 0)
773     {
774         EC_KEY_free(ecKey);
775         lg2::error("Error occurred during assign EC Key into EVP");
776         elog<InternalFailure>();
777     }
778 
779     return pKey;
780 
781 #else
782     auto holderOfKey = [](EVP_PKEY* key) {
783         return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
784             key, &::EVP_PKEY_free};
785     };
786 
787     // Create context to set up curve parameters.
788     auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
789         EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
790     if (!ctx)
791     {
792         lg2::error("Error occurred creating EVP_PKEY_CTX for params");
793         elog<InternalFailure>();
794     }
795 
796     // Set up curve parameters.
797     EVP_PKEY* params = nullptr;
798 
799     if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
800         (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
801          0) ||
802         (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
803         (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
804     {
805         lg2::error("Error occurred setting curve parameters");
806         elog<InternalFailure>();
807     }
808 
809     // Move parameters to RAII holder.
810     auto pparms = holderOfKey(params);
811 
812     // Create new context for key.
813     ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
814 
815     if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
816     {
817         lg2::error("Error occurred initializing keygen context");
818         elog<InternalFailure>();
819     }
820 
821     EVP_PKEY* pKey = nullptr;
822     if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
823     {
824         lg2::error("Error occurred during generate EC key");
825         elog<InternalFailure>();
826     }
827 
828     return holderOfKey(pKey);
829 #endif
830 }
831 
832 void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
833                               const std::string& privKeyFileName)
834 {
835     lg2::info("Writing private key to file");
836     // write private key to file
837     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
838 
839     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
840     if (fp == nullptr)
841     {
842         lg2::error("Error occurred creating private key file");
843         elog<InternalFailure>();
844     }
845     int ret = PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0,
846                                    nullptr);
847     std::fclose(fp);
848     if (ret == 0)
849     {
850         lg2::error("Error occurred while writing private key to file");
851         elog<InternalFailure>();
852     }
853 }
854 
855 void Manager::addEntry(X509_NAME* x509Name, const char* field,
856                        const std::string& bytes)
857 {
858     if (bytes.empty())
859     {
860         return;
861     }
862     int ret = X509_NAME_add_entry_by_txt(
863         x509Name, field, MBSTRING_ASC,
864         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
865     if (ret != 1)
866     {
867         lg2::error("Unable to set entry, FIELD:{FIELD}, VALUE:{VALUE}", "FIELD",
868                    field, "VALUE", bytes);
869         elog<InternalFailure>();
870     }
871 }
872 
873 void Manager::createCSRObject(const Status& status)
874 {
875     if (csrPtr)
876     {
877         csrPtr.reset(nullptr);
878     }
879     auto csrObjectPath = objectPath + '/' + "csr";
880     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
881                                    certInstallPath.c_str(), status);
882 }
883 
884 void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
885 {
886     if (fs::exists(filePath))
887     {
888         lg2::info("Removing the existing file, FILENAME:{FILENAME}", "FILENAME",
889                   filePath);
890         if (!fs::remove(filePath.c_str()))
891         {
892             lg2::error("Unable to remove the file, FILENAME:{FILENAME}",
893                        "FILENAME", filePath);
894             elog<InternalFailure>();
895         }
896     }
897 
898     FILE* fp = nullptr;
899 
900     if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
901     {
902         lg2::error(
903             "Error opening the file to write the CSR, FILENAME:{FILENAME}",
904             "FILENAME", filePath);
905         elog<InternalFailure>();
906     }
907 
908     int rc = PEM_write_X509_REQ(fp, x509Req.get());
909     if (!rc)
910     {
911         lg2::error("PEM write routine failed, FILENAME:{FILENAME}", "FILENAME",
912                    filePath);
913         std::fclose(fp);
914         elog<InternalFailure>();
915     }
916     std::fclose(fp);
917 }
918 
919 void Manager::createCertificates()
920 {
921     auto certObjectPath = objectPath + '/';
922 
923     if (certType == CertificateType::authority)
924     {
925         // Check whether install path is a directory.
926         if (!fs::is_directory(certInstallPath))
927         {
928             lg2::error("Certificate installation path exists and it is "
929                        "not a directory");
930             elog<InternalFailure>();
931         }
932 
933         // If the authorities list exists, recover from it and return
934         if (fs::path authoritiesListFilePath = fs::path(certInstallPath) /
935                                                defaultAuthoritiesListFileName;
936             fs::exists(authoritiesListFilePath))
937         {
938             // remove all other files and directories
939             for (auto& path : fs::directory_iterator(certInstallPath))
940             {
941                 if (path.path() != authoritiesListFilePath)
942                 {
943                     fs::remove_all(path);
944                 }
945             }
946             installAll(authoritiesListFilePath);
947             return;
948         }
949 
950         for (auto& path : fs::directory_iterator(certInstallPath))
951         {
952             try
953             {
954                 // Assume here any regular file located in certificate directory
955                 // contains certificates body. Do not want to use soft links
956                 // would add value.
957                 if (fs::is_regular_file(path))
958                 {
959                     installedCerts.emplace_back(std::make_unique<Certificate>(
960                         bus, certObjectPath + std::to_string(certIdCounter++),
961                         certType, certInstallPath, path.path(),
962                         certWatchPtr.get(), *this, /*restore=*/true));
963                 }
964             }
965             catch (const InternalFailure& e)
966             {
967                 report<InternalFailure>();
968             }
969             catch (const InvalidCertificate& e)
970             {
971                 report<InvalidCertificate>(InvalidCertificateReason(
972                     "Existing certificate file is corrupted"));
973             }
974         }
975     }
976     else if (fs::exists(certInstallPath))
977     {
978         try
979         {
980             installedCerts.emplace_back(std::make_unique<Certificate>(
981                 bus, certObjectPath + '1', certType, certInstallPath,
982                 certInstallPath, certWatchPtr.get(), *this, /*restore=*/false));
983         }
984         catch (const InternalFailure& e)
985         {
986             report<InternalFailure>();
987         }
988         catch (const InvalidCertificate& e)
989         {
990             report<InvalidCertificate>(InvalidCertificateReason(
991                 "Existing certificate file is corrupted"));
992         }
993     }
994 }
995 
996 void Manager::createRSAPrivateKeyFile()
997 {
998     fs::path rsaPrivateKeyFileName = certParentInstallPath /
999                                      defaultRSAPrivateKeyFileName;
1000 
1001     try
1002     {
1003         if (!fs::exists(rsaPrivateKeyFileName))
1004         {
1005             writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
1006                             defaultRSAPrivateKeyFileName);
1007         }
1008     }
1009     catch (const InternalFailure& e)
1010     {
1011         report<InternalFailure>();
1012     }
1013 }
1014 
1015 EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
1016 {
1017     if (keyBitLength != supportedKeyBitLength)
1018     {
1019         lg2::error(
1020             "Given Key bit length is not supported, GIVENKEYBITLENGTH:"
1021             "{GIVENKEYBITLENGTH}, SUPPORTEDKEYBITLENGTH:{SUPPORTEDKEYBITLENGTH}",
1022             "GIVENKEYBITLENGTH", keyBitLength, "SUPPORTEDKEYBITLENGTH",
1023             supportedKeyBitLength);
1024         elog<InvalidArgument>(
1025             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1026             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1027     }
1028     fs::path rsaPrivateKeyFileName = certParentInstallPath /
1029                                      defaultRSAPrivateKeyFileName;
1030 
1031     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1032     if (!privateKeyFile)
1033     {
1034         lg2::error(
1035             "Unable to open RSA private key file to read, RSAKEYFILE:{RSAKEYFILE},"
1036             "ERRORREASON:{ERRORREASON}",
1037             "RSAKEYFILE", rsaPrivateKeyFileName, "ERRORREASON",
1038             strerror(errno));
1039         elog<InternalFailure>();
1040     }
1041 
1042     EVPPkeyPtr privateKey(
1043         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1044         ::EVP_PKEY_free);
1045     std::fclose(privateKeyFile);
1046 
1047     if (!privateKey)
1048     {
1049         lg2::error("Error occurred during PEM_read_PrivateKey call");
1050         elog<InternalFailure>();
1051     }
1052     return privateKey;
1053 }
1054 
1055 void Manager::storageUpdate()
1056 {
1057     if (certType == CertificateType::authority)
1058     {
1059         // Remove symbolic links in the certificate directory
1060         for (auto& certPath : fs::directory_iterator(certInstallPath))
1061         {
1062             try
1063             {
1064                 if (fs::is_symlink(certPath))
1065                 {
1066                     fs::remove(certPath);
1067                 }
1068             }
1069             catch (const std::exception& e)
1070             {
1071                 lg2::error(
1072                     "Failed to remove symlink for certificate, ERR:{ERR} SYMLINK:{SYMLINK}",
1073                     "ERR", e, "SYMLINK", certPath.path().string());
1074                 elog<InternalFailure>();
1075             }
1076         }
1077     }
1078 
1079     for (const auto& cert : installedCerts)
1080     {
1081         cert->storageUpdate();
1082     }
1083 }
1084 
1085 void Manager::reloadOrReset(const std::string& unit)
1086 {
1087     if (!unit.empty())
1088     {
1089         try
1090         {
1091             constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1092             constexpr auto defaultSystemdObjectPath =
1093                 "/org/freedesktop/systemd1";
1094             constexpr auto defaultSystemdInterface =
1095                 "org.freedesktop.systemd1.Manager";
1096             auto method = bus.new_method_call(
1097                 defaultSystemdService, defaultSystemdObjectPath,
1098                 defaultSystemdInterface, "ReloadOrRestartUnit");
1099             method.append(unit, "replace");
1100             bus.call_noreply(method);
1101         }
1102         catch (const sdbusplus::exception_t& e)
1103         {
1104             lg2::error(
1105                 "Failed to reload or restart service, ERR:{ERR}, UNIT:{UNIT}",
1106                 "ERR", e, "UNIT", unit);
1107             elog<InternalFailure>();
1108         }
1109     }
1110 }
1111 
1112 bool Manager::isCertificateUnique(const std::string& filePath,
1113                                   const Certificate* const certToDrop)
1114 {
1115     if (std::any_of(
1116             installedCerts.begin(), installedCerts.end(),
1117             [&filePath, certToDrop](const std::unique_ptr<Certificate>& cert) {
1118         return cert.get() != certToDrop && cert->isSame(filePath);
1119     }))
1120     {
1121         return false;
1122     }
1123     else
1124     {
1125         return true;
1126     }
1127 }
1128 
1129 } // namespace phosphor::certs
1130