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