blob: 0b4b0ed6d9aaf7943b5c2e889a35783ba63c49f8 [file] [log] [blame]
Marri Devender Raocd30c492019-06-12 01:40:17 -05001#include "config.h"
2
Marri Devender Rao6ceec402019-02-01 03:15:19 -06003#include "certificate.hpp"
4
5#include <openssl/bio.h>
6#include <openssl/crypto.h>
7#include <openssl/err.h>
8#include <openssl/evp.h>
9#include <openssl/pem.h>
10#include <openssl/x509v3.h>
11
12#include <fstream>
13#include <phosphor-logging/elog-errors.hpp>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -050014#include <xyz/openbmc_project/Certs/error.hpp>
Marri Devender Rao6ceec402019-02-01 03:15:19 -060015#include <xyz/openbmc_project/Common/error.hpp>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -050016
Marri Devender Rao6ceec402019-02-01 03:15:19 -060017namespace phosphor
18{
19namespace certs
20{
21// RAII support for openSSL functions.
22using BIO_MEM_Ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
23using X509_STORE_CTX_Ptr =
24 std::unique_ptr<X509_STORE_CTX, decltype(&::X509_STORE_CTX_free)>;
25using X509_LOOKUP_Ptr =
26 std::unique_ptr<X509_LOOKUP, decltype(&::X509_LOOKUP_free)>;
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -060027using ASN1_TIME_ptr = std::unique_ptr<ASN1_TIME, decltype(&ASN1_STRING_free)>;
Marri Devender Rao6ceec402019-02-01 03:15:19 -060028using EVP_PKEY_Ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
29using BUF_MEM_Ptr = std::unique_ptr<BUF_MEM, decltype(&::BUF_MEM_free)>;
30using InternalFailure =
31 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
32using InvalidCertificate =
Marri Devender Rao13bf74e2019-03-26 01:52:17 -050033 sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
34using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
Marri Devender Rao6ceec402019-02-01 03:15:19 -060035
36// Trust chain related errors.`
37#define TRUST_CHAIN_ERR(errnum) \
38 ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || \
39 (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) || \
40 (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) || \
41 (errnum == X509_V_ERR_CERT_UNTRUSTED) || \
42 (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
43
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -060044// Refer to schema 2018.3
45// http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for
46// supported KeyUsage types in redfish
47// Refer to
48// https://github.com/openssl/openssl/blob/master/include/openssl/x509v3.h for
49// key usage bit fields
50std::map<uint8_t, std::string> keyUsageToRfStr = {
51 {KU_DIGITAL_SIGNATURE, "DigitalSignature"},
52 {KU_NON_REPUDIATION, "NonRepudiation"},
53 {KU_KEY_ENCIPHERMENT, "KeyEncipherment"},
54 {KU_DATA_ENCIPHERMENT, "DataEncipherment"},
55 {KU_KEY_AGREEMENT, "KeyAgreement"},
56 {KU_KEY_CERT_SIGN, "KeyCertSign"},
57 {KU_CRL_SIGN, "CRLSigning"},
58 {KU_ENCIPHER_ONLY, "EncipherOnly"},
59 {KU_DECIPHER_ONLY, "DecipherOnly"}};
60
61// Refer to schema 2018.3
62// http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for
63// supported Extended KeyUsage types in redfish
64std::map<uint8_t, std::string> extendedKeyUsageToRfStr = {
65 {NID_server_auth, "ServerAuthentication"},
66 {NID_client_auth, "ClientAuthentication"},
67 {NID_email_protect, "EmailProtection"},
68 {NID_OCSP_sign, "OCSPSigning"},
69 {NID_ad_timeStamping, "Timestamping"},
70 {NID_code_sign, "CodeSigning"}};
71
Marri Devender Rao6ceec402019-02-01 03:15:19 -060072Certificate::Certificate(sdbusplus::bus::bus& bus, const std::string& objPath,
73 const CertificateType& type,
74 const UnitsToRestart& unit,
75 const CertInstallPath& installPath,
Marri Devender Rao8f80c352019-05-13 00:53:01 -050076 const CertUploadPath& uploadPath,
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050077 bool isSkipUnitReload,
78 const CertWatchPtr& certWatchPtr) :
Marri Devender Raoedd11312019-02-27 08:45:10 -060079 CertIfaces(bus, objPath.c_str(), true),
80 bus(bus), objectPath(objPath), certType(type), unitToRestart(unit),
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050081 certInstallPath(installPath), certWatchPtr(certWatchPtr)
Marri Devender Rao6ceec402019-02-01 03:15:19 -060082{
83 auto installHelper = [this](const auto& filePath) {
84 if (!compareKeys(filePath))
85 {
86 elog<InvalidCertificate>(
87 Reason("Private key does not match the Certificate"));
88 };
89 };
90 typeFuncMap[SERVER] = installHelper;
91 typeFuncMap[CLIENT] = installHelper;
92 typeFuncMap[AUTHORITY] = [](auto filePath) {};
Marri Devender Raocd30c492019-06-12 01:40:17 -050093
94 auto appendPrivateKey = [this](const std::string& filePath) {
95 checkAndAppendPrivateKey(filePath);
96 };
97
98 appendKeyMap[SERVER] = appendPrivateKey;
99 appendKeyMap[CLIENT] = appendPrivateKey;
100 appendKeyMap[AUTHORITY] = [](const std::string& filePath) {};
101
102 // install the certificate
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500103 install(uploadPath, isSkipUnitReload);
Marri Devender Raocd30c492019-06-12 01:40:17 -0500104
Marri Devender Raoedd11312019-02-27 08:45:10 -0600105 this->emit_object_added();
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600106}
107
108Certificate::~Certificate()
109{
110 if (!fs::remove(certInstallPath))
111 {
112 log<level::INFO>("Certificate file not found!",
113 entry("PATH=%s", certInstallPath.c_str()));
114 }
115 else if (!unitToRestart.empty())
116 {
117 reloadOrReset(unitToRestart);
118 }
119}
120
Marri Devender Rao13bf74e2019-03-26 01:52:17 -0500121void Certificate::replace(const std::string filePath)
122{
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500123 install(filePath, false);
Marri Devender Rao13bf74e2019-03-26 01:52:17 -0500124}
125
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500126void Certificate::install(const std::string& filePath, bool isSkipUnitReload)
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600127{
128 log<level::INFO>("Certificate install ",
129 entry("FILEPATH=%s", filePath.c_str()));
130 auto errCode = X509_V_OK;
131
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500132 // stop watch for user initiated certificate install
133 if (certWatchPtr)
134 {
135 certWatchPtr->stopWatch();
136 }
137
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600138 // Verify the certificate file
139 fs::path file(filePath);
140 if (!fs::exists(file))
141 {
142 log<level::ERR>("File is Missing", entry("FILE=%s", filePath.c_str()));
143 elog<InternalFailure>();
144 }
145
146 try
147 {
148 if (fs::file_size(filePath) == 0)
149 {
150 // file is empty
151 log<level::ERR>("File is empty",
152 entry("FILE=%s", filePath.c_str()));
153 elog<InvalidCertificate>(Reason("File is empty"));
154 }
155 }
156 catch (const fs::filesystem_error& e)
157 {
158 // Log Error message
159 log<level::ERR>(e.what(), entry("FILE=%s", filePath.c_str()));
160 elog<InternalFailure>();
161 }
162
163 // Defining store object as RAW to avoid double free.
164 // X509_LOOKUP_free free up store object.
165 // Create an empty X509_STORE structure for certificate validation.
166 auto x509Store = X509_STORE_new();
167 if (!x509Store)
168 {
169 log<level::ERR>("Error occured during X509_STORE_new call");
170 elog<InternalFailure>();
171 }
172
173 OpenSSL_add_all_algorithms();
174
175 // ADD Certificate Lookup method.
176 X509_LOOKUP_Ptr lookup(X509_STORE_add_lookup(x509Store, X509_LOOKUP_file()),
177 ::X509_LOOKUP_free);
178 if (!lookup)
179 {
180 // Normally lookup cleanup function interanlly does X509Store cleanup
181 // Free up the X509Store.
182 X509_STORE_free(x509Store);
183 log<level::ERR>("Error occured during X509_STORE_add_lookup call");
184 elog<InternalFailure>();
185 }
186 // Load Certificate file.
187 errCode = X509_LOOKUP_load_file(lookup.get(), filePath.c_str(),
188 X509_FILETYPE_PEM);
189 if (errCode != 1)
190 {
191 log<level::ERR>("Error occured during X509_LOOKUP_load_file call",
192 entry("FILE=%s", filePath.c_str()));
193 elog<InvalidCertificate>(Reason("Invalid certificate file format"));
194 }
195
196 // Load Certificate file into the X509 structre.
197 X509_Ptr cert = std::move(loadCert(filePath));
198 X509_STORE_CTX_Ptr storeCtx(X509_STORE_CTX_new(), ::X509_STORE_CTX_free);
199 if (!storeCtx)
200 {
201 log<level::ERR>("Error occured during X509_STORE_CTX_new call",
202 entry("FILE=%s", filePath.c_str()));
203 elog<InternalFailure>();
204 }
205
206 errCode = X509_STORE_CTX_init(storeCtx.get(), x509Store, cert.get(), NULL);
207 if (errCode != 1)
208 {
209 log<level::ERR>("Error occured during X509_STORE_CTX_init call",
210 entry("FILE=%s", filePath.c_str()));
211 elog<InternalFailure>();
212 }
213
214 // Set time to current time.
215 auto locTime = time(nullptr);
216
217 X509_STORE_CTX_set_time(storeCtx.get(), X509_V_FLAG_USE_CHECK_TIME,
218 locTime);
219
220 errCode = X509_verify_cert(storeCtx.get());
221 if (errCode == 1)
222 {
223 errCode = X509_V_OK;
224 }
225 else if (errCode == 0)
226 {
227 errCode = X509_STORE_CTX_get_error(storeCtx.get());
Marri Devender Rao2e8c3a52019-08-09 01:26:35 -0500228 log<level::INFO>(
229 "Error occured during X509_verify_cert call, checking for known "
230 "error",
231 entry("FILE=%s", filePath.c_str()), entry("ERRCODE=%d", errCode),
232 entry("ERROR_STR=%s", X509_verify_cert_error_string(errCode)));
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600233 }
234 else
235 {
236 log<level::ERR>("Error occured during X509_verify_cert call",
237 entry("FILE=%s", filePath.c_str()));
238 elog<InternalFailure>();
239 }
240
241 // Allow certificate upload, for "certificate is not yet valid" and
242 // trust chain related errors.
243 if (!((errCode == X509_V_OK) ||
244 (errCode == X509_V_ERR_CERT_NOT_YET_VALID) ||
245 TRUST_CHAIN_ERR(errCode)))
246 {
247 if (errCode == X509_V_ERR_CERT_HAS_EXPIRED)
248 {
249 elog<InvalidCertificate>(Reason("Expired Certificate"));
250 }
251 // Loging general error here.
252 elog<InvalidCertificate>(Reason("Certificate validation failed"));
253 }
254
Marri Devender Raocd30c492019-06-12 01:40:17 -0500255 // Invoke type specific append private key function.
256 auto appendIter = appendKeyMap.find(certType);
257 if (appendIter == appendKeyMap.end())
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600258 {
259 log<level::ERR>("Unsupported Type", entry("TYPE=%s", certType.c_str()));
260 elog<InternalFailure>();
261 }
Marri Devender Raocd30c492019-06-12 01:40:17 -0500262 appendIter->second(filePath);
263
264 // Invoke type specific compare keys function.
265 auto compIter = typeFuncMap.find(certType);
266 if (compIter == typeFuncMap.end())
267 {
268 log<level::ERR>("Unsupported Type", entry("TYPE=%s", certType.c_str()));
269 elog<InternalFailure>();
270 }
271 compIter->second(filePath);
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600272
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500273 // Copy the certificate to the installation path
274 // During bootup will be parsing existing file so no need to
275 // copy it.
276 if (filePath != certInstallPath)
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600277 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500278 std::ifstream inputCertFileStream;
279 std::ofstream outputCertFileStream;
280 inputCertFileStream.exceptions(std::ifstream::failbit |
281 std::ifstream::badbit |
282 std::ifstream::eofbit);
283 outputCertFileStream.exceptions(std::ofstream::failbit |
284 std::ofstream::badbit |
285 std::ofstream::eofbit);
286 try
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600287 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500288 inputCertFileStream.open(filePath);
289 outputCertFileStream.open(certInstallPath, std::ios::out);
290 outputCertFileStream << inputCertFileStream.rdbuf() << std::flush;
291 inputCertFileStream.close();
292 outputCertFileStream.close();
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600293 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500294 catch (const std::exception& e)
295 {
296 log<level::ERR>("Failed to copy certificate",
297 entry("ERR=%s", e.what()),
298 entry("SRC=%s", filePath.c_str()),
299 entry("DST=%s", certInstallPath.c_str()));
300 elog<InternalFailure>();
301 }
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600302 }
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500303
304 if (!isSkipUnitReload)
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600305 {
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500306 // restart the units
307 if (!unitToRestart.empty())
308 {
309 reloadOrReset(unitToRestart);
310 }
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600311 }
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -0600312
313 // Parse the certificate file and populate properties
314 populateProperties();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500315
316 // restart watch
317 if (certWatchPtr)
318 {
319 certWatchPtr->startWatch();
320 }
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -0600321}
322
323void Certificate::populateProperties()
324{
325 X509_Ptr cert = std::move(loadCert(certInstallPath));
326 // Update properties if no error thrown
327 BIO_MEM_Ptr certBio(BIO_new(BIO_s_mem()), BIO_free);
328 PEM_write_bio_X509(certBio.get(), cert.get());
329 BUF_MEM_Ptr certBuf(BUF_MEM_new(), BUF_MEM_free);
330 BUF_MEM* buf = certBuf.get();
331 BIO_get_mem_ptr(certBio.get(), &buf);
332 std::string certStr(buf->data, buf->length);
333 CertificateIface::certificateString(certStr);
334
335 static const int maxKeySize = 4096;
336 char subBuffer[maxKeySize] = {0};
Marri Devender Raodec58772019-06-11 03:10:00 -0500337 BIO_MEM_Ptr subBio(BIO_new(BIO_s_mem()), BIO_free);
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -0600338 // This pointer cannot be freed independantly.
339 X509_NAME* sub = X509_get_subject_name(cert.get());
Marri Devender Raodec58772019-06-11 03:10:00 -0500340 X509_NAME_print_ex(subBio.get(), sub, 0, XN_FLAG_SEP_COMMA_PLUS);
341 BIO_read(subBio.get(), subBuffer, maxKeySize);
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -0600342 CertificateIface::subject(subBuffer);
343
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -0600344 char issuerBuffer[maxKeySize] = {0};
Marri Devender Raodec58772019-06-11 03:10:00 -0500345 BIO_MEM_Ptr issuerBio(BIO_new(BIO_s_mem()), BIO_free);
346 // This pointer cannot be freed independantly.
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -0600347 X509_NAME* issuer_name = X509_get_issuer_name(cert.get());
Marri Devender Raodec58772019-06-11 03:10:00 -0500348 X509_NAME_print_ex(issuerBio.get(), issuer_name, 0, XN_FLAG_SEP_COMMA_PLUS);
349 BIO_read(issuerBio.get(), issuerBuffer, maxKeySize);
Dhruvaraj Subhashchandran36f25142019-02-14 05:06:26 -0600350 CertificateIface::issuer(issuerBuffer);
351
352 std::vector<std::string> keyUsageList;
353 ASN1_BIT_STRING* usage;
354
355 // Go through each usage in the bit string and convert to
356 // corresponding string value
357 if ((usage = static_cast<ASN1_BIT_STRING*>(
358 X509_get_ext_d2i(cert.get(), NID_key_usage, NULL, NULL))))
359 {
360 for (auto i = 0; i < usage->length; ++i)
361 {
362 for (auto& x : keyUsageToRfStr)
363 {
364 if (x.first & usage->data[i])
365 {
366 keyUsageList.push_back(x.second);
367 break;
368 }
369 }
370 }
371 }
372
373 EXTENDED_KEY_USAGE* extUsage;
374 if ((extUsage = static_cast<EXTENDED_KEY_USAGE*>(
375 X509_get_ext_d2i(cert.get(), NID_ext_key_usage, NULL, NULL))))
376 {
377 for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++)
378 {
379 keyUsageList.push_back(extendedKeyUsageToRfStr[OBJ_obj2nid(
380 sk_ASN1_OBJECT_value(extUsage, i))]);
381 }
382 }
383 CertificateIface::keyUsage(keyUsageList);
384
385 int days = 0;
386 int secs = 0;
387
388 ASN1_TIME_ptr epoch(ASN1_TIME_new(), ASN1_STRING_free);
389 // Set time to 12:00am GMT, Jan 1 1970
390 ASN1_TIME_set_string(epoch.get(), "700101120000Z");
391
392 static const int dayToSeconds = 24 * 60 * 60;
393 ASN1_TIME* notAfter = X509_get_notAfter(cert.get());
394 ASN1_TIME_diff(&days, &secs, epoch.get(), notAfter);
395 CertificateIface::validNotAfter((days * dayToSeconds) + secs);
396
397 ASN1_TIME* notBefore = X509_get_notBefore(cert.get());
398 ASN1_TIME_diff(&days, &secs, epoch.get(), notBefore);
399 CertificateIface::validNotBefore((days * dayToSeconds) + secs);
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600400}
401
402X509_Ptr Certificate::loadCert(const std::string& filePath)
403{
404 log<level::INFO>("Certificate loadCert",
405 entry("FILEPATH=%s", filePath.c_str()));
406 // Read Certificate file
407 X509_Ptr cert(X509_new(), ::X509_free);
408 if (!cert)
409 {
410 log<level::ERR>("Error occured during X509_new call",
411 entry("FILE=%s", filePath.c_str()),
412 entry("ERRCODE=%lu", ERR_get_error()));
413 elog<InternalFailure>();
414 }
415
416 BIO_MEM_Ptr bioCert(BIO_new_file(filePath.c_str(), "rb"), ::BIO_free);
417 if (!bioCert)
418 {
419 log<level::ERR>("Error occured during BIO_new_file call",
420 entry("FILE=%s", filePath.c_str()));
421 elog<InternalFailure>();
422 }
423
424 X509* x509 = cert.get();
425 if (!PEM_read_bio_X509(bioCert.get(), &x509, nullptr, nullptr))
426 {
427 log<level::ERR>("Error occured during PEM_read_bio_X509 call",
428 entry("FILE=%s", filePath.c_str()));
429 elog<InternalFailure>();
430 }
431 return cert;
432}
Marri Devender Raocd30c492019-06-12 01:40:17 -0500433
434void Certificate::checkAndAppendPrivateKey(const std::string& filePath)
435{
436 BIO_MEM_Ptr keyBio(BIO_new(BIO_s_file()), ::BIO_free);
437 if (!keyBio)
438 {
439 log<level::ERR>("Error occured during BIO_s_file call",
440 entry("FILE=%s", filePath.c_str()));
441 elog<InternalFailure>();
442 }
443 BIO_read_filename(keyBio.get(), filePath.c_str());
444
445 EVP_PKEY_Ptr priKey(
446 PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr),
447 ::EVP_PKEY_free);
448 if (!priKey)
449 {
450 log<level::INFO>("Private key not present in file",
451 entry("FILE=%s", filePath.c_str()));
452 fs::path privateKeyFile = fs::path(certInstallPath).parent_path();
453 privateKeyFile = privateKeyFile / PRIV_KEY_FILE_NAME;
454 if (!fs::exists(privateKeyFile))
455 {
456 log<level::ERR>("Private key file is not found",
457 entry("FILE=%s", privateKeyFile.c_str()));
458 elog<InternalFailure>();
459 }
460
461 std::ifstream privKeyFileStream;
462 std::ofstream certFileStream;
463 privKeyFileStream.exceptions(std::ifstream::failbit |
464 std::ifstream::badbit |
465 std::ifstream::eofbit);
466 certFileStream.exceptions(std::ofstream::failbit |
467 std::ofstream::badbit |
468 std::ofstream::eofbit);
469 try
470 {
471 privKeyFileStream.open(privateKeyFile);
472 certFileStream.open(filePath, std::ios::app);
Marri Devender Rao18e51c92019-07-15 04:59:01 -0500473 certFileStream << std::endl; // insert line break
Marri Devender Raocd30c492019-06-12 01:40:17 -0500474 certFileStream << privKeyFileStream.rdbuf() << std::flush;
475 privKeyFileStream.close();
476 certFileStream.close();
477 }
478 catch (const std::exception& e)
479 {
480 log<level::ERR>("Failed to append private key",
481 entry("ERR=%s", e.what()),
482 entry("SRC=%s", privateKeyFile.c_str()),
483 entry("DST=%s", filePath.c_str()));
484 elog<InternalFailure>();
485 }
486 }
487}
488
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600489bool Certificate::compareKeys(const std::string& filePath)
490{
491 log<level::INFO>("Certificate compareKeys",
492 entry("FILEPATH=%s", filePath.c_str()));
493 X509_Ptr cert(X509_new(), ::X509_free);
494 if (!cert)
495 {
496 log<level::ERR>("Error occured during X509_new call",
497 entry("FILE=%s", filePath.c_str()),
498 entry("ERRCODE=%lu", ERR_get_error()));
499 elog<InternalFailure>();
500 }
501
502 BIO_MEM_Ptr bioCert(BIO_new_file(filePath.c_str(), "rb"), ::BIO_free);
503 if (!bioCert)
504 {
505 log<level::ERR>("Error occured during BIO_new_file call",
506 entry("FILE=%s", filePath.c_str()));
507 elog<InternalFailure>();
508 }
509
510 X509* x509 = cert.get();
511 PEM_read_bio_X509(bioCert.get(), &x509, nullptr, nullptr);
512
513 EVP_PKEY_Ptr pubKey(X509_get_pubkey(cert.get()), ::EVP_PKEY_free);
514 if (!pubKey)
515 {
516 log<level::ERR>("Error occurred during X509_get_pubkey",
517 entry("FILE=%s", filePath.c_str()),
518 entry("ERRCODE=%lu", ERR_get_error()));
519 elog<InvalidCertificate>(Reason("Failed to get public key info"));
520 }
521
522 BIO_MEM_Ptr keyBio(BIO_new(BIO_s_file()), ::BIO_free);
523 if (!keyBio)
524 {
525 log<level::ERR>("Error occured during BIO_s_file call",
526 entry("FILE=%s", filePath.c_str()));
527 elog<InternalFailure>();
528 }
529 BIO_read_filename(keyBio.get(), filePath.c_str());
530
531 EVP_PKEY_Ptr priKey(
532 PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr),
533 ::EVP_PKEY_free);
534 if (!priKey)
535 {
536 log<level::ERR>("Error occurred during PEM_read_bio_PrivateKey",
537 entry("FILE=%s", filePath.c_str()),
538 entry("ERRCODE=%lu", ERR_get_error()));
539 elog<InvalidCertificate>(Reason("Failed to get private key info"));
540 }
541
542 int32_t rc = EVP_PKEY_cmp(priKey.get(), pubKey.get());
543 if (rc != 1)
544 {
545 log<level::ERR>("Private key is not matching with Certificate",
546 entry("FILE=%s", filePath.c_str()),
547 entry("ERRCODE=%d", rc));
548 return false;
549 }
550 return true;
551}
552
553void Certificate::reloadOrReset(const UnitsToRestart& unit)
554{
555 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
556 constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
557 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
558 try
559 {
560 auto method =
561 bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
562 SYSTEMD_INTERFACE, "ReloadOrRestartUnit");
563 method.append(unit, "replace");
564 bus.call_noreply(method);
565 }
566 catch (const sdbusplus::exception::SdBusError& e)
567 {
568 log<level::ERR>("Failed to reload or restart service",
569 entry("ERR=%s", e.what()),
570 entry("UNIT=%s", unit.c_str()));
571 elog<InternalFailure>();
572 }
573}
574} // namespace certs
575} // namespace phosphor