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