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