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