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