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