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