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