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