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