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