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