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