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