1 #include "config.h"
2 
3 #include "certificate.hpp"
4 
5 #include "certs_manager.hpp"
6 #include "x509_utils.hpp"
7 
8 #include <openssl/asn1.h>
9 #include <openssl/bio.h>
10 #include <openssl/buffer.h>
11 #include <openssl/err.h>
12 #include <openssl/evp.h>
13 #include <openssl/obj_mac.h>
14 #include <openssl/objects.h>
15 #include <openssl/opensslv.h>
16 #include <openssl/pem.h>
17 #include <openssl/x509v3.h>
18 
19 #include <cstdint>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <exception>
23 #include <filesystem>
24 #include <fstream>
25 #include <map>
26 #include <phosphor-logging/elog-errors.hpp>
27 #include <phosphor-logging/elog.hpp>
28 #include <phosphor-logging/log.hpp>
29 #include <utility>
30 #include <vector>
31 #include <watch.hpp>
32 #include <xyz/openbmc_project/Certs/error.hpp>
33 #include <xyz/openbmc_project/Common/error.hpp>
34 
35 namespace phosphor::certs
36 {
37 
38 namespace
39 {
40 namespace fs = std::filesystem;
41 using ::phosphor::logging::elog;
42 using ::phosphor::logging::entry;
43 using ::phosphor::logging::level;
44 using ::phosphor::logging::log;
45 using ::phosphor::logging::report;
46 using InvalidCertificateError =
47     ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
48 using ::phosphor::logging::xyz::openbmc_project::Certs::InvalidCertificate;
49 using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
50 
51 // RAII support for openSSL functions.
52 using BIOMemPtr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
53 using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
54 using ASN1TimePtr = std::unique_ptr<ASN1_TIME, decltype(&ASN1_STRING_free)>;
55 using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
56 using BufMemPtr = std::unique_ptr<BUF_MEM, decltype(&::BUF_MEM_free)>;
57 
58 // Refer to schema 2018.3
59 // http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for
60 // supported KeyUsage types in redfish
61 // Refer to
62 // https://github.com/openssl/openssl/blob/master/include/openssl/x509v3.h for
63 // key usage bit fields
64 std::map<uint8_t, std::string> keyUsageToRfStr = {
65     {KU_DIGITAL_SIGNATURE, "DigitalSignature"},
66     {KU_NON_REPUDIATION, "NonRepudiation"},
67     {KU_KEY_ENCIPHERMENT, "KeyEncipherment"},
68     {KU_DATA_ENCIPHERMENT, "DataEncipherment"},
69     {KU_KEY_AGREEMENT, "KeyAgreement"},
70     {KU_KEY_CERT_SIGN, "KeyCertSign"},
71     {KU_CRL_SIGN, "CRLSigning"},
72     {KU_ENCIPHER_ONLY, "EncipherOnly"},
73     {KU_DECIPHER_ONLY, "DecipherOnly"}};
74 
75 // Refer to schema 2018.3
76 // http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for
77 // supported Extended KeyUsage types in redfish
78 std::map<uint8_t, std::string> extendedKeyUsageToRfStr = {
79     {NID_server_auth, "ServerAuthentication"},
80     {NID_client_auth, "ClientAuthentication"},
81     {NID_email_protect, "EmailProtection"},
82     {NID_OCSP_sign, "OCSPSigning"},
83     {NID_ad_timeStamping, "Timestamping"},
84     {NID_code_sign, "CodeSigning"}};
85 
86 /**
87  * @brief Dumps the PEM encoded certificate to installFilePath
88  *
89  * @param[in] pem - PEM encoded X509 certificate buffer.
90  * @param[in] certFilePath - Path to the destination file.
91  *
92  * @return void
93  */
94 
95 void dumpCertificate(const std::string& pem, const std::string& certFilePath)
96 {
97     std::ofstream outputCertFileStream;
98 
99     outputCertFileStream.exceptions(
100         std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
101 
102     try
103     {
104         outputCertFileStream.open(certFilePath, std::ios::out);
105         outputCertFileStream << pem << "\n" << std::flush;
106         outputCertFileStream.close();
107     }
108     catch (const std::exception& e)
109     {
110         log<level::ERR>("Failed to dump certificate", entry("ERR=%s", e.what()),
111                         entry("SRC_PEM=%s", pem.c_str()),
112                         entry("DST=%s", certFilePath.c_str()));
113         elog<InternalFailure>();
114     }
115 }
116 } // namespace
117 
118 void Certificate::copyCertificate(const std::string& certSrcFilePath,
119                                   const std::string& certFilePath)
120 {
121     // Copy the certificate to the installation path
122     // During bootup will be parsing existing file so no need to
123     // copy it.
124     if (certSrcFilePath != certFilePath)
125     {
126         std::ifstream inputCertFileStream;
127         std::ofstream outputCertFileStream;
128         inputCertFileStream.exceptions(std::ifstream::failbit |
129                                        std::ifstream::badbit |
130                                        std::ifstream::eofbit);
131         outputCertFileStream.exceptions(std::ofstream::failbit |
132                                         std::ofstream::badbit |
133                                         std::ofstream::eofbit);
134         try
135         {
136             inputCertFileStream.open(certSrcFilePath);
137             outputCertFileStream.open(certFilePath, std::ios::out);
138             outputCertFileStream << inputCertFileStream.rdbuf() << std::flush;
139             inputCertFileStream.close();
140             outputCertFileStream.close();
141         }
142         catch (const std::exception& e)
143         {
144             log<level::ERR>("Failed to copy certificate",
145                             entry("ERR=%s", e.what()),
146                             entry("SRC=%s", certSrcFilePath.c_str()),
147                             entry("DST=%s", certFilePath.c_str()));
148             elog<InternalFailure>();
149         }
150     }
151 }
152 
153 std::string
154     Certificate::generateUniqueFilePath(const std::string& directoryPath)
155 {
156     char* filePath = tempnam(directoryPath.c_str(), nullptr);
157     if (filePath == nullptr)
158     {
159         log<level::ERR>(
160             "Error occurred while creating random certificate file path",
161             entry("DIR=%s", directoryPath.c_str()));
162         elog<InternalFailure>();
163     }
164     std::string filePathStr(filePath);
165     free(filePath);
166     return filePathStr;
167 }
168 
169 std::string Certificate::generateAuthCertFileX509Path(
170     const std::string& certSrcFilePath, const std::string& certDstDirPath)
171 {
172     const internal::X509Ptr cert = loadCert(certSrcFilePath);
173     unsigned long hash = X509_subject_name_hash(cert.get());
174     static constexpr auto certHashLength = 9;
175     char hashBuf[certHashLength];
176 
177     snprintf(hashBuf, certHashLength, "%08lx", hash);
178 
179     const std::string certHash(hashBuf);
180     for (size_t i = 0; i < maxNumAuthorityCertificates; ++i)
181     {
182         const std::string certDstFileX509Path =
183             certDstDirPath + "/" + certHash + "." + std::to_string(i);
184         if (!fs::exists(certDstFileX509Path))
185         {
186             return certDstFileX509Path;
187         }
188     }
189 
190     log<level::ERR>("Authority certificate x509 file path already used",
191                     entry("DIR=%s", certDstDirPath.c_str()));
192     elog<InternalFailure>();
193 }
194 
195 std::string
196     Certificate::generateAuthCertFilePath(const std::string& certSrcFilePath)
197 {
198     // If there is a certificate file path (which means certificate replacement
199     // is doing) use it (do not create new one)
200     if (!certFilePath.empty())
201     {
202         return certFilePath;
203     }
204     // If source certificate file is located in the certificates directory use
205     // it (do not create new one)
206     else if (fs::path(certSrcFilePath).parent_path().string() ==
207              certInstallPath)
208     {
209         return certSrcFilePath;
210     }
211     // Otherwise generate new file name/path
212     else
213     {
214         return generateUniqueFilePath(certInstallPath);
215     }
216 }
217 
218 std::string
219     Certificate::generateCertFilePath(const std::string& certSrcFilePath)
220 {
221     if (certType == CertificateType::authority)
222     {
223         return generateAuthCertFilePath(certSrcFilePath);
224     }
225     else
226     {
227         return certInstallPath;
228     }
229 }
230 
231 Certificate::Certificate(sdbusplus::bus_t& bus, const std::string& objPath,
232                          CertificateType type, const std::string& installPath,
233                          const std::string& uploadPath, Watch* watch,
234                          Manager& parent, bool restore) :
235     internal::CertificateInterface(
236         bus, objPath.c_str(),
237         internal::CertificateInterface::action::defer_emit),
238     objectPath(objPath), certType(type), certInstallPath(installPath),
239     certWatch(watch), manager(parent)
240 {
241     auto installHelper = [this](const auto& filePath) {
242         if (!compareKeys(filePath))
243         {
244             elog<InvalidCertificateError>(InvalidCertificate::REASON(
245                 "Private key does not match the Certificate"));
246         };
247     };
248     typeFuncMap[CertificateType::server] = installHelper;
249     typeFuncMap[CertificateType::client] = installHelper;
250     typeFuncMap[CertificateType::authority] = [](const std::string&) {};
251 
252     auto appendPrivateKey = [this](const std::string& filePath) {
253         checkAndAppendPrivateKey(filePath);
254     };
255 
256     appendKeyMap[CertificateType::server] = appendPrivateKey;
257     appendKeyMap[CertificateType::client] = appendPrivateKey;
258     appendKeyMap[CertificateType::authority] = [](const std::string&) {};
259 
260     // Generate certificate file path
261     certFilePath = generateCertFilePath(uploadPath);
262 
263     // install the certificate
264     install(uploadPath, restore);
265 
266     this->emit_object_added();
267 }
268 
269 Certificate::Certificate(sdbusplus::bus_t& bus, const std::string& objPath,
270                          const CertificateType& type,
271                          const std::string& installPath, X509_STORE& x509Store,
272                          const std::string& pem, Watch* watchPtr,
273                          Manager& parent, bool restore) :
274     internal::CertificateInterface(
275         bus, objPath.c_str(),
276         internal::CertificateInterface::action::defer_emit),
277     objectPath(objPath), certType(type), certInstallPath(installPath),
278     certWatch(watchPtr), manager(parent)
279 {
280     // Generate certificate file path
281     certFilePath = generateUniqueFilePath(installPath);
282 
283     // install the certificate
284     install(x509Store, pem, restore);
285 
286     this->emit_object_added();
287 }
288 
289 Certificate::~Certificate()
290 {
291     if (!fs::remove(certFilePath))
292     {
293         log<level::INFO>("Certificate file not found!",
294                          entry("PATH=%s", certFilePath.c_str()));
295     }
296 }
297 
298 void Certificate::replace(const std::string filePath)
299 {
300     manager.replaceCertificate(this, filePath);
301 }
302 
303 void Certificate::install(const std::string& certSrcFilePath, bool restore)
304 {
305     if (restore)
306     {
307         log<level::DEBUG>("Certificate install ",
308                           entry("FILEPATH=%s", certSrcFilePath.c_str()));
309     }
310     else
311     {
312         log<level::INFO>("Certificate install ",
313                          entry("FILEPATH=%s", certSrcFilePath.c_str()));
314     }
315 
316     // stop watch for user initiated certificate install
317     if (certWatch != nullptr)
318     {
319         certWatch->stopWatch();
320     }
321 
322     // Verify the certificate file
323     fs::path file(certSrcFilePath);
324     if (!fs::exists(file))
325     {
326         log<level::ERR>("File is Missing",
327                         entry("FILE=%s", certSrcFilePath.c_str()));
328         elog<InternalFailure>();
329     }
330 
331     try
332     {
333         if (fs::file_size(certSrcFilePath) == 0)
334         {
335             // file is empty
336             log<level::ERR>("File is empty",
337                             entry("FILE=%s", certSrcFilePath.c_str()));
338             elog<InvalidCertificateError>(
339                 InvalidCertificate::REASON("File is empty"));
340         }
341     }
342     catch (const fs::filesystem_error& e)
343     {
344         // Log Error message
345         log<level::ERR>(e.what(), entry("FILE=%s", certSrcFilePath.c_str()));
346         elog<InternalFailure>();
347     }
348 
349     X509StorePtr x509Store = getX509Store(certSrcFilePath);
350 
351     // Load Certificate file into the X509 structure.
352     internal::X509Ptr cert = loadCert(certSrcFilePath);
353 
354     // Perform validation
355     validateCertificateAgainstStore(*x509Store, *cert);
356     validateCertificateStartDate(*cert);
357     validateCertificateInSSLContext(*cert);
358 
359     // Invoke type specific append private key function.
360     if (auto it = appendKeyMap.find(certType); it == appendKeyMap.end())
361     {
362         log<level::ERR>("Unsupported Type",
363                         entry("TYPE=%s", certificateTypeToString(certType)));
364         elog<InternalFailure>();
365     }
366     else
367     {
368         it->second(certSrcFilePath);
369     }
370 
371     // Invoke type specific compare keys function.
372     if (auto it = typeFuncMap.find(certType); it == typeFuncMap.end())
373     {
374         log<level::ERR>("Unsupported Type",
375                         entry("TYPE=%s", certificateTypeToString(certType)));
376         elog<InternalFailure>();
377     }
378     else
379     {
380         it->second(certSrcFilePath);
381     }
382 
383     copyCertificate(certSrcFilePath, certFilePath);
384     storageUpdate();
385 
386     // Keep certificate ID
387     certId = generateCertId(*cert);
388 
389     // Parse the certificate file and populate properties
390     populateProperties(*cert);
391 
392     // restart watch
393     if (certWatch != nullptr)
394     {
395         certWatch->startWatch();
396     }
397 }
398 
399 void Certificate::install(X509_STORE& x509Store, const std::string& pem,
400                           bool restore)
401 {
402     if (restore)
403     {
404         log<level::DEBUG>("Certificate install ",
405                           entry("PEM_STR=%s", pem.data()));
406     }
407     else
408     {
409         log<level::INFO>("Certificate install ",
410                          entry("PEM_STR=%s", pem.data()));
411     }
412 
413     if (certType != CertificateType::authority)
414     {
415         log<level::ERR>("Bulk install error: Unsupported Type; only authority "
416                         "supports bulk install",
417                         entry("TYPE=%s", certificateTypeToString(certType)));
418         elog<InternalFailure>();
419     }
420 
421     // stop watch for user initiated certificate install
422     if (certWatch)
423     {
424         certWatch->stopWatch();
425     }
426 
427     // Load Certificate file into the X509 structure.
428     internal::X509Ptr cert = parseCert(pem);
429     // Perform validation; no type specific compare keys function
430     validateCertificateAgainstStore(x509Store, *cert);
431     validateCertificateStartDate(*cert);
432     validateCertificateInSSLContext(*cert);
433 
434     // Copy the PEM to the installation path
435     dumpCertificate(pem, certFilePath);
436     storageUpdate();
437     // Keep certificate ID
438     certId = generateCertId(*cert);
439     // Parse the certificate file and populate properties
440     populateProperties(*cert);
441     // restart watch
442     if (certWatch)
443     {
444         certWatch->startWatch();
445     }
446 }
447 
448 void Certificate::populateProperties()
449 {
450     internal::X509Ptr cert = loadCert(certInstallPath);
451     populateProperties(*cert);
452 }
453 
454 std::string Certificate::getCertId() const
455 {
456     return certId;
457 }
458 
459 bool Certificate::isSame(const std::string& certPath)
460 {
461     internal::X509Ptr cert = loadCert(certPath);
462     return getCertId() == generateCertId(*cert);
463 }
464 
465 void Certificate::storageUpdate()
466 {
467     if (certType == CertificateType::authority)
468     {
469         // Create symbolic link in the certificate directory
470         std::string certFileX509Path;
471         try
472         {
473             if (!certFilePath.empty() &&
474                 fs::is_regular_file(fs::path(certFilePath)))
475             {
476                 certFileX509Path =
477                     generateAuthCertFileX509Path(certFilePath, certInstallPath);
478                 fs::create_symlink(fs::path(certFilePath),
479                                    fs::path(certFileX509Path));
480             }
481         }
482         catch (const std::exception& e)
483         {
484             log<level::ERR>("Failed to create symlink for certificate",
485                             entry("ERR=%s", e.what()),
486                             entry("FILE=%s", certFilePath.c_str()),
487                             entry("SYMLINK=%s", certFileX509Path.c_str()));
488             elog<InternalFailure>();
489         }
490     }
491 }
492 
493 void Certificate::populateProperties(X509& cert)
494 {
495     // Update properties if no error thrown
496     BIOMemPtr certBio(BIO_new(BIO_s_mem()), BIO_free);
497     PEM_write_bio_X509(certBio.get(), &cert);
498     BufMemPtr certBuf(BUF_MEM_new(), BUF_MEM_free);
499     BUF_MEM* buf = certBuf.get();
500     BIO_get_mem_ptr(certBio.get(), &buf);
501     std::string certStr(buf->data, buf->length);
502     certificateString(certStr);
503 
504     static const int maxKeySize = 4096;
505     char subBuffer[maxKeySize] = {0};
506     BIOMemPtr subBio(BIO_new(BIO_s_mem()), BIO_free);
507     // This pointer cannot be freed independantly.
508     X509_NAME* sub = X509_get_subject_name(&cert);
509     X509_NAME_print_ex(subBio.get(), sub, 0, XN_FLAG_SEP_COMMA_PLUS);
510     BIO_read(subBio.get(), subBuffer, maxKeySize);
511     subject(subBuffer);
512 
513     char issuerBuffer[maxKeySize] = {0};
514     BIOMemPtr issuerBio(BIO_new(BIO_s_mem()), BIO_free);
515     // This pointer cannot be freed independantly.
516     X509_NAME* issuerName = X509_get_issuer_name(&cert);
517     X509_NAME_print_ex(issuerBio.get(), issuerName, 0, XN_FLAG_SEP_COMMA_PLUS);
518     BIO_read(issuerBio.get(), issuerBuffer, maxKeySize);
519     issuer(issuerBuffer);
520 
521     std::vector<std::string> keyUsageList;
522     ASN1_BIT_STRING* usage;
523 
524     // Go through each usage in the bit string and convert to
525     // corresponding string value
526     if ((usage = static_cast<ASN1_BIT_STRING*>(
527              X509_get_ext_d2i(&cert, NID_key_usage, nullptr, nullptr))))
528     {
529         for (auto i = 0; i < usage->length; ++i)
530         {
531             for (auto& x : keyUsageToRfStr)
532             {
533                 if (x.first & usage->data[i])
534                 {
535                     keyUsageList.push_back(x.second);
536                     break;
537                 }
538             }
539         }
540     }
541 
542     EXTENDED_KEY_USAGE* extUsage;
543     if ((extUsage = static_cast<EXTENDED_KEY_USAGE*>(
544              X509_get_ext_d2i(&cert, NID_ext_key_usage, nullptr, nullptr))))
545     {
546         for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++)
547         {
548             keyUsageList.push_back(extendedKeyUsageToRfStr[OBJ_obj2nid(
549                 sk_ASN1_OBJECT_value(extUsage, i))]);
550         }
551     }
552     keyUsage(keyUsageList);
553 
554     int days = 0;
555     int secs = 0;
556 
557     ASN1TimePtr epoch(ASN1_TIME_new(), ASN1_STRING_free);
558     // Set time to 00:00am GMT, Jan 1 1970; format: YYYYMMDDHHMMSSZ
559     ASN1_TIME_set_string(epoch.get(), "19700101000000Z");
560 
561     static const uint64_t dayToSeconds = 24 * 60 * 60;
562     ASN1_TIME* notAfter = X509_get_notAfter(&cert);
563     ASN1_TIME_diff(&days, &secs, epoch.get(), notAfter);
564     validNotAfter((days * dayToSeconds) + secs);
565 
566     ASN1_TIME* notBefore = X509_get_notBefore(&cert);
567     ASN1_TIME_diff(&days, &secs, epoch.get(), notBefore);
568     validNotBefore((days * dayToSeconds) + secs);
569 }
570 
571 void Certificate::checkAndAppendPrivateKey(const std::string& filePath)
572 {
573     BIOMemPtr keyBio(BIO_new(BIO_s_file()), ::BIO_free);
574     if (!keyBio)
575     {
576         log<level::ERR>("Error occurred during BIO_s_file call",
577                         entry("FILE=%s", filePath.c_str()));
578         elog<InternalFailure>();
579     }
580     BIO_read_filename(keyBio.get(), filePath.c_str());
581 
582     EVPPkeyPtr priKey(
583         PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr),
584         ::EVP_PKEY_free);
585     if (!priKey)
586     {
587         log<level::INFO>("Private key not present in file",
588                          entry("FILE=%s", filePath.c_str()));
589         fs::path privateKeyFile = fs::path(certInstallPath).parent_path();
590         privateKeyFile = privateKeyFile / defaultPrivateKeyFileName;
591         if (!fs::exists(privateKeyFile))
592         {
593             log<level::ERR>("Private key file is not found",
594                             entry("FILE=%s", privateKeyFile.c_str()));
595             elog<InternalFailure>();
596         }
597 
598         std::ifstream privKeyFileStream;
599         std::ofstream certFileStream;
600         privKeyFileStream.exceptions(std::ifstream::failbit |
601                                      std::ifstream::badbit |
602                                      std::ifstream::eofbit);
603         certFileStream.exceptions(std::ofstream::failbit |
604                                   std::ofstream::badbit |
605                                   std::ofstream::eofbit);
606         try
607         {
608             privKeyFileStream.open(privateKeyFile);
609             certFileStream.open(filePath, std::ios::app);
610             certFileStream << std::endl; // insert line break
611             certFileStream << privKeyFileStream.rdbuf() << std::flush;
612             privKeyFileStream.close();
613             certFileStream.close();
614         }
615         catch (const std::exception& e)
616         {
617             log<level::ERR>("Failed to append private key",
618                             entry("ERR=%s", e.what()),
619                             entry("SRC=%s", privateKeyFile.c_str()),
620                             entry("DST=%s", filePath.c_str()));
621             elog<InternalFailure>();
622         }
623     }
624 }
625 
626 bool Certificate::compareKeys(const std::string& filePath)
627 {
628     log<level::INFO>("Certificate compareKeys",
629                      entry("FILEPATH=%s", filePath.c_str()));
630     internal::X509Ptr cert(X509_new(), ::X509_free);
631     if (!cert)
632     {
633         log<level::ERR>("Error occurred during X509_new call",
634                         entry("FILE=%s", filePath.c_str()),
635                         entry("ERRCODE=%lu", ERR_get_error()));
636         elog<InternalFailure>();
637     }
638 
639     BIOMemPtr bioCert(BIO_new_file(filePath.c_str(), "rb"), ::BIO_free);
640     if (!bioCert)
641     {
642         log<level::ERR>("Error occurred during BIO_new_file call",
643                         entry("FILE=%s", filePath.c_str()));
644         elog<InternalFailure>();
645     }
646 
647     X509* x509 = cert.get();
648     PEM_read_bio_X509(bioCert.get(), &x509, nullptr, nullptr);
649 
650     EVPPkeyPtr pubKey(X509_get_pubkey(cert.get()), ::EVP_PKEY_free);
651     if (!pubKey)
652     {
653         log<level::ERR>("Error occurred during X509_get_pubkey",
654                         entry("FILE=%s", filePath.c_str()),
655                         entry("ERRCODE=%lu", ERR_get_error()));
656         elog<InvalidCertificateError>(
657             InvalidCertificate::REASON("Failed to get public key info"));
658     }
659 
660     BIOMemPtr keyBio(BIO_new(BIO_s_file()), ::BIO_free);
661     if (!keyBio)
662     {
663         log<level::ERR>("Error occurred during BIO_s_file call",
664                         entry("FILE=%s", filePath.c_str()));
665         elog<InternalFailure>();
666     }
667     BIO_read_filename(keyBio.get(), filePath.c_str());
668 
669     EVPPkeyPtr priKey(
670         PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr),
671         ::EVP_PKEY_free);
672     if (!priKey)
673     {
674         log<level::ERR>("Error occurred during PEM_read_bio_PrivateKey",
675                         entry("FILE=%s", filePath.c_str()),
676                         entry("ERRCODE=%lu", ERR_get_error()));
677         elog<InvalidCertificateError>(
678             InvalidCertificate::REASON("Failed to get private key info"));
679     }
680 
681 #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
682     int32_t rc = EVP_PKEY_cmp(priKey.get(), pubKey.get());
683 #else
684     int32_t rc = EVP_PKEY_eq(priKey.get(), pubKey.get());
685 #endif
686     if (rc != 1)
687     {
688         log<level::ERR>("Private key is not matching with Certificate",
689                         entry("FILE=%s", filePath.c_str()),
690                         entry("ERRCODE=%d", rc));
691         return false;
692     }
693     return true;
694 }
695 
696 void Certificate::delete_()
697 {
698     manager.deleteCertificate(this);
699 }
700 
701 std::string Certificate::getObjectPath()
702 {
703     return objectPath;
704 }
705 
706 std::string Certificate::getCertFilePath()
707 {
708     return certFilePath;
709 }
710 
711 void Certificate::setCertFilePath(const std::string& path)
712 {
713     certFilePath = path;
714 }
715 
716 void Certificate::setCertInstallPath(const std::string& path)
717 {
718     certInstallPath = path;
719 }
720 
721 } // namespace phosphor::certs
722